Ensure the same timestamp is used for backtest and signal export

This commit is contained in:
Matthias 2022-06-15 06:53:52 +02:00
parent 01a68e1060
commit 3c62df6b86
4 changed files with 26 additions and 21 deletions

View File

@ -1264,13 +1264,14 @@ class Backtesting:
self.results['strategy_comparison'].extend(results['strategy_comparison'])
else:
self.results = results
dt_appendix = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
if self.config.get('export', 'none') in ('trades', 'signals'):
store_backtest_stats(self.config['exportfilename'], self.results)
store_backtest_stats(self.config['exportfilename'], self.results, dt_appendix)
if (self.config.get('export', 'none') == 'signals' and
self.dataprovider.runmode == RunMode.BACKTEST):
store_backtest_signal_candles(self.config['exportfilename'], self.processed_dfs)
store_backtest_signal_candles(
self.config['exportfilename'], self.processed_dfs, dt_appendix)
# Results may be mixed up now. Sort them so they follow --strategy-list order.
if 'strategy_list' in self.config and len(self.results) > 0:

View File

@ -17,21 +17,21 @@ from freqtrade.optimize.backtest_caching import get_backtest_metadata_filename
logger = logging.getLogger(__name__)
def store_backtest_stats(recordfilename: Path, stats: Dict[str, DataFrame]) -> None:
def store_backtest_stats(
recordfilename: Path, stats: Dict[str, DataFrame], dtappendix: str) -> None:
"""
Stores backtest results
:param recordfilename: Path object, which can either be a filename or a directory.
Filenames will be appended with a timestamp right before the suffix
while for directories, <directory>/backtest-result-<datetime>.json will be used as filename
:param stats: Dataframe containing the backtesting statistics
:param dtappendix: Datetime to use for the filename
"""
if recordfilename.is_dir():
filename = (recordfilename /
f'backtest-result-{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}.json')
filename = (recordfilename / f'backtest-result-{dtappendix}.json')
else:
filename = Path.joinpath(
recordfilename.parent,
f'{recordfilename.stem}-{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}'
recordfilename.parent, f'{recordfilename.stem}-{dtappendix}'
).with_suffix(recordfilename.suffix)
# Store metadata separately.
@ -44,7 +44,8 @@ def store_backtest_stats(recordfilename: Path, stats: Dict[str, DataFrame]) -> N
file_dump_json(latest_filename, {'latest_backtest': str(filename.name)})
def store_backtest_signal_candles(recordfilename: Path, candles: Dict[str, Dict]) -> Path:
def store_backtest_signal_candles(
recordfilename: Path, candles: Dict[str, Dict], dtappendix: str) -> Path:
"""
Stores backtest trade signal candles
:param recordfilename: Path object, which can either be a filename or a directory.
@ -52,14 +53,13 @@ def store_backtest_signal_candles(recordfilename: Path, candles: Dict[str, Dict]
while for directories, <directory>/backtest-result-<datetime>_signals.pkl will be used
as filename
:param stats: Dict containing the backtesting signal candles
:param dtappendix: Datetime to use for the filename
"""
if recordfilename.is_dir():
filename = (recordfilename /
f'backtest-result-{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}_signals.pkl')
filename = (recordfilename / f'backtest-result-{dtappendix}_signals.pkl')
else:
filename = Path.joinpath(
recordfilename.parent,
f'{recordfilename.stem}-{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}_signals.pkl'
recordfilename.parent, f'{recordfilename.stem}-{dtappendix}_signals.pkl'
)
file_dump_joblib(filename, candles)

View File

@ -1,6 +1,7 @@
import asyncio
import logging
from copy import deepcopy
from datetime import datetime
from typing import Any, Dict, List
from fastapi import APIRouter, BackgroundTasks, Depends
@ -102,7 +103,10 @@ async def api_start_backtest(bt_settings: BacktestRequest, background_tasks: Bac
min_date=min_date, max_date=max_date)
if btconfig.get('export', 'none') == 'trades':
store_backtest_stats(btconfig['exportfilename'], ApiServer._bt.results)
store_backtest_stats(
btconfig['exportfilename'], ApiServer._bt.results,
datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
)
logger.info("Backtest finished.")

View File

@ -171,7 +171,7 @@ def test_generate_backtest_stats(default_conf, testdatadir, tmpdir):
_backup_file(filename_last, copy_file=True)
assert not filename.is_file()
store_backtest_stats(filename, stats)
store_backtest_stats(filename, stats, '2022_01_01_15_05_13')
# get real Filename (it's btresult-<date>.json)
last_fn = get_latest_backtest_filename(filename_last.parent)
@ -194,7 +194,7 @@ def test_store_backtest_stats(testdatadir, mocker):
dump_mock = mocker.patch('freqtrade.optimize.optimize_reports.file_dump_json')
store_backtest_stats(testdatadir, {'metadata': {}})
store_backtest_stats(testdatadir, {'metadata': {}}, '2022_01_01_15_05_13')
assert dump_mock.call_count == 3
assert isinstance(dump_mock.call_args_list[0][0][0], Path)
@ -202,7 +202,7 @@ def test_store_backtest_stats(testdatadir, mocker):
dump_mock.reset_mock()
filename = testdatadir / 'testresult.json'
store_backtest_stats(filename, {'metadata': {}})
store_backtest_stats(filename, {'metadata': {}}, '2022_01_01_15_05_13')
assert dump_mock.call_count == 3
assert isinstance(dump_mock.call_args_list[0][0][0], Path)
# result will be testdatadir / testresult-<timestamp>.json
@ -216,7 +216,7 @@ def test_store_backtest_candles(testdatadir, mocker):
candle_dict = {'DefStrat': {'UNITTEST/BTC': pd.DataFrame()}}
# mock directory exporting
store_backtest_signal_candles(testdatadir, candle_dict)
store_backtest_signal_candles(testdatadir, candle_dict, '2022_01_01_15_05_13')
assert dump_mock.call_count == 1
assert isinstance(dump_mock.call_args_list[0][0][0], Path)
@ -225,7 +225,7 @@ def test_store_backtest_candles(testdatadir, mocker):
dump_mock.reset_mock()
# mock file exporting
filename = Path(testdatadir / 'testresult')
store_backtest_signal_candles(filename, candle_dict)
store_backtest_signal_candles(filename, candle_dict, '2022_01_01_15_05_13')
assert dump_mock.call_count == 1
assert isinstance(dump_mock.call_args_list[0][0][0], Path)
# result will be testdatadir / testresult-<timestamp>_signals.pkl
@ -238,7 +238,7 @@ def test_write_read_backtest_candles(tmpdir):
candle_dict = {'DefStrat': {'UNITTEST/BTC': pd.DataFrame()}}
# test directory exporting
stored_file = store_backtest_signal_candles(Path(tmpdir), candle_dict)
stored_file = store_backtest_signal_candles(Path(tmpdir), candle_dict, '2022_01_01_15_05_13')
scp = open(stored_file, "rb")
pickled_signal_candles = joblib.load(scp)
scp.close()
@ -252,7 +252,7 @@ def test_write_read_backtest_candles(tmpdir):
# test file exporting
filename = Path(tmpdir / 'testresult')
stored_file = store_backtest_signal_candles(filename, candle_dict)
stored_file = store_backtest_signal_candles(filename, candle_dict, '2022_01_01_15_05_13')
scp = open(stored_file, "rb")
pickled_signal_candles = joblib.load(scp)
scp.close()