feat: Phase B fip_id liquid-breadth research tooling
Deploy / lint (push) Successful in 9s
Deploy / deploy (push) Canceled after 0s
Deploy / test (push) Canceled after 1m5s

Add research-only snapshot extender, PIT dollar-volume mask for signal IC,
rank-only harness path, fingerprint+breadth runner, and docs. Fingerprint
reproduced IC -0.045 / t -2.91 on prod.sqlite. No production gate/schedule changes.
This commit is contained in:
2026-07-18 20:22:11 +02:00
parent c2d29184dd
commit 9704e0d85a
8 changed files with 1578 additions and 73 deletions
+46
View File
@@ -1154,6 +1154,52 @@ class TestSimulatePortfolio:
assert allowed["trade_details"][0]["entry"] == pytest.approx(110.0)
def test_median_dollar_vol_63_basic():
closes = [10.0] * 70
volumes = [100.0 + i for i in range(70)]
med = bt._median_dollar_vol_63(closes, volumes, 69, lookback=63)
assert med is not None
assert med > 0
def test_liquid_breadth_week_keeps_top_n_by_dvol():
recs = [
{"val": 0.1, "fwd": 0.01, "close": 20.0, "median_dvol_63": 1e6},
{"val": 0.2, "fwd": 0.02, "close": 20.0, "median_dvol_63": 9e6},
{"val": 0.3, "fwd": 0.03, "close": 20.0, "median_dvol_63": 5e6},
{"val": 0.4, "fwd": 0.04, "close": 1.0, "median_dvol_63": 99e6}, # price floor
{"val": 0.5, "fwd": 0.05, "close": 20.0, "median_dvol_63": None},
]
pairs = bt._filter_liquid_breadth_week(recs, top_n=2, min_price=5.0)
assert len(pairs) == 2
# Highest dvol first among eligible: 9e6 then 5e6
assert pairs[0][0] == pytest.approx(0.2)
assert pairs[1][0] == pytest.approx(0.3)
def test_signal_eval_liquid_breadth_env(monkeypatch):
# top_n=5 → keep 5 names/week; spearman needs ≥3 observations.
monkeypatch.setenv("BACKTEST_LIQUID_BREADTH", "5")
monkeypatch.setenv("BACKTEST_LIQUID_MIN_PRICE", "5")
monkeypatch.setattr(bt, "MIN_CROSS_SECTION", 3)
monkeypatch.setattr(bt, "MIN_RELIABLE_PERIODS", 3)
week = {}
for w in (1, 10, 20, 30, 40, 50):
week[(2024, w)] = [
{
"val": float(i),
"fwd": float(i) * 0.01,
"close": 10.0,
"median_dvol_63": float(100 - i),
}
for i in range(12)
]
rows = bt._signal_evaluation({"toy": week})
assert rows
assert rows[0]["liquid_breadth_top_n"] == 5
assert rows[0]["avg_cross_section"] == 5.0
def test_fip_id_sign_convention_steady_climber_vs_jump():
# Steady climber: many up days, continuous path → lower (more negative) ID.
steady = [100.0]