From 3d72709b7a183f4676b3adbd338cfe2954c47932 Mon Sep 17 00:00:00 2001 From: Brad Smith Date: Thu, 11 Jun 2026 12:02:36 -0500 Subject: [PATCH] test(backtesting): correct wrong oracles in performance metric tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three tests asserted incorrect expected values and passed/failed for the wrong reasons: - test_win_rate_calculation: pnl [100,-50,200,150,-75,300,-25,180,-100,250] is 6 wins / 4 losses = 0.6, but the comment said "7 wins" and it asserted 0.7. Corrected to 0.6. - test_sharpe_ratio_calculation: used a constant return series (zero std), which the calculator maps to Sharpe 0 — so `sharpe_ratio > 10` could never hold. Give the series small, deterministic volatility so it genuinely exercises the high-Sharpe case, and replace the nonsensical `annualized_return > 10` (>1000%) with `> 0.10`. - test_annualization: 252 freq='D' rows span only 251 calendar days, so a 20% total return correctly annualizes to ~30%, not the asserted 20%. Use a full calendar year of dates so 20% total annualizes to ~20%. All seven tests in the file now pass and assert correct values. Closes #14 Co-Authored-By: Claude Opus 4.8 --- tests/backtesting/test_performance.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/tests/backtesting/test_performance.py b/tests/backtesting/test_performance.py index fd108f7..f7e0855 100644 --- a/tests/backtesting/test_performance.py +++ b/tests/backtesting/test_performance.py @@ -58,7 +58,11 @@ def test_sharpe_ratio_calculation(self): """Test Sharpe ratio calculation with risk-free rate""" # Create known equity curve for predictable Sharpe ratio dates = pd.date_range('2023-01-01', periods=252, freq='D') - returns = np.full(252, 0.001) # 1% daily return + # Strong positive mean with small, non-zero volatility -> high Sharpe. + # A constant series has zero std, which the calculator treats as an + # undefined Sharpe of 0, so it cannot exercise the "high Sharpe" case. + returns = np.full(252, 0.001) + returns[1::2] = 0.0008 equity_values = 100000 * np.cumprod(1 + returns) equity_curve = pd.DataFrame({ @@ -68,9 +72,10 @@ def test_sharpe_ratio_calculation(self): metrics = self.calculator.calculate_all_metrics(equity_curve, pd.DataFrame()) - # With consistent 1% daily returns and no volatility, Sharpe should be very high + # Consistent low-volatility positive returns -> high Sharpe and a + # solidly positive annualized return (the old `> 10` asserted >1000%). assert metrics['sharpe_ratio'] > 10, "Sharpe ratio should be high for consistent returns" - assert metrics['annualized_return'] > 10, "Annualized return should be very high" + assert metrics['annualized_return'] > 0.10, "Annualized return should be solidly positive" def test_max_drawdown_calculation(self): """Test maximum drawdown calculation""" @@ -95,13 +100,13 @@ def test_win_rate_calculation(self): # Create trade history with known win rate trade_history = pd.DataFrame({ 'datetime': pd.date_range('2023-01-01', periods=10, freq='D'), - 'pnl': [100, -50, 200, 150, -75, 300, -25, 180, -100, 250] # 7 wins, 3 losses + 'pnl': [100, -50, 200, 150, -75, 300, -25, 180, -100, 250] # 6 wins, 4 losses }) metrics = self.calculator.calculate_all_metrics(pd.DataFrame(), trade_history) - # Win rate should be 70% (7 out of 10 trades) - expected_win_rate = 0.7 + # Win rate should be 60% (6 of the 10 trades have positive PnL) + expected_win_rate = 0.6 assert abs(metrics['win_rate'] - expected_win_rate) < 0.001 def test_profit_factor_calculation(self): @@ -140,12 +145,16 @@ def test_edge_cases(self): def test_annualization(self): """Test proper annualization using 252 trading days""" # One year of daily data - dates = pd.date_range('2023-01-01', periods=252, freq='D') - # 20% total return over the year + # A full calendar year of daily points: a 20% total return annualizes + # to ~20%. The calculator annualizes by elapsed calendar time when a + # datetime column is present, so the span must be ~one year. (The + # previous 252 freq='D' rows spanned only 251 days, so 20% annualized + # to ~30%.) + dates = pd.date_range('2023-01-01', '2023-12-31', freq='D') final_value = 120000 equity_curve = pd.DataFrame({ 'datetime': dates, - 'total': np.linspace(100000, final_value, 252) + 'total': np.linspace(100000, final_value, len(dates)) }) metrics = self.calculator.calculate_all_metrics(equity_curve, pd.DataFrame())