Split 2016-01-01, costs 10bps one-way (decimal 0.001), sqrt(252), monthly hold 21, next-open fills, lag>=1 throughout. Look-ahead guards PASS (D9 rotation, D9 baseline).
D9 -- macro country/regime rotation (FRED only, NOT price momentum)
Universe: ['SPY', 'EFA', 'EEM', 'TLT', 'SHY'] from data/parquet (per-name source: {'SPY': '_ADJ', 'EFA': '_D(Yahoo)', 'EEM': '_D(Yahoo)', 'TLT': '_D(Yahoo)', 'SHY': '_D(Yahoo)'}; _ADJ listing check for ['SPY', 'EFA', 'EEM', 'TLT', 'SHY']: only SPY has _ADJ -- EFA/EEM/TLT/SHY use _D Yahoo daily adj_close; ETF proxies so survivorship bias is nil). Eval 2005-01-13..2026-08-27 after 260d z-warmup.
Composite z = z(spread inverted) + z(curve) + z(payroll), trailing z(252): spread src BAA10Y-AAA10Y, curve src T10Y2Y, payroll src PAYEMS 3m% (vintage-21d) (3 parts). Monthly payroll vintage-lagged 21 trading days (never trades on an unreleased print); composite additionally shift(1). Rule: composite>0 -> risk-on (equal ['SPY', 'EFA', 'EEM']), else defensive (equal ['TLT', 'SHY']).
Baseline = price-trend dual (close>SMA200 & ROC60>0) inverse-vol(60d) on the SAME universe/hold/costs (production/etf_trend_runner.py compute_targets logic); cash when no name active.
| Variant | IS Ret | IS Sharpe | IS MaxDD | OOS Ret | OOS Sharpe | OOS MaxDD | Turn/yr |
|---|---|---|---|---|---|---|---|
| D9 macro rotation | +56.65% | 0.35 | -21.11% | +80.94% | 0.46 | -33.32% | 4.37 |
| Price-trend baseline | +29.11% | 0.43 | -20.20% | +52.64% | 0.57 | -11.12% | 5.69 |
| EqMom L126/H21 top50 | +232.45% | 0.62 | -55.43% | +942.19% | 1.06 | -38.77% | 8.57 |
D9 audit
| Metric | Value |
|---|---|
| D9-base OOS bootstrap p | 0.2756 |
| D9 corrEqMom (OOS) | 0.60 |
| D9 corrMkt SPY (OOS) | 0.62 |
| Baseline corrEqMom (OOS) | 0.49 |
| OOS Sharpe D9 / baseline / EqMom | 0.46 / 0.57 / 1.06 |
D9 verdict: REJECT -- macro composite does not beat the price-trend baseline OOS (or costs more to run); no macro sleeve.
D10 -- FINRA short-interest feasibility + pilot
Source: http(repo) (Rule 4560, 2x/month settlements; published 7th business day after settlement -> join positions on availableDate = settlement+7BD, PIT-safe). Pre-2021-06 files are OTC-only (different host) -- pilot history starts 2021-06. CDN needs a browser UA (403 otherwise). 2026 settlement count: 24 (mid-month + month-end).
Cache: {'snapshots': 122, 'first': '2021-06-15 00:00:00', 'last': '2026-08-14 00:00:00', 'symbols_median': 20222, 'symbols_min': 19204, 'rows': 2480131} (gate: >=24 snapshots, >=500 median symbols). Probe: latest snapshot 2026-08-14: 22481 symbols, 498/501 (99.4%) of _ADJ universe covered; daysToCover floor 1.00 / cap 999.99 per FINRA file; avgDailyVol<=0 frac 14.7%; avail-settle = [11] calendar days (= 7 BDays, FINRA publishes 7th biz day after).
| Pilot | OOS Ret | OOS Sharpe | OOS MaxDD | p vs EqMom |
|---|---|---|---|---|
| EqMom ex-crowded | +920.41% | 1.04 | -38.77% | 0.5914 |
| EqMom + capped short | +852.89% | 1.06 | -38.77% | 0.8986 |
D10 verdict: REJECT both pilots (2026-09-09 rerun, n=122 snapshots).
Exclusion (1.04, p=0.59) and capped-short (1.06, same DD, borrow fees
unmodelled so optimistic) add nothing over EqMom (1.06). The FINRA loader
(scripts/fetch_finra_short.py) and PIT join stay as infrastructure; do not
build a short-interest sleeve without a new mechanism hypothesis.
ALL DONE