From b04c5aec88bc004abeb1cd33ca1c320be0b2854a Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 15 Dec 2024 13:18:25 +0100 Subject: [PATCH] refactor: move backtest "storage" logic to storage file --- freqtrade/optimize/backtesting.py | 18 ++------ .../optimize/optimize_reports/__init__.py | 5 +-- .../optimize/optimize_reports/bt_storage.py | 44 ++++++++++++------- 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 699cb73ed..bf0b52e72 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -47,8 +47,7 @@ from freqtrade.optimize.optimize_reports import ( generate_rejected_signals, generate_trade_signal_candles, show_backtest_results, - store_backtest_analysis_results, - store_backtest_stats, + store_backtest_results, ) from freqtrade.persistence import ( CustomDataWrapper, @@ -1662,21 +1661,12 @@ class Backtesting: dt_appendix = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") if self.config.get("export", "none") in ("trades", "signals"): combined_res = combined_dataframes_with_rel_mean(data, min_date, max_date) - store_backtest_stats( - self.config["exportfilename"], + store_backtest_results( + self.config, self.results, dt_appendix, market_change_data=combined_res, - ) - - if ( - self.config.get("export", "none") == "signals" - and self.dataprovider.runmode == RunMode.BACKTEST - ): - store_backtest_analysis_results( - self.config["exportfilename"], - self.analysis_results, - dt_appendix, + analysis_results=self.analysis_results, ) # Results may be mixed up now. Sort them so they follow --strategy-list order. diff --git a/freqtrade/optimize/optimize_reports/__init__.py b/freqtrade/optimize/optimize_reports/__init__.py index 6f3278a1c..c08bae4be 100644 --- a/freqtrade/optimize/optimize_reports/__init__.py +++ b/freqtrade/optimize/optimize_reports/__init__.py @@ -11,10 +11,7 @@ from freqtrade.optimize.optimize_reports.bt_output import ( text_table_strategy, text_table_tags, ) -from freqtrade.optimize.optimize_reports.bt_storage import ( - store_backtest_analysis_results, - store_backtest_stats, -) +from freqtrade.optimize.optimize_reports.bt_storage import store_backtest_results from freqtrade.optimize.optimize_reports.optimize_reports import ( generate_all_periodic_breakdown_stats, generate_backtest_stats, diff --git a/freqtrade/optimize/optimize_reports/bt_storage.py b/freqtrade/optimize/optimize_reports/bt_storage.py index 7a4aaf651..cd47aab18 100644 --- a/freqtrade/optimize/optimize_reports/bt_storage.py +++ b/freqtrade/optimize/optimize_reports/bt_storage.py @@ -4,6 +4,7 @@ from pathlib import Path from pandas import DataFrame from freqtrade.constants import LAST_BT_RESULT_FN +from freqtrade.enums.runmode import RunMode from freqtrade.ft_types import BacktestResultType from freqtrade.misc import file_dump_joblib, file_dump_json from freqtrade.optimize.backtest_caching import get_backtest_metadata_filename @@ -29,21 +30,27 @@ def _generate_filename(recordfilename: Path, appendix: str, suffix: str) -> Path return filename -def store_backtest_stats( - recordfilename: Path, +def store_backtest_results( + config: dict, stats: BacktestResultType, dtappendix: str, *, market_change_data: DataFrame | None = None, + analysis_results: dict[str, dict[str, DataFrame]] | None = None, ) -> Path: """ - 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, /backtest-result-.json will be used as filename + Stores backtest results and analysis data + :param config: Configuration dictionary :param stats: Dataframe containing the backtesting statistics :param dtappendix: Datetime to use for the filename + :param market_change_data: Dataframe containing market change data + :param analysis_results: Dictionary containing analysis results """ + + # 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, /backtest-result-.json will be used as filename + recordfilename: Path = config["exportfilename"] filename = _generate_filename(recordfilename, dtappendix, ".json") # Store metadata separately. @@ -65,6 +72,21 @@ def store_backtest_stats( filename_mc, compression_level=9, compression="lz4" ) + if ( + config.get("export", "none") == "signals" + and analysis_results is not None + and config.get("runmode", RunMode.OTHER) == RunMode.BACKTEST + ): + _store_backtest_analysis_data( + recordfilename, analysis_results["signals"], dtappendix, "signals" + ) + _store_backtest_analysis_data( + recordfilename, analysis_results["rejected"], dtappendix, "rejected" + ) + _store_backtest_analysis_data( + recordfilename, analysis_results["exited"], dtappendix, "exited" + ) + return filename @@ -86,13 +108,3 @@ def _store_backtest_analysis_data( file_dump_joblib(filename, data) return filename - - -def store_backtest_analysis_results( - recordfilename: Path, - candles: dict[str, dict[str, DataFrame]], - dtappendix: str, -) -> None: - _store_backtest_analysis_data(recordfilename, candles["signals"], dtappendix, "signals") - _store_backtest_analysis_data(recordfilename, candles["rejected"], dtappendix, "rejected") - _store_backtest_analysis_data(recordfilename, candles["exited"], dtappendix, "exited")