Merge pull request #4887 from freqtrade/timerange_noarrow
Don't use Arrow to get min/max backtest dates
This commit is contained in:
commit
4a7d7a5779
@ -3,6 +3,7 @@ This module contains the argument manager class
|
||||
"""
|
||||
import logging
|
||||
import re
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
import arrow
|
||||
@ -43,7 +44,7 @@ class TimeRange:
|
||||
self.startts = self.startts - seconds
|
||||
|
||||
def adjust_start_if_necessary(self, timeframe_secs: int, startup_candles: int,
|
||||
min_date: arrow.Arrow) -> None:
|
||||
min_date: datetime) -> None:
|
||||
"""
|
||||
Adjust startts by <startup_candles> candles.
|
||||
Applies only if no startup-candles have been available.
|
||||
@ -54,11 +55,11 @@ class TimeRange:
|
||||
:return: None (Modifies the object in place)
|
||||
"""
|
||||
if (not self.starttype or (startup_candles
|
||||
and min_date.int_timestamp >= self.startts)):
|
||||
and min_date.timestamp() >= self.startts)):
|
||||
# If no startts was defined, or backtest-data starts at the defined backtest-date
|
||||
logger.warning("Moving start-date by %s candles to account for startup time.",
|
||||
startup_candles)
|
||||
self.startts = (min_date.int_timestamp + timeframe_secs * startup_candles)
|
||||
self.startts = int(min_date.timestamp() + timeframe_secs * startup_candles)
|
||||
self.starttype = 'date'
|
||||
|
||||
@staticmethod
|
||||
|
@ -367,7 +367,7 @@ def convert_trades_to_ohlcv(pairs: List[str], timeframes: List[str],
|
||||
logger.exception(f'Could not convert {pair} to OHLCV.')
|
||||
|
||||
|
||||
def get_timerange(data: Dict[str, DataFrame]) -> Tuple[arrow.Arrow, arrow.Arrow]:
|
||||
def get_timerange(data: Dict[str, DataFrame]) -> Tuple[datetime, datetime]:
|
||||
"""
|
||||
Get the maximum common timerange for the given backtest data.
|
||||
|
||||
@ -375,7 +375,7 @@ def get_timerange(data: Dict[str, DataFrame]) -> Tuple[arrow.Arrow, arrow.Arrow]
|
||||
:return: tuple containing min_date, max_date
|
||||
"""
|
||||
timeranges = [
|
||||
(arrow.get(frame['date'].min()), arrow.get(frame['date'].max()))
|
||||
(frame['date'].min().to_pydatetime(), frame['date'].max().to_pydatetime())
|
||||
for frame in data.values()
|
||||
]
|
||||
return (min(timeranges, key=operator.itemgetter(0))[0],
|
||||
|
@ -9,7 +9,7 @@ from copy import deepcopy
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
from pandas import DataFrame
|
||||
from pandas import DataFrame, NaT
|
||||
|
||||
from freqtrade.configuration import TimeRange, remove_credentials, validate_config_consistency
|
||||
from freqtrade.constants import DATETIME_PRINT_FORMAT
|
||||
@ -159,7 +159,7 @@ class Backtesting:
|
||||
|
||||
logger.info(f'Loading data from {min_date.strftime(DATETIME_PRINT_FORMAT)} '
|
||||
f'up to {max_date.strftime(DATETIME_PRINT_FORMAT)} '
|
||||
f'({(max_date - min_date).days} days)..')
|
||||
f'({(max_date - min_date).days} days).')
|
||||
|
||||
# Adjust startts forward if not enough data is available
|
||||
timerange.adjust_start_if_necessary(timeframe_to_seconds(self.timeframe),
|
||||
@ -449,15 +449,17 @@ class Backtesting:
|
||||
preprocessed[pair] = trim_dataframe(df, timerange,
|
||||
startup_candles=self.required_startup)
|
||||
min_date, max_date = history.get_timerange(preprocessed)
|
||||
|
||||
if min_date is NaT or max_date is NaT:
|
||||
raise OperationalException(
|
||||
"No data left after adjusting for startup candles. ")
|
||||
logger.info(f'Backtesting with data from {min_date.strftime(DATETIME_PRINT_FORMAT)} '
|
||||
f'up to {max_date.strftime(DATETIME_PRINT_FORMAT)} '
|
||||
f'({(max_date - min_date).days} days)..')
|
||||
f'({(max_date - min_date).days} days).')
|
||||
# Execute backtest and store results
|
||||
results = self.backtest(
|
||||
processed=preprocessed,
|
||||
start_date=min_date.datetime,
|
||||
end_date=max_date.datetime,
|
||||
start_date=min_date,
|
||||
end_date=max_date,
|
||||
max_open_trades=max_open_trades,
|
||||
position_stacking=self.config.get('position_stacking', False),
|
||||
enable_protections=self.config.get('enable_protections', False),
|
||||
|
@ -273,8 +273,8 @@ class Hyperopt:
|
||||
|
||||
bt_results = self.backtesting.backtest(
|
||||
processed=processed,
|
||||
start_date=self.min_date.datetime,
|
||||
end_date=self.max_date.datetime,
|
||||
start_date=self.min_date,
|
||||
end_date=self.max_date,
|
||||
max_open_trades=self.max_open_trades,
|
||||
position_stacking=self.position_stacking,
|
||||
enable_protections=self.config.get('enable_protections', False),
|
||||
@ -314,7 +314,7 @@ class Hyperopt:
|
||||
if trade_count >= self.config['hyperopt_min_trades']:
|
||||
loss = self.calculate_loss(results=backtesting_results['results'],
|
||||
trade_count=trade_count,
|
||||
min_date=min_date.datetime, max_date=max_date.datetime,
|
||||
min_date=min_date, max_date=max_date,
|
||||
config=self.config, processed=processed)
|
||||
return {
|
||||
'loss': loss,
|
||||
|
@ -3,7 +3,6 @@ from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Union
|
||||
|
||||
from arrow import Arrow
|
||||
from numpy import int64
|
||||
from pandas import DataFrame
|
||||
from tabulate import tabulate
|
||||
@ -259,7 +258,7 @@ def generate_daily_stats(results: DataFrame) -> Dict[str, Any]:
|
||||
def generate_strategy_stats(btdata: Dict[str, DataFrame],
|
||||
strategy: str,
|
||||
content: Dict[str, Any],
|
||||
min_date: Arrow, max_date: Arrow,
|
||||
min_date: datetime, max_date: datetime,
|
||||
market_change: float
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
@ -314,10 +313,10 @@ def generate_strategy_stats(btdata: Dict[str, DataFrame],
|
||||
'profit_median': results['profit_ratio'].median() if len(results) > 0 else 0,
|
||||
'profit_total': results['profit_abs'].sum() / starting_balance,
|
||||
'profit_total_abs': results['profit_abs'].sum(),
|
||||
'backtest_start': min_date.datetime,
|
||||
'backtest_start_ts': min_date.int_timestamp * 1000,
|
||||
'backtest_end': max_date.datetime,
|
||||
'backtest_end_ts': max_date.int_timestamp * 1000,
|
||||
'backtest_start': min_date,
|
||||
'backtest_start_ts': int(min_date.timestamp() * 1000),
|
||||
'backtest_end': max_date,
|
||||
'backtest_end_ts': int(max_date.timestamp() * 1000),
|
||||
'backtest_days': backtest_days,
|
||||
|
||||
'backtest_run_start_ts': content['backtest_start_time'],
|
||||
@ -397,7 +396,7 @@ def generate_strategy_stats(btdata: Dict[str, DataFrame],
|
||||
|
||||
def generate_backtest_stats(btdata: Dict[str, DataFrame],
|
||||
all_results: Dict[str, Dict[str, Union[DataFrame, Dict]]],
|
||||
min_date: Arrow, max_date: Arrow
|
||||
min_date: datetime, max_date: datetime
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
:param btdata: Backtest data
|
||||
|
@ -366,7 +366,7 @@ def test_backtesting_start(default_conf, mocker, testdatadir, caplog) -> None:
|
||||
# check the logs, that will contain the backtest result
|
||||
exists = [
|
||||
'Backtesting with data from 2017-11-14 21:17:00 '
|
||||
'up to 2017-11-14 22:59:00 (0 days)..'
|
||||
'up to 2017-11-14 22:59:00 (0 days).'
|
||||
]
|
||||
for line in exists:
|
||||
assert log_has(line, caplog)
|
||||
@ -791,9 +791,9 @@ def test_backtest_start_timerange(default_conf, mocker, caplog, testdatadir):
|
||||
'Parameter --timerange detected: 1510694220-1510700340 ...',
|
||||
f'Using data directory: {testdatadir} ...',
|
||||
'Loading data from 2017-11-14 20:57:00 '
|
||||
'up to 2017-11-14 22:58:00 (0 days)..',
|
||||
'up to 2017-11-14 22:58:00 (0 days).',
|
||||
'Backtesting with data from 2017-11-14 21:17:00 '
|
||||
'up to 2017-11-14 22:58:00 (0 days)..',
|
||||
'up to 2017-11-14 22:58:00 (0 days).',
|
||||
'Parameter --enable-position-stacking detected ...'
|
||||
]
|
||||
|
||||
@ -864,9 +864,9 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir):
|
||||
'Parameter --timerange detected: 1510694220-1510700340 ...',
|
||||
f'Using data directory: {testdatadir} ...',
|
||||
'Loading data from 2017-11-14 20:57:00 '
|
||||
'up to 2017-11-14 22:58:00 (0 days)..',
|
||||
'up to 2017-11-14 22:58:00 (0 days).',
|
||||
'Backtesting with data from 2017-11-14 21:17:00 '
|
||||
'up to 2017-11-14 22:58:00 (0 days)..',
|
||||
'up to 2017-11-14 22:58:00 (0 days).',
|
||||
'Parameter --enable-position-stacking detected ...',
|
||||
'Running backtesting for Strategy DefaultStrategy',
|
||||
'Running backtesting for Strategy TestStrategyLegacy',
|
||||
@ -960,9 +960,9 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat
|
||||
'Parameter --timerange detected: 1510694220-1510700340 ...',
|
||||
f'Using data directory: {testdatadir} ...',
|
||||
'Loading data from 2017-11-14 20:57:00 '
|
||||
'up to 2017-11-14 22:58:00 (0 days)..',
|
||||
'up to 2017-11-14 22:58:00 (0 days).',
|
||||
'Backtesting with data from 2017-11-14 21:17:00 '
|
||||
'up to 2017-11-14 22:58:00 (0 days)..',
|
||||
'up to 2017-11-14 22:58:00 (0 days).',
|
||||
'Parameter --enable-position-stacking detected ...',
|
||||
'Running backtesting for Strategy DefaultStrategy',
|
||||
'Running backtesting for Strategy TestStrategyLegacy',
|
||||
|
Loading…
Reference in New Issue
Block a user