feat(regime): drawdown regime leg — producer (PR 1, observe-only)#176
Merged
Conversation
…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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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) — mirrorsregime/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_daysdefaults 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_regime— the canonical most-protective composition thesubstrate.pydocstring promised but was never implemented.read_eod_pnl_navwith load-bearing graceful-degrade.scripts/backfill_regime_fast_signal.py(dedup) —_bear_stretchesnow delegates toregime.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) — optionaldrawdown_blockparam →drawdown+effective_regimepayload keys + sidecareffective_regime.None(default) ⇒ zero change for existing consumers / the macro-brief HMM path.substrate.pystays pure (block assembled by the S3-aware caller).Tests
tests/test_regime_drawdown.py— 28 cases:bear_stretcheslegacy-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_pnldegrade 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.pyadvancing the drawdown leg) and the liveeod_pnl.csvS3 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