Skip to content

feat(regime): drawdown regime leg — producer (PR 1, observe-only)#176

Merged
cipher813 merged 1 commit into
mainfrom
feat/drawdown-regime-leg
May 19, 2026
Merged

feat(regime): drawdown regime leg — producer (PR 1, observe-only)#176
cipher813 merged 1 commit into
mainfrom
feat/drawdown-regime-leg

Conversation

@cipher813
Copy link
Copy Markdown
Owner

What

PR 1 of the drawdown-regime-model arc (3rd leg of the regime ensemble). Producer-only, observe-only — no behavior change.

Plan: alpha-engine-docs/private/regime-drawdown-hysteresis-260518.md (local). ROADMAP: alpha-engine-config PR #230 (P1).

Changes

  • regime/drawdown.py (new, pure-logic) — mirrors regime/fast_signal.py. Tiered SPY drawdown (risk_on/caution/risk_off) + book-vs-market excess (risk_on/alpha_bleed), pure-level asymmetric hysteresis (the enter/exit band is the sole debounce; min_persist_days defaults to 1 — raising it re-opens F1 calibration per the single-source-of-truth invariant, plan §3). step() mirrors fast_signal's idempotency + cold-start contract. most_protective + compose_effective_regimethe canonical most-protective composition the substrate.py docstring promised but was never implemented. read_eod_pnl_nav with load-bearing graceful-degrade.
  • scripts/backfill_regime_fast_signal.py (dedup)_bear_stretches now delegates to regime.drawdown.bear_stretches. The L95 / F1-F2 eval reference and the production leg are now the same code (was a script-local copy). Semantics-preserving — legacy-parity asserted in tests — so the existing F1 calibration stays valid.
  • regime/substrate.py (additive, S3-contract-safe) — optional drawdown_block param → drawdown + effective_regime payload keys + sidecar effective_regime. None (default) ⇒ zero change for existing consumers / the macro-brief HMM path. substrate.py stays pure (block assembled by the S3-aware caller).

Tests

tests/test_regime_drawdown.py — 28 cases: bear_stretches legacy-parity (5 seeds), tiered hysteresis truth table (enter/exit asymmetry, one-rung de-escalation, band-holds, persistence>1), excess leg + NAV graceful-degrade, step idempotency/cold-start, ser/de + schema-mismatch, composition truth table, eod_pnl degrade matrix, additive-substrate-hook regression (None ⇒ no keys; present ⇒ block + sidecar mirror).

287 regime-suite tests pass (-k "regime or substrate or drawdown or backfill"), zero failures. Pre-existing sklearn matmul RuntimeWarnings only, unrelated.

Scoping note (deliberate)

This PR is the producer. The daily-stage extension (inference/stages/regime_fast_signal.py advancing the drawdown leg) and the live eod_pnl.csv S3 fetch are deferred to the consumer PRs — they are pure I/O glue with no logic, and splitting keeps this a clean, fully-tested, behavior-neutral reviewable unit (consistent with the plan's "producer first, all consumers gated default-off" sequencing). Nothing reads the new keys yet.

🤖 Generated with Claude Code

…ditive substrate hook (PR 1, producer, observe-only)

Leg 3 of the regime ensemble (HMM + BOCPD + deterministic drawdown).
Plan: alpha-engine-docs/private/regime-drawdown-hysteresis-260518.md;
tracked in alpha-engine-config ROADMAP PR #230 (P1).

- regime/drawdown.py: pure-logic module mirroring regime/fast_signal.py.
  Tiered SPY drawdown (risk_on/caution/risk_off) + book-vs-market excess
  (risk_on/alpha_bleed), pure-level asymmetric hysteresis (band is the
  sole debounce; min_persist_days defaults to 1; raising it re-opens F1
  calibration per the single-source-of-truth invariant). step() mirrors
  fast_signal idempotency/cold-start. most_protective + compose_effective_regime
  is the canonical composition the substrate.py docstring promised but
  was never implemented. eod_pnl NAV reader with load-bearing
  graceful-degrade.
- scripts/backfill_regime_fast_signal.py: _bear_stretches now delegates
  to regime.drawdown.bear_stretches — one drawdown reference, not two;
  the L95/F1-F2 eval reference and the production leg are the SAME code.
  Semantics-preserving (parity asserted in tests) so F1 calibration
  stays valid.
- regime/substrate.py: optional additive drawdown_block param adds the
  drawdown + effective_regime payload keys + sidecar effective_regime.
  None (default) gives zero change for existing consumers
  (S3-contract-safe, ADD-only). substrate.py stays pure (block
  assembled by the caller).
- tests/test_regime_drawdown.py: 28 cases — bear_stretches legacy
  parity, tiered hysteresis truth table, excess + NAV graceful-degrade,
  step idempotency/cold-start, ser/de, composition truth table,
  eod_pnl degrade matrix, additive-substrate-hook regression.

Observe-only: NO consumer reads the new keys; daily-stage wiring +
eod_pnl S3 fetch are deferred to the consumer PRs (pure I/O glue, keeps
this a clean reviewable producer). 287 regime-suite tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant