get rid of TICKER_INTERVAL_MINUTES dict, use ccxt's parse_timeframe() instead
This commit is contained in:
parent
75c522e082
commit
2aa1b43f01
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user