Move most logic to history
This commit is contained in:
parent
9c7696a8ce
commit
704121c197
@ -8,6 +8,7 @@ Includes:
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import operator
|
import operator
|
||||||
|
from copy import deepcopy
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, List, Optional, Tuple
|
from typing import Any, Dict, List, Optional, Tuple
|
||||||
@ -19,7 +20,7 @@ from pandas import DataFrame
|
|||||||
from freqtrade import OperationalException, misc
|
from freqtrade import OperationalException, misc
|
||||||
from freqtrade.configuration import TimeRange
|
from freqtrade.configuration import TimeRange
|
||||||
from freqtrade.data.converter import parse_ticker_dataframe, trades_to_ohlcv
|
from freqtrade.data.converter import parse_ticker_dataframe, trades_to_ohlcv
|
||||||
from freqtrade.exchange import Exchange, timeframe_to_minutes
|
from freqtrade.exchange import Exchange, timeframe_to_minutes, timeframe_to_seconds
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -127,7 +128,8 @@ def load_pair_history(pair: str,
|
|||||||
refresh_pairs: bool = False,
|
refresh_pairs: bool = False,
|
||||||
exchange: Optional[Exchange] = None,
|
exchange: Optional[Exchange] = None,
|
||||||
fill_up_missing: bool = True,
|
fill_up_missing: bool = True,
|
||||||
drop_incomplete: bool = True
|
drop_incomplete: bool = True,
|
||||||
|
startup_candles: int = 0,
|
||||||
) -> DataFrame:
|
) -> DataFrame:
|
||||||
"""
|
"""
|
||||||
Loads cached ticker history for the given pair.
|
Loads cached ticker history for the given pair.
|
||||||
@ -140,9 +142,15 @@ def load_pair_history(pair: str,
|
|||||||
:param exchange: Exchange object (needed when using "refresh_pairs")
|
:param exchange: Exchange object (needed when using "refresh_pairs")
|
||||||
:param fill_up_missing: Fill missing values with "No action"-candles
|
:param fill_up_missing: Fill missing values with "No action"-candles
|
||||||
:param drop_incomplete: Drop last candle assuming it may be incomplete.
|
:param drop_incomplete: Drop last candle assuming it may be incomplete.
|
||||||
|
:param startup_candles: Additional candles to load at the start of the period
|
||||||
:return: DataFrame with ohlcv data
|
:return: DataFrame with ohlcv data
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
timerange_startup = deepcopy(timerange)
|
||||||
|
if startup_candles:
|
||||||
|
logger.info('Using indicator startup period: %s ...', startup_candles)
|
||||||
|
timerange_startup.subtract_start(timeframe_to_seconds(ticker_interval) * startup_candles)
|
||||||
|
|
||||||
# The user forced the refresh of pairs
|
# The user forced the refresh of pairs
|
||||||
if refresh_pairs:
|
if refresh_pairs:
|
||||||
download_pair_history(datadir=datadir,
|
download_pair_history(datadir=datadir,
|
||||||
@ -151,11 +159,11 @@ def load_pair_history(pair: str,
|
|||||||
ticker_interval=ticker_interval,
|
ticker_interval=ticker_interval,
|
||||||
timerange=timerange)
|
timerange=timerange)
|
||||||
|
|
||||||
pairdata = load_tickerdata_file(datadir, pair, ticker_interval, timerange=timerange)
|
pairdata = load_tickerdata_file(datadir, pair, ticker_interval, timerange=timerange_startup)
|
||||||
|
|
||||||
if pairdata:
|
if pairdata:
|
||||||
if timerange:
|
if timerange_startup:
|
||||||
_validate_pairdata(pair, pairdata, timerange)
|
_validate_pairdata(pair, pairdata, timerange_startup)
|
||||||
return parse_ticker_dataframe(pairdata, ticker_interval, pair=pair,
|
return parse_ticker_dataframe(pairdata, ticker_interval, pair=pair,
|
||||||
fill_missing=fill_up_missing,
|
fill_missing=fill_up_missing,
|
||||||
drop_incomplete=drop_incomplete)
|
drop_incomplete=drop_incomplete)
|
||||||
@ -174,10 +182,20 @@ def load_data(datadir: Path,
|
|||||||
exchange: Optional[Exchange] = None,
|
exchange: Optional[Exchange] = None,
|
||||||
timerange: Optional[TimeRange] = None,
|
timerange: Optional[TimeRange] = None,
|
||||||
fill_up_missing: bool = True,
|
fill_up_missing: bool = True,
|
||||||
|
startup_candles: int = 0,
|
||||||
) -> Dict[str, DataFrame]:
|
) -> Dict[str, DataFrame]:
|
||||||
"""
|
"""
|
||||||
Loads ticker history data for a list of pairs
|
Loads ticker history data for a list of pairs
|
||||||
:return: dict(<pair>:<tickerlist>)
|
:param datadir: Path to the data storage location.
|
||||||
|
:param ticker_interval: Ticker-interval (e.g. "5m")
|
||||||
|
:param pairs: List of pairs to load
|
||||||
|
:param refresh_pairs: Refresh pairs from exchange.
|
||||||
|
(Note: Requires exchange to be passed as well.)
|
||||||
|
:param exchange: Exchange object (needed when using "refresh_pairs")
|
||||||
|
:param timerange: Limit data to be loaded to this timerange
|
||||||
|
:param fill_up_missing: Fill missing values with "No action"-candles
|
||||||
|
:param startup_candles: Additional candles to load at the start of the period
|
||||||
|
:return: dict(<pair>:<Dataframe>)
|
||||||
TODO: refresh_pairs is still used by edge to keep the data uptodate.
|
TODO: refresh_pairs is still used by edge to keep the data uptodate.
|
||||||
This should be replaced in the future. Instead, writing the current candles to disk
|
This should be replaced in the future. Instead, writing the current candles to disk
|
||||||
from dataprovider should be implemented, as this would avoid loading ohlcv data twice.
|
from dataprovider should be implemented, as this would avoid loading ohlcv data twice.
|
||||||
|
@ -92,7 +92,6 @@ class Backtesting:
|
|||||||
|
|
||||||
# Get maximum required startup period
|
# Get maximum required startup period
|
||||||
self.required_startup = max([strat.startup_candle_count for strat in self.strategylist])
|
self.required_startup = max([strat.startup_candle_count for strat in self.strategylist])
|
||||||
self.required_startup_s = self.required_startup * timeframe_to_seconds(self.ticker_interval)
|
|
||||||
# Load one (first) strategy
|
# Load one (first) strategy
|
||||||
self._set_strategy(self.strategylist[0])
|
self._set_strategy(self.strategylist[0])
|
||||||
|
|
||||||
@ -422,11 +421,6 @@ class Backtesting:
|
|||||||
timerange = TimeRange.parse_timerange(None if self.config.get(
|
timerange = TimeRange.parse_timerange(None if self.config.get(
|
||||||
'timerange') is None else str(self.config.get('timerange')))
|
'timerange') is None else str(self.config.get('timerange')))
|
||||||
|
|
||||||
logger.info('Using indicator startup period: %s ...', self.required_startup)
|
|
||||||
|
|
||||||
# Timerange_startup is timerange - startup-candles
|
|
||||||
timerange_startup = deepcopy(timerange)
|
|
||||||
timerange_startup.subtract_start(self.required_startup_s)
|
|
||||||
|
|
||||||
data = history.load_data(
|
data = history.load_data(
|
||||||
datadir=Path(self.config['datadir']),
|
datadir=Path(self.config['datadir']),
|
||||||
@ -453,10 +447,12 @@ class Backtesting:
|
|||||||
'Loading backtest data from %s up to %s (%s days)..',
|
'Loading backtest data from %s up to %s (%s days)..',
|
||||||
min_date.isoformat(), max_date.isoformat(), (max_date - min_date).days
|
min_date.isoformat(), max_date.isoformat(), (max_date - min_date).days
|
||||||
)
|
)
|
||||||
if not timerange_startup.starttype:
|
if not timerange.starttype:
|
||||||
# If no startts was defined, we need to move the backtesting start
|
# If no startts was defined, we need to move the backtesting start
|
||||||
logger.info("Moving start-date by %s candles.", self.required_startup)
|
logger.info("Moving start-date by %s candles.", self.required_startup)
|
||||||
timerange.startts = min_date.timestamp + self.required_startup_s
|
timerange.startts = (min_date.timestamp
|
||||||
|
+ timeframe_to_seconds(self.ticker_interval)
|
||||||
|
* self.required_startup)
|
||||||
timerange.starttype = 'date'
|
timerange.starttype = 'date'
|
||||||
|
|
||||||
for strat in self.strategylist:
|
for strat in self.strategylist:
|
||||||
|
@ -117,7 +117,7 @@ def simple_backtest(config, contour, num_results, mocker, testdatadir) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def mocked_load_data(datadir, pairs=[], ticker_interval='0m', refresh_pairs=False,
|
def mocked_load_data(datadir, pairs=[], ticker_interval='0m', refresh_pairs=False,
|
||||||
timerange=None, exchange=None, live=False):
|
timerange=None, exchange=None, live=False, startup_candles=0):
|
||||||
tickerdata = history.load_tickerdata_file(datadir, 'UNITTEST/BTC', '1m', timerange=timerange)
|
tickerdata = history.load_tickerdata_file(datadir, 'UNITTEST/BTC', '1m', timerange=timerange)
|
||||||
pairdata = {'UNITTEST/BTC': parse_ticker_dataframe(tickerdata, '1m', pair="UNITTEST/BTC",
|
pairdata = {'UNITTEST/BTC': parse_ticker_dataframe(tickerdata, '1m', pair="UNITTEST/BTC",
|
||||||
fill_missing=True)}
|
fill_missing=True)}
|
||||||
|
Loading…
Reference in New Issue
Block a user