What (One-liner)
A per-ticker conditional-volatility read on one honest daily axis — the GARCH(1,1) σ path with persistence and shock half-life, a RiskMetrics EWMA twin on the same seed, and a declared rule-based volatility state (rising / high / low / normal).
How to use
Set the ticker (or wire a price_factor upstream — per-symbol semantics) and run. Read the conditional-vol headline with the vol-state badge, then the GARCH σ series chart for the path (the EWMA twin is in the CSV). Persistence (α+β) and the shock half-life tell you how long a volatility shock lingers; long-run vol is where σ mean-reverts to. Wire it upstream of risk_management (vol scaling), casa_strategy, or meta_strategy. ⬇ CSV exports the full daily axis: GARCH, EWMA, percentile, state.
Core formula
GARCH: σ²_t = ω + α·ε²_{t-1} + β·σ²_{t-1}; Gaussian QMLE (hand-rolled NM vs SLSQP golden)
persistence = α+β; half-life = ln0.5/ln(α+β); long-run var = ω/(1−α−β)
EWMA: σ²_t = λ·σ²_{t-1} + (1−λ)·ε²_{t-1}; λ = 0.94 (RiskMetrics daily benchmark)
State: motion first — σ up ≥10% vs 21d ago → rising;
else expanding percentile ≥75 high / ≤25 low / else normalAssumptions & applicability
Assumptions: Gaussian QMLE (consistent, not efficient, under fat tails); close-to-close percent returns; shared sample-variance seed; a declared deterministic state rule; persistence capped at 0.999 with honest None beyond it.
Applicable: any liquid ticker with ≥250 daily closes; conditional-vol level, persistence and state reading.
Not applicable: hidden-state regime estimation (use markov_regime_v1 and compare), implied vol / surfaces, vol-targeting P&L, intraday estimators.
Input / Output contract
Inputs: symbol (default SPY), lookback_days (default 756, min 250), ewma_lambda (default 0.94).
Output: metrics (garch_vol_ann, ewma_vol_ann, long_run_vol_ann, alpha, beta, omega, persistence, half_life_days, regime, vol_percentile, converged, n_days) + one axis namespace series (dates, garch_vol_ann, ewma_vol_ann, vol_percentile, regime — all equal length on the return axis), plus a provenance block declaring the returns scaling, seed convention, estimator, the exact state rule and the annualization.
Known limitations
- The state label is a transparent declared rule — it will disagree with a hidden-state model at transitions, by design; compare against
markov_regime_v1rather than treating either as ground truth. - Parameters are reported to optimizer precision on a likelihood that is flat along ω; the golden's LL-dominance gate — not parameter closeness — is the quality bar.
- Close-to-close only: overnight gaps and intraday range are invisible until the family-B2 range estimators exist.
- A missing or short price history degrades honestly (
status: unavailable+ reason) — the card never fabricates a σ.

