feat: grade gate-ablation variants under the hold-to-horizon exit too
The ablation judged floors under the target/stop model, but the exit sweeps point at replacing that exit with a fixed hold — under which the R:R floor's rationale (bigger payoff at the target) may not apply. Each ablation row now also carries hold_avg_r / hold_net_avg_r / hold_total_r (30d hold, initial stop only), so the Phase 3 gate decision can be read under the exit policy that would actually be used. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -221,6 +221,7 @@ def _acand(
|
||||
"outcome": OUTCOME_TARGET_HIT,
|
||||
"realized_r": rr,
|
||||
"risk_pct": 0.05,
|
||||
"time_r": {d: 0.5 for d in bt.TIME_EXIT_DAYS},
|
||||
}
|
||||
|
||||
|
||||
@@ -249,6 +250,11 @@ class TestGateAblation:
|
||||
assert rows["no_neutral_exclusion"]["total"] == 2
|
||||
assert rows["momentum_only"]["total"] == 4
|
||||
assert rows["all_floors"]["net_avg_r"] is not None
|
||||
# Every variant is also graded under the hold-to-horizon exit.
|
||||
assert rows["all_floors"]["hold_days"] == max(bt.TIME_EXIT_DAYS)
|
||||
assert rows["all_floors"]["hold_avg_r"] == pytest.approx(0.5)
|
||||
assert rows["all_floors"]["hold_net_avg_r"] is not None
|
||||
assert rows["momentum_only"]["hold_total_r"] == pytest.approx(4 * 0.5, abs=0.01)
|
||||
|
||||
def test_threshold_zero_disables_momentum_gate(self):
|
||||
# Floors only: the short and the low-momentum long both pass all_floors.
|
||||
@@ -378,9 +384,12 @@ async def test_run_backtest_smoke(session):
|
||||
assert report["params"]["cost_per_side_pct"] == pytest.approx(bt.COST_PER_SIDE * 100)
|
||||
assert "net_avg_r" in report["overall_all"]
|
||||
|
||||
# ablation baseline reproduces the qualified set exactly
|
||||
# ablation baseline reproduces the qualified set exactly, and every row
|
||||
# carries the hold-to-horizon grading alongside the target model
|
||||
ablation = {r["variant"]: r for r in report["gate_ablation"]}
|
||||
assert ablation["all_floors"]["total"] == report["overall_qualified"]["total"]
|
||||
for row in report["gate_ablation"]:
|
||||
assert "hold_net_avg_r" in row
|
||||
|
||||
# time-exit sweep covers the configured hold lengths
|
||||
assert [r["hold_days"] for r in report["time_exit_sweep"]] == list(bt.TIME_EXIT_DAYS)
|
||||
|
||||
Reference in New Issue
Block a user