diff --git a/quantstats/reports.py b/quantstats/reports.py index f0d8a9ad..1ce68c0b 100644 --- a/quantstats/reports.py +++ b/quantstats/reports.py @@ -1545,12 +1545,12 @@ def metrics( metrics["1Y %"] = _np.sum(df[df.index >= y1], axis=0) * pct # Multi-year annualized returns - d = today - relativedelta(months=35) + d = today - relativedelta(years=3) metrics["3Y (ann.) %"] = ( _get_stats().cagr(df[df.index >= d], 0.0, compounded, win_year) * pct ) - d = today - relativedelta(months=59) + d = today - relativedelta(years=5) metrics["5Y (ann.) %"] = ( _get_stats().cagr(df[df.index >= d], 0.0, compounded, win_year) * pct ) diff --git a/tests/test_reports.py b/tests/test_reports.py index e03bcc97..c00ae229 100644 --- a/tests/test_reports.py +++ b/tests/test_reports.py @@ -10,6 +10,7 @@ import quantstats as qs from quantstats import reports +from dateutil.relativedelta import relativedelta @pytest.fixture @@ -174,6 +175,29 @@ def test_metrics_with_rf(self, sample_returns): # Results should be different assert not result_no_rf.equals(result_with_rf) + def test_metrics_use_full_three_and_five_year_windows(self): + """Test that multi-year annualized metrics use full labeled windows.""" + dates = pd.date_range("2020-01-31", "2026-01-31", freq="ME") + returns = pd.Series(0.0, index=dates, name="Strategy") + returns.loc[pd.Timestamp("2021-01-31")] = 0.25 + returns.loc[pd.Timestamp("2023-01-31")] = 0.15 + + result = reports.metrics(returns, display=False) + + expected_3y = qs.stats.cagr( + returns[returns.index >= dates[-1] - relativedelta(years=3)], + rf=0.0, + compounded=True, + ).iloc[0] + expected_5y = qs.stats.cagr( + returns[returns.index >= dates[-1] - relativedelta(years=5)], + rf=0.0, + compounded=True, + ).iloc[0] + + assert result.loc["3Y (ann.)", "Strategy"] == pytest.approx(round(expected_3y, 2)) + assert result.loc["5Y (ann.)", "Strategy"] == pytest.approx(round(expected_5y, 2)) + class TestMatchDates: """Test date matching functionality."""