Software companion

Change-Point Detector Comparison on SPX Realized Volatility

Overview

Four detectors with very different parameterizations are compared, so the package is arranged so that nothing about the comparison lives inside a detector. Each implements the same detectors/base.py interface and returns alarm dates; the realized-volatility input, the true-event set, the matching window, the latency definition and the false-alarm accounting are shared code applied identically to all four.

The second constraint is downstream. Three other studies consume this one’s alarms, so the export is a contract rather than a by-product: changepoints.csv is a point-event table keyed by ISO date with false-alarm flags preserved, and primary_regime_breaks.csv names the one recommended run for consumers that want a single canonical set. Consumers join on the date or widen the window themselves; they never parse detector-specific output.

Implementation

Core libraries
hmmlearn, ruptures, NumPy, pandas, SciPy, yfinance, pandas-datareader, Jinja2
Install
An installable package, rsk-04-changepoint, exposing a console script of the same name
Configuration
Two YAML files — configs/default.yaml for live sources, configs/fixtures_smoke.yaml for an offline run
Protocol settings
Sample from 2010-01-01, seed 1729, a 10-day matching window, a one-per-year false-alarm target, a 0.25 held-out fraction, and a 64-sample block bootstrap at block length 10
Ablation grids
Seven CUSUM thresholds crossed with three drift values, and eight PELT penalties
Tests
9 modules, including one per detector and a pipeline smoke test

Components

detectors/base.py
The shared detector interface every method is measured through
detectors/hmm.py
Two-state Gaussian hidden Markov regime labelling
detectors/cusum.py
CUSUM with the bootstrap-calibrated threshold and drift grid
detectors/pelt.py
Exact penalized segmentation via ruptures
detectors/baseline.py
The fixed z-score threshold any method has to beat to be worth its complexity
realized_vol.py
Realized volatility from 5-minute bars, with a daily squared-return fallback that is flagged rather than silent
data_sources.py
Price, VIX and NBER acquisition plus the vintage record
evaluation.py
Event matching, detection latency, and false alarms per year
ablation.py
The detector sensitivity grid
schemas.py
Column contracts checked before any artifact is written
report.py, plotting.py
The methods note, the one-page summary, and the figures

Stages

  1. download-data Acquire prices, intraday bars, VIX and NBER recession dates, recording the vintage.
  2. build-rv Build the canonical log realized-volatility series and flag every fallback day.
  3. run-detectors Run all four detectors over the same input.
  4. evaluate Match alarms to events, compute latency and false-alarm rates, and write the comparison table.
  5. run-ablation Sweep the CUSUM and PELT grids to separate method from tuning.
  6. build-report Render the methods note, the forwardable summary, and the downstream exports.

Reproducibility and validation

  • Coverage of free 5-minute index data is uneven across the sample, so the pipeline records every day on which it fell back to daily squared returns instead of quietly substituting one estimator for another.
  • Recession dating is revision-sensitive; the report will not build without data_vintage.json, and the vintage is surfaced in the appendix.
  • The headline template reports latency and false alarms per year together, and does not assert that PELT detects earlier unless the computed metrics support it.
  • run_manifest.json records the effective configuration, dependency versions, and checksums for every artifact the report cites.
  • A fixtures configuration runs the whole pipeline offline, so the code path can be tested without network access or vendor availability.

Availability

Not publicly released. Every input comes from a free source, so the constraint here is maintenance rather than licensing: the exports are consumed by three other studies, and publishing the package would freeze a join contract that is still in internal use.

Companion research

Three named detectors scored against a fixed-threshold baseline under a matching rule fixed before any metric was computed. The baseline wins on both axes.

Read the research report