get rid of TICKER_INTERVAL_MINUTES dict, use ccxt's parse_timeframe() instead

This commit is contained in:
hroff-1902 2019-04-04 20:56:40 +03:00
parent 75c522e082
commit 2aa1b43f01
11 changed files with 52 additions and 42 deletions

View File

@ -6,7 +6,7 @@ bot constants
DEFAULT_CONFIG = 'config.json' DEFAULT_CONFIG = 'config.json'
DYNAMIC_WHITELIST = 20 # pairs DYNAMIC_WHITELIST = 20 # pairs
PROCESS_THROTTLE_SECS = 5 # sec PROCESS_THROTTLE_SECS = 5 # sec
TICKER_INTERVAL = 5 # min DEFAULT_TICKER_INTERVAL = 5 # min
HYPEROPT_EPOCH = 100 # epochs HYPEROPT_EPOCH = 100 # epochs
RETRY_TIMEOUT = 30 # sec RETRY_TIMEOUT = 30 # sec
DEFAULT_STRATEGY = 'DefaultStrategy' DEFAULT_STRATEGY = 'DefaultStrategy'
@ -22,22 +22,11 @@ ORDERTIF_POSSIBILITIES = ['gtc', 'fok', 'ioc']
AVAILABLE_PAIRLISTS = ['StaticPairList', 'VolumePairList'] AVAILABLE_PAIRLISTS = ['StaticPairList', 'VolumePairList']
DRY_RUN_WALLET = 999.9 DRY_RUN_WALLET = 999.9
TICKER_INTERVAL_MINUTES = { TICKER_INTERVALS = [
'1m': 1, '1m', '3m', '5m', '15m', '30m',
'3m': 3, '1h', '2h', '4h', '6h', '8h', '12h',
'5m': 5, '1d', '3d', '1w',
'15m': 15, ]
'30m': 30,
'1h': 60,
'2h': 120,
'4h': 240,
'6h': 360,
'8h': 480,
'12h': 720,
'1d': 1440,
'3d': 4320,
'1w': 10080,
}
SUPPORTED_FIAT = [ SUPPORTED_FIAT = [
"AUD", "BRL", "CAD", "CHF", "CLP", "CNY", "CZK", "DKK", "AUD", "BRL", "CAD", "CHF", "CLP", "CNY", "CZK", "DKK",
@ -52,7 +41,7 @@ CONF_SCHEMA = {
'type': 'object', 'type': 'object',
'properties': { 'properties': {
'max_open_trades': {'type': 'integer', 'minimum': -1}, '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_currency': {'type': 'string', 'enum': ['BTC', 'XBT', 'ETH', 'USDT', 'EUR', 'USD']},
'stake_amount': { 'stake_amount': {
"type": ["number", "string"], "type": ["number", "string"],

View File

@ -4,8 +4,8 @@ Functions to convert data from one format to another
import logging import logging
import pandas as pd import pandas as pd
from pandas import DataFrame, to_datetime from pandas import DataFrame, to_datetime
from freqtrade.misc import timeframe_to_minutes
from freqtrade.constants import TICKER_INTERVAL_MINUTES
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -65,9 +65,9 @@ def ohlcv_fill_up_missing_data(dataframe: DataFrame, ticker_interval: str) -> Da
'close': 'last', 'close': 'last',
'volume': 'sum' 'volume': 'sum'
} }
tick_mins = TICKER_INTERVAL_MINUTES[ticker_interval] ticker_minutes = timeframe_to_minutes(ticker_interval)
# Resample to create "NAN" values # 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 # Forwardfill close for missing columns
df['close'] = df['close'].fillna(method='ffill') df['close'] = df['close'].fillna(method='ffill')

View File

@ -12,10 +12,12 @@ from typing import Optional, List, Dict, Tuple, Any
import arrow import arrow
from pandas import DataFrame 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.data.converter import parse_ticker_dataframe
from freqtrade.exchange import Exchange from freqtrade.exchange import Exchange
from freqtrade.arguments import TimeRange from freqtrade.misc import timeframe_to_minutes
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -163,7 +165,7 @@ def load_cached_data_for_updating(filename: Path, tick_interval: str,
if timerange.starttype == 'date': if timerange.starttype == 'date':
since_ms = timerange.startts * 1000 since_ms = timerange.startts * 1000
elif timerange.stoptype == 'line': 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 since_ms = arrow.utcnow().shift(minutes=num_minutes).timestamp * 1000
# read the cached file # read the cached file

View File

@ -15,9 +15,12 @@ from pandas import DataFrame
from freqtrade import constants, DependencyException, OperationalException, TemporaryError from freqtrade import constants, DependencyException, OperationalException, TemporaryError
from freqtrade.data.converter import parse_ticker_dataframe from freqtrade.data.converter import parse_ticker_dataframe
from freqtrade.misc import timeframe_to_seconds, timeframe_to_msecs
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
API_RETRY_COUNT = 4 API_RETRY_COUNT = 4
@ -502,8 +505,8 @@ class Exchange(object):
# Assume exchange returns 500 candles # Assume exchange returns 500 candles
_LIMIT = 500 _LIMIT = 500
one_call = constants.TICKER_INTERVAL_MINUTES[tick_interval] * 60 * _LIMIT * 1000 one_call = timeframe_to_msecs(tick_interval) * _LIMIT
logger.debug("one_call: %s", one_call) logger.debug("one_call: %s msecs", one_call)
input_coroutines = [self._async_get_candle_history( input_coroutines = [self._async_get_candle_history(
pair, tick_interval, since) for since in pair, tick_interval, since) for since in
range(since_ms, arrow.utcnow().timestamp * 1000, one_call)] 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: def _now_is_time_to_refresh(self, pair: str, ticker_interval: str) -> bool:
# Calculating ticker interval in seconds # 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) return not ((self._pairs_last_refresh_time.get((pair, ticker_interval), 0)
+ interval_in_sec) >= arrow.utcnow().timestamp) + interval_in_sec) >= arrow.utcnow().timestamp)

View File

@ -16,6 +16,7 @@ from freqtrade import (DependencyException, OperationalException,
from freqtrade.data.converter import order_book_to_dataframe from freqtrade.data.converter import order_book_to_dataframe
from freqtrade.data.dataprovider import DataProvider from freqtrade.data.dataprovider import DataProvider
from freqtrade.edge import Edge from freqtrade.edge import Edge
from freqtrade.misc import timeframe_to_minutes
from freqtrade.persistence import Trade from freqtrade.persistence import Trade
from freqtrade.rpc import RPCManager, RPCMessageType from freqtrade.rpc import RPCManager, RPCMessageType
from freqtrade.resolvers import ExchangeResolver, StrategyResolver, PairListResolver from freqtrade.resolvers import ExchangeResolver, StrategyResolver, PairListResolver
@ -397,7 +398,7 @@ class FreqtradeBot(object):
exchange=self.exchange.id, exchange=self.exchange.id,
open_order_id=order_id, open_order_id=order_id,
strategy=self.strategy.get_strategy_name(), 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 # Update fees if order is closed

View File

@ -8,6 +8,7 @@ import re
from datetime import datetime from datetime import datetime
from typing import Dict from typing import Dict
from ccxt import Exchange
import numpy as np import numpy as np
from pandas import DataFrame from pandas import DataFrame
import rapidjson import rapidjson
@ -131,3 +132,15 @@ def deep_merge_dicts(source, destination):
destination[key] = value destination[key] = value
return destination 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

View File

@ -19,7 +19,7 @@ from freqtrade.arguments import Arguments
from freqtrade.configuration import Configuration from freqtrade.configuration import Configuration
from freqtrade.data import history from freqtrade.data import history
from freqtrade.data.dataprovider import DataProvider 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.persistence import Trade
from freqtrade.resolvers import ExchangeResolver, StrategyResolver from freqtrade.resolvers import ExchangeResolver, StrategyResolver
from freqtrade.state import RunMode from freqtrade.state import RunMode
@ -77,7 +77,7 @@ class Backtesting(object):
if self.config.get('strategy_list', None): if self.config.get('strategy_list', None):
# Force one interval # Force one interval
self.ticker_interval = str(self.config.get('ticker_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']): for strat in list(self.config['strategy_list']):
stratconf = deepcopy(self.config) stratconf = deepcopy(self.config)
stratconf['strategy'] = strat stratconf['strategy'] = strat
@ -96,7 +96,7 @@ class Backtesting(object):
self.strategy = strategy self.strategy = strategy
self.ticker_interval = self.config.get('ticker_interval') 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.tickerdata_to_dataframe = strategy.tickerdata_to_dataframe
self.advise_buy = strategy.advise_buy self.advise_buy = strategy.advise_buy
self.advise_sell = strategy.advise_sell self.advise_sell = strategy.advise_sell
@ -421,7 +421,7 @@ class Backtesting(object):
min_date, max_date = optimize.get_timeframe(data) min_date, max_date = optimize.get_timeframe(data)
# Validate dataframe for missing values (mainly at start and end, as fillup is called) # Validate dataframe for missing values (mainly at start and end, as fillup is called)
optimize.validate_backtest_data(data, min_date, max_date, optimize.validate_backtest_data(data, min_date, max_date,
constants.TICKER_INTERVAL_MINUTES[self.ticker_interval]) timeframe_to_minutes(self.ticker_interval))
logger.info( logger.info(
'Measuring data from %s up to %s (%s days)..', 'Measuring data from %s up to %s (%s days)..',
min_date.isoformat(), min_date.isoformat(),

View File

@ -12,8 +12,8 @@ import warnings
import arrow import arrow
from pandas import DataFrame from pandas import DataFrame
from freqtrade import constants
from freqtrade.data.dataprovider import DataProvider from freqtrade.data.dataprovider import DataProvider
from freqtrade.misc import timeframe_to_minutes
from freqtrade.persistence import Trade from freqtrade.persistence import Trade
from freqtrade.wallets import Wallets from freqtrade.wallets import Wallets
@ -221,7 +221,7 @@ class IStrategy(ABC):
# Check if dataframe is out of date # Check if dataframe is out of date
signal_date = arrow.get(latest['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) offset = self.config.get('exchange', {}).get('outdated_offset', 5)
if signal_date < (arrow.utcnow().shift(minutes=-(interval_minutes * 2 + offset))): if signal_date < (arrow.utcnow().shift(minutes=-(interval_minutes * 2 + offset))):
logger.warning( logger.warning(

View File

@ -3,11 +3,11 @@ from typing import NamedTuple, List
import arrow import arrow
from pandas import DataFrame from pandas import DataFrame
from freqtrade.misc import timeframe_to_minutes
from freqtrade.strategy.interface import SellType from freqtrade.strategy.interface import SellType
from freqtrade.constants import TICKER_INTERVAL_MINUTES
ticker_start_time = arrow.get(2018, 10, 3) ticker_start_time = arrow.get(2018, 10, 3)
tests_ticker_interval = "1h" tests_ticker_interval = '1h'
class BTrade(NamedTuple): class BTrade(NamedTuple):
@ -32,7 +32,7 @@ class BTContainer(NamedTuple):
def _get_frame_time_from_offset(offset): 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) ).datetime.replace(tzinfo=None)

View File

@ -1,7 +1,8 @@
# pragma pylint: disable=missing-docstring, protected-access, C0103 # pragma pylint: disable=missing-docstring, protected-access, C0103
from freqtrade import optimize, constants from freqtrade import optimize
from freqtrade.arguments import TimeRange from freqtrade.arguments import TimeRange
from freqtrade.data import history from freqtrade.data import history
from freqtrade.misc import timeframe_to_minutes
from freqtrade.strategy.default_strategy import DefaultStrategy from freqtrade.strategy.default_strategy import DefaultStrategy
from freqtrade.tests.conftest import log_has, patch_exchange 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) min_date, max_date = optimize.get_timeframe(data)
caplog.clear() caplog.clear()
assert optimize.validate_backtest_data(data, min_date, max_date, 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 len(caplog.record_tuples) == 1
assert log_has( assert log_has(
"UNITTEST/BTC has missing frames: expected 14396, got 13680, that's 716 missing values", "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) min_date, max_date = optimize.get_timeframe(data)
caplog.clear() caplog.clear()
assert not optimize.validate_backtest_data(data, min_date, max_date, 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 assert len(caplog.record_tuples) == 0

View File

@ -28,6 +28,7 @@ from freqtrade import constants, misc
from freqtrade.arguments import Arguments from freqtrade.arguments import Arguments
from freqtrade.configuration import Configuration from freqtrade.configuration import Configuration
from freqtrade.data import history from freqtrade.data import history
from freqtrade.misc import timeframe_to_seconds
from freqtrade.resolvers import StrategyResolver from freqtrade.resolvers import StrategyResolver
from freqtrade.state import RunMode 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 Return the index of a specific date
""" """
interval_minutes = constants.TICKER_INTERVAL_MINUTES[interval] interval_seconds = timeframe_to_seconds(interval)
return int((max_date - min_date) / (interval_minutes * 60)) return int((max_date - min_date) / interval_seconds)
def plot_parse_args(args: List[str]) -> Namespace: def plot_parse_args(args: List[str]) -> Namespace: