82 lines
2.2 KiB
Python
82 lines
2.2 KiB
Python
from __future__ import annotations
|
|
|
|
import zipfile
|
|
|
|
from scripts import run_fundamentals_research as runner
|
|
|
|
|
|
def _window(name, sharpe, drawdown):
|
|
return {
|
|
"window": name,
|
|
"sharpe": sharpe,
|
|
"sharpe_se": 0.2,
|
|
"dsr": 0.8,
|
|
"cagr_pct": 10.0,
|
|
"max_drawdown_pct": drawdown,
|
|
"calmar": 1.0,
|
|
"trades": 20,
|
|
}
|
|
|
|
|
|
def test_arm_matrix_is_bounded_and_pre_registered():
|
|
assert runner.N_TRIALS == 13
|
|
assert runner.ARMS[0]["id"] == "control_w00"
|
|
assert {arm["weight"] for arm in runner.ARMS[1:]} == {0.1, 0.2, 0.3, 0.4}
|
|
assert {arm["composite"] for arm in runner.ARMS[1:]} == {
|
|
"quality",
|
|
"growth",
|
|
"balanced",
|
|
}
|
|
|
|
|
|
def test_development_grade_does_not_read_test_window():
|
|
control = {
|
|
"windows": [
|
|
_window("train", 1.0, 10.0),
|
|
_window("validation", 1.0, 10.0),
|
|
_window("test", 9.0, 1.0),
|
|
]
|
|
}
|
|
arm = {
|
|
"windows": [
|
|
_window("train", 1.1, 10.0),
|
|
_window("validation", 1.2, 11.0),
|
|
_window("test", -9.0, 90.0),
|
|
]
|
|
}
|
|
assert runner._development_grade(control, arm)["pass"] is True
|
|
|
|
|
|
def test_output_bundle_is_self_contained(tmp_path):
|
|
report = {
|
|
"generated_at": "2026-07-23T00:00:00Z",
|
|
"splits": {"train_end": "2024-01-01", "test_start": "2025-01-01"},
|
|
"n_trials": 13,
|
|
"warnings": ["survivorship bias"],
|
|
"factor_ic": {"full": []},
|
|
"arms": [],
|
|
"development_selection": None,
|
|
"final_check": None,
|
|
}
|
|
output = tmp_path / "result.json"
|
|
runner._write_outputs(report, output, bundle=True)
|
|
with zipfile.ZipFile(output.with_suffix(".zip")) as archive:
|
|
names = set(archive.namelist())
|
|
assert {
|
|
"result.json",
|
|
"result.md",
|
|
"result-arms.csv",
|
|
"result-factor-ic.csv",
|
|
"result-trades.csv",
|
|
} <= names
|
|
|
|
|
|
def test_winner_concentration_exposes_top_five_dependence():
|
|
details = [
|
|
{"pnl": value, "r": value / 10} for value in (100, 90, 80, 70, 60, -10, -20)
|
|
]
|
|
result = runner._winner_concentration(details)
|
|
assert result["top5_pnl"] == 400
|
|
assert result["net_pnl_ex_top5"] == -30
|
|
assert result["avg_r_ex_top5"] == -1.5
|