get rid of TICKER_INTERVAL_MINUTES dict, use ccxt's parse_timeframe() instead
This commit is contained in:
		| @@ -6,7 +6,7 @@ bot constants | ||||
| DEFAULT_CONFIG = 'config.json' | ||||
| DYNAMIC_WHITELIST = 20  # pairs | ||||
| PROCESS_THROTTLE_SECS = 5  # sec | ||||
| TICKER_INTERVAL = 5  # min | ||||
| DEFAULT_TICKER_INTERVAL = 5  # min | ||||
| HYPEROPT_EPOCH = 100  # epochs | ||||
| RETRY_TIMEOUT = 30  # sec | ||||
| DEFAULT_STRATEGY = 'DefaultStrategy' | ||||
| @@ -22,22 +22,11 @@ ORDERTIF_POSSIBILITIES = ['gtc', 'fok', 'ioc'] | ||||
| AVAILABLE_PAIRLISTS = ['StaticPairList', 'VolumePairList'] | ||||
| DRY_RUN_WALLET = 999.9 | ||||
|  | ||||
| TICKER_INTERVAL_MINUTES = { | ||||
|     '1m': 1, | ||||
|     '3m': 3, | ||||
|     '5m': 5, | ||||
|     '15m': 15, | ||||
|     '30m': 30, | ||||
|     '1h': 60, | ||||
|     '2h': 120, | ||||
|     '4h': 240, | ||||
|     '6h': 360, | ||||
|     '8h': 480, | ||||
|     '12h': 720, | ||||
|     '1d': 1440, | ||||
|     '3d': 4320, | ||||
|     '1w': 10080, | ||||
| } | ||||
| TICKER_INTERVALS = [ | ||||
|     '1m', '3m', '5m', '15m', '30m', | ||||
|     '1h', '2h', '4h', '6h', '8h', '12h', | ||||
|     '1d', '3d', '1w', | ||||
| ] | ||||
|  | ||||
| SUPPORTED_FIAT = [ | ||||
|     "AUD", "BRL", "CAD", "CHF", "CLP", "CNY", "CZK", "DKK", | ||||
| @@ -52,7 +41,7 @@ CONF_SCHEMA = { | ||||
|     'type': 'object', | ||||
|     'properties': { | ||||
|         'max_open_trades': {'type': 'integer', 'minimum': -1}, | ||||
|         'ticker_interval': {'type': 'string', 'enum': list(TICKER_INTERVAL_MINUTES.keys())}, | ||||
|         'ticker_interval': {'type': 'string', 'enum': TICKER_INTERVALS}, | ||||
|         'stake_currency': {'type': 'string', 'enum': ['BTC', 'XBT', 'ETH', 'USDT', 'EUR', 'USD']}, | ||||
|         'stake_amount': { | ||||
|             "type": ["number", "string"], | ||||
|   | ||||
| @@ -4,8 +4,8 @@ Functions to convert data from one format to another | ||||
| import logging | ||||
| import pandas as pd | ||||
| from pandas import DataFrame, to_datetime | ||||
| from freqtrade.misc import timeframe_to_minutes | ||||
|  | ||||
| from freqtrade.constants import TICKER_INTERVAL_MINUTES | ||||
|  | ||||
| logger = logging.getLogger(__name__) | ||||
|  | ||||
| @@ -65,9 +65,9 @@ def ohlcv_fill_up_missing_data(dataframe: DataFrame, ticker_interval: str) -> Da | ||||
|         'close': 'last', | ||||
|         'volume': 'sum' | ||||
|     } | ||||
|     tick_mins = TICKER_INTERVAL_MINUTES[ticker_interval] | ||||
|     ticker_minutes = timeframe_to_minutes(ticker_interval) | ||||
|     # Resample to create "NAN" values | ||||
|     df = dataframe.resample(f'{tick_mins}min', on='date').agg(ohlc_dict) | ||||
|     df = dataframe.resample(f'{ticker_minutes}min', on='date').agg(ohlc_dict) | ||||
|  | ||||
|     # Forwardfill close for missing columns | ||||
|     df['close'] = df['close'].fillna(method='ffill') | ||||
|   | ||||
| @@ -12,10 +12,12 @@ from typing import Optional, List, Dict, Tuple, Any | ||||
| import arrow | ||||
| from pandas import DataFrame | ||||
|  | ||||
| from freqtrade import misc, constants, OperationalException | ||||
| from freqtrade import misc, OperationalException | ||||
| from freqtrade.arguments import TimeRange | ||||
| from freqtrade.data.converter import parse_ticker_dataframe | ||||
| from freqtrade.exchange import Exchange | ||||
| from freqtrade.arguments import TimeRange | ||||
| from freqtrade.misc import timeframe_to_minutes | ||||
|  | ||||
|  | ||||
| logger = logging.getLogger(__name__) | ||||
|  | ||||
| @@ -163,7 +165,7 @@ def load_cached_data_for_updating(filename: Path, tick_interval: str, | ||||
|         if timerange.starttype == 'date': | ||||
|             since_ms = timerange.startts * 1000 | ||||
|         elif timerange.stoptype == 'line': | ||||
|             num_minutes = timerange.stopts * constants.TICKER_INTERVAL_MINUTES[tick_interval] | ||||
|             num_minutes = timerange.stopts * timeframe_to_minutes(tick_interval) | ||||
|             since_ms = arrow.utcnow().shift(minutes=num_minutes).timestamp * 1000 | ||||
|  | ||||
|     # read the cached file | ||||
|   | ||||
| @@ -15,9 +15,12 @@ from pandas import DataFrame | ||||
|  | ||||
| from freqtrade import constants, DependencyException, OperationalException, TemporaryError | ||||
| from freqtrade.data.converter import parse_ticker_dataframe | ||||
| from freqtrade.misc import timeframe_to_seconds, timeframe_to_msecs | ||||
|  | ||||
|  | ||||
| logger = logging.getLogger(__name__) | ||||
|  | ||||
|  | ||||
| API_RETRY_COUNT = 4 | ||||
|  | ||||
|  | ||||
| @@ -502,8 +505,8 @@ class Exchange(object): | ||||
|         # Assume exchange returns 500 candles | ||||
|         _LIMIT = 500 | ||||
|  | ||||
|         one_call = constants.TICKER_INTERVAL_MINUTES[tick_interval] * 60 * _LIMIT * 1000 | ||||
|         logger.debug("one_call: %s", one_call) | ||||
|         one_call = timeframe_to_msecs(tick_interval) * _LIMIT | ||||
|         logger.debug("one_call: %s msecs", one_call) | ||||
|         input_coroutines = [self._async_get_candle_history( | ||||
|             pair, tick_interval, since) for since in | ||||
|             range(since_ms, arrow.utcnow().timestamp * 1000, one_call)] | ||||
| @@ -557,7 +560,7 @@ class Exchange(object): | ||||
|  | ||||
|     def _now_is_time_to_refresh(self, pair: str, ticker_interval: str) -> bool: | ||||
|         # Calculating ticker interval in seconds | ||||
|         interval_in_sec = constants.TICKER_INTERVAL_MINUTES[ticker_interval] * 60 | ||||
|         interval_in_sec = timeframe_to_seconds(ticker_interval) | ||||
|  | ||||
|         return not ((self._pairs_last_refresh_time.get((pair, ticker_interval), 0) | ||||
|                      + interval_in_sec) >= arrow.utcnow().timestamp) | ||||
|   | ||||
| @@ -16,6 +16,7 @@ from freqtrade import (DependencyException, OperationalException, | ||||
| from freqtrade.data.converter import order_book_to_dataframe | ||||
| from freqtrade.data.dataprovider import DataProvider | ||||
| from freqtrade.edge import Edge | ||||
| from freqtrade.misc import timeframe_to_minutes | ||||
| from freqtrade.persistence import Trade | ||||
| from freqtrade.rpc import RPCManager, RPCMessageType | ||||
| from freqtrade.resolvers import ExchangeResolver, StrategyResolver, PairListResolver | ||||
| @@ -397,7 +398,7 @@ class FreqtradeBot(object): | ||||
|             exchange=self.exchange.id, | ||||
|             open_order_id=order_id, | ||||
|             strategy=self.strategy.get_strategy_name(), | ||||
|             ticker_interval=constants.TICKER_INTERVAL_MINUTES[self.config['ticker_interval']] | ||||
|             ticker_interval=timeframe_to_minutes(self.config['ticker_interval']) | ||||
|         ) | ||||
|  | ||||
|         # Update fees if order is closed | ||||
|   | ||||
| @@ -8,6 +8,7 @@ import re | ||||
| from datetime import datetime | ||||
| from typing import Dict | ||||
|  | ||||
| from ccxt import Exchange | ||||
| import numpy as np | ||||
| from pandas import DataFrame | ||||
| import rapidjson | ||||
| @@ -131,3 +132,15 @@ def deep_merge_dicts(source, destination): | ||||
|             destination[key] = value | ||||
|  | ||||
|     return destination | ||||
|  | ||||
|  | ||||
| def timeframe_to_seconds(ticker_interval: str) -> int: | ||||
|     return Exchange.parse_timeframe(ticker_interval) | ||||
|  | ||||
|  | ||||
| def timeframe_to_minutes(ticker_interval: str) -> int: | ||||
|     return Exchange.parse_timeframe(ticker_interval) // 60 | ||||
|  | ||||
|  | ||||
| def timeframe_to_msecs(ticker_interval: str) -> int: | ||||
|     return Exchange.parse_timeframe(ticker_interval) * 1000 | ||||
|   | ||||
| @@ -19,7 +19,7 @@ from freqtrade.arguments import Arguments | ||||
| from freqtrade.configuration import Configuration | ||||
| from freqtrade.data import history | ||||
| from freqtrade.data.dataprovider import DataProvider | ||||
| from freqtrade.misc import file_dump_json | ||||
| from freqtrade.misc import file_dump_json, timeframe_to_minutes | ||||
| from freqtrade.persistence import Trade | ||||
| from freqtrade.resolvers import ExchangeResolver, StrategyResolver | ||||
| from freqtrade.state import RunMode | ||||
| @@ -77,7 +77,7 @@ class Backtesting(object): | ||||
|         if self.config.get('strategy_list', None): | ||||
|             # Force one interval | ||||
|             self.ticker_interval = str(self.config.get('ticker_interval')) | ||||
|             self.ticker_interval_mins = constants.TICKER_INTERVAL_MINUTES[self.ticker_interval] | ||||
|             self.ticker_interval_mins = timeframe_to_minutes(self.ticker_interval) | ||||
|             for strat in list(self.config['strategy_list']): | ||||
|                 stratconf = deepcopy(self.config) | ||||
|                 stratconf['strategy'] = strat | ||||
| @@ -96,7 +96,7 @@ class Backtesting(object): | ||||
|         self.strategy = strategy | ||||
|  | ||||
|         self.ticker_interval = self.config.get('ticker_interval') | ||||
|         self.ticker_interval_mins = constants.TICKER_INTERVAL_MINUTES[self.ticker_interval] | ||||
|         self.ticker_interval_mins = timeframe_to_minutes(self.ticker_interval) | ||||
|         self.tickerdata_to_dataframe = strategy.tickerdata_to_dataframe | ||||
|         self.advise_buy = strategy.advise_buy | ||||
|         self.advise_sell = strategy.advise_sell | ||||
| @@ -421,7 +421,7 @@ class Backtesting(object): | ||||
|             min_date, max_date = optimize.get_timeframe(data) | ||||
|             # Validate dataframe for missing values (mainly at start and end, as fillup is called) | ||||
|             optimize.validate_backtest_data(data, min_date, max_date, | ||||
|                                             constants.TICKER_INTERVAL_MINUTES[self.ticker_interval]) | ||||
|                                             timeframe_to_minutes(self.ticker_interval)) | ||||
|             logger.info( | ||||
|                 'Measuring data from %s up to %s (%s days)..', | ||||
|                 min_date.isoformat(), | ||||
|   | ||||
| @@ -12,8 +12,8 @@ import warnings | ||||
| import arrow | ||||
| from pandas import DataFrame | ||||
|  | ||||
| from freqtrade import constants | ||||
| from freqtrade.data.dataprovider import DataProvider | ||||
| from freqtrade.misc import timeframe_to_minutes | ||||
| from freqtrade.persistence import Trade | ||||
| from freqtrade.wallets import Wallets | ||||
|  | ||||
| @@ -221,7 +221,7 @@ class IStrategy(ABC): | ||||
|  | ||||
|         # Check if dataframe is out of date | ||||
|         signal_date = arrow.get(latest['date']) | ||||
|         interval_minutes = constants.TICKER_INTERVAL_MINUTES[interval] | ||||
|         interval_minutes = timeframe_to_minutes(interval) | ||||
|         offset = self.config.get('exchange', {}).get('outdated_offset', 5) | ||||
|         if signal_date < (arrow.utcnow().shift(minutes=-(interval_minutes * 2 + offset))): | ||||
|             logger.warning( | ||||
|   | ||||
| @@ -3,11 +3,11 @@ from typing import NamedTuple, List | ||||
| import arrow | ||||
| from pandas import DataFrame | ||||
|  | ||||
| from freqtrade.misc import timeframe_to_minutes | ||||
| from freqtrade.strategy.interface import SellType | ||||
| from freqtrade.constants import TICKER_INTERVAL_MINUTES | ||||
|  | ||||
| ticker_start_time = arrow.get(2018, 10, 3) | ||||
| tests_ticker_interval = "1h" | ||||
| tests_ticker_interval = '1h' | ||||
|  | ||||
|  | ||||
| class BTrade(NamedTuple): | ||||
| @@ -32,7 +32,7 @@ class BTContainer(NamedTuple): | ||||
|  | ||||
|  | ||||
| def _get_frame_time_from_offset(offset): | ||||
|     return ticker_start_time.shift(minutes=(offset * TICKER_INTERVAL_MINUTES[tests_ticker_interval]) | ||||
|     return ticker_start_time.shift(minutes=(offset * timeframe_to_minutes(tests_ticker_interval)) | ||||
|                                    ).datetime.replace(tzinfo=None) | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,8 @@ | ||||
| # pragma pylint: disable=missing-docstring, protected-access, C0103 | ||||
| from freqtrade import optimize, constants | ||||
| from freqtrade import optimize | ||||
| from freqtrade.arguments import TimeRange | ||||
| from freqtrade.data import history | ||||
| from freqtrade.misc import timeframe_to_minutes | ||||
| from freqtrade.strategy.default_strategy import DefaultStrategy | ||||
| from freqtrade.tests.conftest import log_has, patch_exchange | ||||
|  | ||||
| @@ -37,7 +38,7 @@ def test_validate_backtest_data_warn(default_conf, mocker, caplog) -> None: | ||||
|     min_date, max_date = optimize.get_timeframe(data) | ||||
|     caplog.clear() | ||||
|     assert optimize.validate_backtest_data(data, min_date, max_date, | ||||
|                                            constants.TICKER_INTERVAL_MINUTES["1m"]) | ||||
|                                            timeframe_to_minutes('1m')) | ||||
|     assert len(caplog.record_tuples) == 1 | ||||
|     assert log_has( | ||||
|         "UNITTEST/BTC has missing frames: expected 14396, got 13680, that's 716 missing values", | ||||
| @@ -61,5 +62,5 @@ def test_validate_backtest_data(default_conf, mocker, caplog) -> None: | ||||
|     min_date, max_date = optimize.get_timeframe(data) | ||||
|     caplog.clear() | ||||
|     assert not optimize.validate_backtest_data(data, min_date, max_date, | ||||
|                                                constants.TICKER_INTERVAL_MINUTES["5m"]) | ||||
|                                                timeframe_to_minutes('5m')) | ||||
|     assert len(caplog.record_tuples) == 0 | ||||
|   | ||||
| @@ -28,6 +28,7 @@ from freqtrade import constants, misc | ||||
| from freqtrade.arguments import Arguments | ||||
| from freqtrade.configuration import Configuration | ||||
| from freqtrade.data import history | ||||
| from freqtrade.misc import timeframe_to_seconds | ||||
| from freqtrade.resolvers import StrategyResolver | ||||
| from freqtrade.state import RunMode | ||||
|  | ||||
| @@ -193,8 +194,8 @@ def define_index(min_date: int, max_date: int, interval: str) -> int: | ||||
|     """ | ||||
|     Return the index of a specific date | ||||
|     """ | ||||
|     interval_minutes = constants.TICKER_INTERVAL_MINUTES[interval] | ||||
|     return int((max_date - min_date) / (interval_minutes * 60)) | ||||
|     interval_seconds = timeframe_to_seconds(interval) | ||||
|     return int((max_date - min_date) / interval_seconds) | ||||
|  | ||||
|  | ||||
| def plot_parse_args(args: List[str]) -> Namespace: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user