You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
fithia2/tests/unit/test_ensemble_overlay_backt...

45 lines
1.7 KiB
Python

from __future__ import annotations
import importlib.util
from pathlib import Path
import sys
import pandas as pd
_SCRIPT_PATH = Path(__file__).resolve().parents[2] / "scripts" / "ensemble_overlay_backtest.py"
_SPEC = importlib.util.spec_from_file_location("ensemble_overlay_backtest", _SCRIPT_PATH)
assert _SPEC and _SPEC.loader
_MODULE = importlib.util.module_from_spec(_SPEC)
sys.modules[_SPEC.name] = _MODULE
_SPEC.loader.exec_module(_MODULE)
build_ensemble_returns = _MODULE.build_ensemble_returns
summarize_ensemble = _MODULE.summarize_ensemble
def test_build_ensemble_returns_uses_lagged_rolling_sharpe() -> None:
dates = pd.date_range("2024-01-01", periods=6, freq="B")
returns = pd.DataFrame(
{
"date": dates,
"a": [0.0, 0.01, 0.015, 0.02, -0.02, -0.02],
"b": [0.0, -0.01, -0.015, -0.02, 0.02, 0.02],
}
)
ensemble, weights = build_ensemble_returns(returns, window=3)
# Before enough history, fallback is equal weight.
assert weights.loc[0, "a"] == 0.5
assert weights.loc[1, "b"] == 0.5
# Once trailing Sharpe is available, positive trailing performer gets all the weight.
assert weights.loc[4, "a"] == 1.0
assert weights.loc[4, "b"] == 0.0
assert ensemble.loc[4, "ensemble_return"] == returns.loc[4, "a"]
def test_summarize_ensemble_reports_yearly_returns() -> None:
dates = pd.to_datetime(["2024-12-30", "2024-12-31", "2025-01-02"])
ensemble = pd.DataFrame({"date": dates, "ensemble_return": [0.0, 0.01, 0.02]})
summary = summarize_ensemble(ensemble, initial_equity=100.0)
assert round(summary["total_return_pct"], 4) == 3.02
assert "2024" in summary["yearly_returns_pct"]
assert "2025" in summary["yearly_returns_pct"]