From b3b21e6b931ec3ea81640e5def9ef1cd7653f688 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 25 Apr 2025 08:28:19 +0200 Subject: [PATCH] fix: market_change deviation between backtesting and hyperopt closes #11672 --- freqtrade/data/metrics.py | 18 +++++++++++++++--- .../optimize_reports/optimize_reports.py | 2 +- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/freqtrade/data/metrics.py b/freqtrade/data/metrics.py index 8e234df85..6a1ad2766 100644 --- a/freqtrade/data/metrics.py +++ b/freqtrade/data/metrics.py @@ -10,7 +10,9 @@ import pandas as pd logger = logging.getLogger(__name__) -def calculate_market_change(data: dict[str, pd.DataFrame], column: str = "close") -> float: +def calculate_market_change( + data: dict[str, pd.DataFrame], column: str = "close", min_date: datetime | None = None +) -> float: """ Calculate market change based on "column". Calculation is done by taking the first non-null and the last non-null element of each column @@ -19,14 +21,24 @@ def calculate_market_change(data: dict[str, pd.DataFrame], column: str = "close" :param data: Dict of Dataframes, dict key should be pair. :param column: Column in the original dataframes to use + :param min_date: Minimum date to consider for calculations. Market change should only be + calculated for data actually backtested, excluding startup periods. :return: """ tmp_means = [] for pair, df in data.items(): - start = df[column].dropna().iloc[0] - end = df[column].dropna().iloc[-1] + df1 = df + if min_date is not None: + df1 = df1[df1["date"] >= min_date] + if df1.empty: + logger.warning(f"Pair {pair} has no data after {min_date}.") + continue + start = df1[column].dropna().iloc[0] + end = df1[column].dropna().iloc[-1] tmp_means.append((end - start) / start) + if not tmp_means: + return 0.0 return float(np.mean(tmp_means)) diff --git a/freqtrade/optimize/optimize_reports/optimize_reports.py b/freqtrade/optimize/optimize_reports/optimize_reports.py index 560e91476..1478ee2be 100644 --- a/freqtrade/optimize/optimize_reports/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports/optimize_reports.py @@ -649,7 +649,7 @@ def generate_backtest_stats( :return: Dictionary containing results per strategy and a strategy summary. """ result: BacktestResultType = get_BacktestResultType_default() - market_change = calculate_market_change(btdata, "close") + market_change = calculate_market_change(btdata, "close", min_date=min_date) metadata = {} pairlist = list(btdata.keys()) for strategy, content in all_results.items():