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'
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"],

View File

@ -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')

View File

@ -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

View 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)

View File

@ -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

View File

@ -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

View File

@ -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(),

View File

@ -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(

View File

@ -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)

View File

@ -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

View File

@ -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: