From 5744e16a0702c8787f50998df7e74f60b77ad976 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 14 Dec 2024 19:50:59 +0100 Subject: [PATCH] refactor: use 1 structure to save analysis signals --- freqtrade/optimize/backtesting.py | 28 +++++++++---------- .../optimize/optimize_reports/bt_storage.py | 10 +++---- tests/optimize/test_optimize_reports.py | 19 ++++++++++--- 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 47f920e01..699cb73ed 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -121,10 +121,12 @@ class Backtesting: self.run_ids: dict[str, str] = {} self.strategylist: list[IStrategy] = [] self.all_results: dict[str, dict] = {} - self.processed_dfs: dict[str, dict] = {} + self.analysis_results: dict[str, dict[str, DataFrame]] = { + "signals": {}, + "rejected": {}, + "exited": {}, + } self.rejected_dict: dict[str, list] = {} - self.rejected_df: dict[str, dict] = {} - self.exited_dfs: dict[str, dict] = {} self._exchange_name = self.config["exchange"]["name"] if not exchange: @@ -1590,15 +1592,13 @@ class Backtesting: self.config.get("export", "none") == "signals" and self.dataprovider.runmode == RunMode.BACKTEST ): - self.processed_dfs[strategy_name] = generate_trade_signal_candles( - preprocessed_tmp, results, "open_date" - ) - self.rejected_df[strategy_name] = generate_rejected_signals( - preprocessed_tmp, self.rejected_dict - ) - self.exited_dfs[strategy_name] = generate_trade_signal_candles( - preprocessed_tmp, results, "close_date" - ) + signals = generate_trade_signal_candles(preprocessed_tmp, results, "open_date") + rejected = generate_rejected_signals(preprocessed_tmp, self.rejected_dict) + exited = generate_trade_signal_candles(preprocessed_tmp, results, "close_date") + + self.analysis_results["signals"][strategy_name] = signals + self.analysis_results["rejected"][strategy_name] = rejected + self.analysis_results["exited"][strategy_name] = exited return min_date, max_date @@ -1675,9 +1675,7 @@ class Backtesting: ): store_backtest_analysis_results( self.config["exportfilename"], - self.processed_dfs, - self.rejected_df, - self.exited_dfs, + self.analysis_results, dt_appendix, ) diff --git a/freqtrade/optimize/optimize_reports/bt_storage.py b/freqtrade/optimize/optimize_reports/bt_storage.py index 21532d4d2..7a4aaf651 100644 --- a/freqtrade/optimize/optimize_reports/bt_storage.py +++ b/freqtrade/optimize/optimize_reports/bt_storage.py @@ -90,11 +90,9 @@ def _store_backtest_analysis_data( def store_backtest_analysis_results( recordfilename: Path, - candles: dict[str, dict], - trades: dict[str, dict], - exited: dict[str, dict], + candles: dict[str, dict[str, DataFrame]], dtappendix: str, ) -> None: - _store_backtest_analysis_data(recordfilename, candles, dtappendix, "signals") - _store_backtest_analysis_data(recordfilename, trades, dtappendix, "rejected") - _store_backtest_analysis_data(recordfilename, exited, dtappendix, "exited") + _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") diff --git a/tests/optimize/test_optimize_reports.py b/tests/optimize/test_optimize_reports.py index 40673a1b6..dacc6c91a 100644 --- a/tests/optimize/test_optimize_reports.py +++ b/tests/optimize/test_optimize_reports.py @@ -293,7 +293,13 @@ def test_store_backtest_candles(testdatadir, mocker): candle_dict = {"DefStrat": {"UNITTEST/BTC": pd.DataFrame()}} # mock directory exporting - store_backtest_analysis_results(testdatadir, candle_dict, {}, {}, "2022_01_01_15_05_13") + data = { + "signals": candle_dict, + "rejected": {}, + "exited": {}, + } + + store_backtest_analysis_results(testdatadir, data, "2022_01_01_15_05_13") assert dump_mock.call_count == 3 assert isinstance(dump_mock.call_args_list[0][0][0], Path) @@ -304,7 +310,7 @@ def test_store_backtest_candles(testdatadir, mocker): dump_mock.reset_mock() # mock file exporting filename = Path(testdatadir / "testresult") - store_backtest_analysis_results(filename, candle_dict, {}, {}, "2022_01_01_15_05_13") + store_backtest_analysis_results(filename, data, "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-_signals.pkl @@ -320,7 +326,12 @@ def test_write_read_backtest_candles(tmp_path): # test directory exporting sample_date = "2022_01_01_15_05_13" - store_backtest_analysis_results(tmp_path, candle_dict, {}, {}, sample_date) + data = { + "signals": candle_dict, + "rejected": {}, + "exited": {}, + } + store_backtest_analysis_results(tmp_path, data, sample_date) stored_file = tmp_path / f"backtest-result-{sample_date}_signals.pkl" with stored_file.open("rb") as scp: pickled_signal_candles = joblib.load(scp) @@ -335,7 +346,7 @@ def test_write_read_backtest_candles(tmp_path): # test file exporting filename = tmp_path / "testresult" - store_backtest_analysis_results(filename, candle_dict, {}, {}, sample_date) + store_backtest_analysis_results(filename, data, sample_date) stored_file = tmp_path / f"testresult-{sample_date}_signals.pkl" with stored_file.open("rb") as scp: pickled_signal_candles = joblib.load(scp)