The session-level metalabel P(our ORB profits today) — the one lever that survives out-of-sample. Backtested on 266 prod sessions (walk-forward): trade-always (trained subset): -0.111R/session, 36% hit meta_v1 GATED (trades best ~32% of days): -0.004R/session, 48% hit delta +0.107R in-sample, +0.128R OOS (recent 80 sessions), improves across folds It does NOT make the bot profitable — it takes a bleeding strategy to roughly flat by sitting out the worst ~2/3 of sessions. threshold_v1 rule gates too little to matter; meta_v1 (walk-forward GBM) is the signal. Leaky full-fit (+0.61R) >> walk-forward confirms the discipline was load-bearing; the OOS holding is the evidence the +0.078R is real, not look-ahead. Changes: - research/regime.py: batch minute-bar load per session (64k per-fire round-trips -> ~266 queries; fixed a >5min build to ~3min) + incremental label pass (skip already-labeled sessions; --rebuild forces full). Nightly cost now ~one new day. - docker-compose.yml + truenas-compose.yml: scheduler runs build-features + score (both models) before `experiments run`, nightly. ALL-SHADOW — does NOT gate live trading (that stays owner-gated Step 5). - admin_api.py + admin.html: POST /api/regime/run (detached) + GET /api/regime/status + a Run/Status button — the panel had no way to trigger this. - plans/011 + docs/research/regime_notes.md (6-book distillation) + plans 008/009 docs. Prod state (shadow, rollback = DROP regime_features/regime_scores + DELETE experiments WHERE id LIKE 'regime%'): 266 feature rows, 532 scores, 2 experiments registered. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
6.8 KiB
Regime-detection research notes — distilled for the momentum bot
Date: 2026-07-15
Method: 6 books in books/market_regime_state_detection/ distilled by parallel readers (Ang & Timmermann NBER survey; Kritzman Regime Shifts; Zucchini/MacDonald/Langrock HMM for Time Series; Chan Hands-On AI Trading & Quantitative Trading; Kakkar et al Trading Decoded). Hamilton 1989 is a scanned image (no extractable text); its Markov-switching method is covered by the others.
Problem this feeds: the bot is ~breakeven with no entry edge after honest fills; the one thing untried is regime awareness — it did well 07-08/09 (a runner regime) and sits out / bleeds otherwise. Goal: a FREE-data daily regime signal that gates/sizes ORB entries, harness-backtestable over ~260 sessions.
The one insight that reframes everything (Chan's metalabeling)
"The key to successfully apply AI/ML to finance is to focus on metalabeling — finding the probability of profit of your own simple trading strategy, and not to use it to predict the market directly. Your own strategy's past track record is private; no one else is trying to predict it." — Chan, Quantitative Trading
Don't detect abstract "market regime." Predict P(our ORB makes money today) from free pre-open features, using our OWN per-session expR (which the plan-006 harness already computes) as the label. This targets exactly what matters (does our edge work today), sidesteps the "high-vol lumps runner-days with crash-days" problem, reuses the harness, is free, and is a private signal nobody arbs away. Every practical book (Chan CPO, Trading Decoded RF) converges here; the academic survey (Ang-Timmermann) calls the same thing "regime-conditioned position sizing."
The method stack (what to build, in escalation order — ponytail)
- Threshold baseline first (Kritzman, Trading Decoded both insist): a trivial rule — e.g.
SPY 5d momentum > 0 AND SPY 20d vol < median, or Kritzman Financial Turbulence (sqrt((r−μ)Σ⁻¹(r−μ)')on ~11 sector-ETF returns) below its 75th percentile. If the fancy model can't beat this net-of-costs out-of-sample, ship the rule. - Metalabel classifier (the primary):
GradientBoostingClassifier/RandomForest(free sklearn — the books'predictnow.ai/gbdtreplaced) predictingP(profitable ORB session)from ~5–8 free features. Gate/size on the probability. - HMM regime as a FEATURE (not the whole model): a 2-state Markov-switching state on SPY (
statsmodels MarkovRegression(spy_returns, k_regimes=2, switching_variance=True)) or on the turbulence series — one column feeding the classifier, or a standalone gate to compare.
Free features (all pre-open, all we have or can ingest free)
| Feature | Source | Note |
|---|---|---|
| SPY 5d/20d momentum + 20d realized vol (VIX proxy) | already ingesting SPY (plan 009) | the level-1 input every book uses |
| IWM (small-cap index) + sector-ETF momentum | Alpaca/yfinance, free | small-caps specifically; sector rotation |
| Kritzman turbulence (Mahalanobis on ~11 sector ETFs) | sector-ETF daily returns, free | "prices behaving uncharacteristically" |
| Breadth = % of the gapper universe green / held-VWAP yesterday | our own stored data | the SIGNED feature that breaks vol-symmetry |
| Bot's own trailing-N-day realized expR + hit-rate | our harness | the most on-target feature — a hot/cold-streak detector on our OWN edge |
| VIX level + 1d change | CBOE/yfinance, free | the vol axis directly |
Keep to ≤5–8 features — only ~260 sessions, ~a third fewer "runner days." More features = curve-fit.
The load-bearing discipline (or the whole thing is a lie)
- Filtered / walk-forward / purged only. Only a regime label computed from data ≤ today is tradeable. Smoothed HMM probs and full-sample fits peek at the future. Sanity check every book demanded: if a smoothed-gated backtest crushes the filtered-gated one, your edge is look-ahead. Use purged/embargoed walk-forward CV (drop the boundary day) — the same leakage-safe split used in
plans/008. - Label is same-day-outcome, features are strictly pre-open. The session's expR (label) uses open-knowable exits; every feature is lagged to the prior close.
- Out-of-sample split is mandatory. Fit on the older half, apply to the recent half; confirm the favorable-regime expR advantage survives. "In-sample regimes need not persist out-of-sample" (Ang-Timmermann) — if the edge evaporates OOS, the regimes were in-sample noise.
- Acceptance = NET expR improves across EVERY walk-forward fold, not AUC. A 52.8% classifier can still be net-negative (Chan Hands-On's own OOS accuracy was 52.77%).
- Let the DATA pick the sign. Ang-Timmermann finds low-vol = high-Sharpe for a long-index investor — but a long-dispersion small-cap momentum strategy likely inverts this (runners need volatility). Measure conditional expR per regime; never assume high-vol = bad.
- Small-sample humility. 2 states (don't LR-test the count), shallow trees (
max_depth ≤ 3), report bootstrap/posterior bands on the regime probs, deflate any OOS Sharpe by the number of tweaks tried (Deflated Sharpe Ratio). - Regimes lag. A daily gate enters the runner regime a day or two late and exits late — structural. It sits out some good days and takes some bad ones. The bar is net improvement, not perfection.
Honest prior
This is the most promising lever of the session — it targets the bot's own edge, uses free data, reuses the harness, and directly explains the 07-08/09-vs-today swing. But 260 sessions is a small sample, so the real risk is curve-fitting a regime that doesn't persist. The threshold-baseline-first rule, purged walk-forward, and OOS split are the guards. If, after all that, the gated expR doesn't clearly beat trade-always out-of-sample → the honest finding is "no exploitable regime signal in free data at this sample size," and we've learned it cheaply.
Sources (in books/market_regime_state_detection/)
- Ang & Timmermann (2011), Regime Changes and Financial Markets, NBER WP 17182 — the survey + the sizing template + every caveat.
- Kritzman et al, Regime Shifts: Implications for Dynamic Strategies — Financial Turbulence + absorption ratio.
- Zucchini, MacDonald, Langrock, Hidden Markov Models for Time Series — the estimation recipe (forward-filter, BIC state selection, why filtered ≠ smoothed).
- Chan et al, Hands-On AI Trading — the exact
statsmodels MarkovRegressiondaily-gate recipe (Example 4) + the 4-year-lookback calibration. - Chan, Quantitative Trading — Conditional Parameter Optimization + the metalabeling principle.
- Kakkar, Sahni, Shanmugamani, Trading Decoded — the RandomForest regime-as-feature recipe + purged walk-forward CV + the "beat the trivial rule or ship the rule" discipline.