Change Point Detection
Bayesian online detection for regime shifts and structural breaks
Markets change regimes: a 50/50 prediction market jumps to 70/30 after a news event, a low-vol equity enters a crash, a spread relationship breaks down. BocpdDetector implements the Adams-MacKay Bayesian Online Change Point Detection algorithm, giving you real-time probability that a regime shift just occurred.
API
detector = hz.BocpdDetector(
hazard_rate=250.0, # expected run length between changes
mu0=0.0, # prior mean
kappa0=1.0, # prior precision scaling
alpha0=1.0, # prior shape (inverse-gamma)
beta0=1.0, # prior rate (inverse-gamma)
)
change_prob = detector.update(observation)
# change_prob: float in [0, 1] -- probability a change point just occurred
Parameters
| Parameter | Meaning | Typical values |
|---|---|---|
hazard_rate | Expected observations between change points | 100-500 for daily data |
mu0 | Prior mean of the observation distribution | 0.0 for returns, 0.5 for prediction market prices |
kappa0 | Strength of belief in prior mean | 1.0 (weak prior) |
alpha0 | Shape parameter for variance prior | 1.0 |
beta0 | Rate parameter for variance prior | 1.0 |
Complexity
O(T) per observation where T is the number of observations since the last reset. The algorithm maintains a run-length distribution that grows with each observation. For long-running applications, call detector.reset() periodically (e.g., daily) to bound memory usage.
Detecting regime shifts in prediction markets
detector = hz.BocpdDetector(
hazard_rate=100.0,
mu0=0.50, # prior: 50/50 market
kappa0=0.1, # weak prior
alpha0=1.0,
beta0=0.01,
)
for tick in market_ticks:
cp = detector.update(tick.price)
if cp > 0.5:
print(f"Regime shift detected at {tick.timestamp}, prob={cp:.2f}")
# Adapt: widen spreads, reduce position, or re-estimate fair value
Adaptive lookback windows
When a structural break occurs, historical data from before the break is misleading. Use change point detection to reset your feature windows:
detector = hz.BocpdDetector(hazard_rate=200.0, mu0=0.0, kappa0=1.0, alpha0=1.0, beta0=1.0)
lookback_start = 0
for i, ret in enumerate(returns):
cp = detector.update(ret)
if cp > 0.6:
lookback_start = i # discard pre-break data
detector.reset()
effective_window = returns[lookback_start:i+1]
# Use effective_window for feature computation
When to use
- Event-driven markets: prediction markets where a debate, earnings call, or ruling can instantly shift the probability.
- Vol regime detection: detect transitions between low-vol and high-vol regimes to adjust position sizing.
- Spread monitoring: detect when a pairs-trading spread relationship has broken down and the model needs recalibration.
- Adaptive features: automatically shorten lookback windows after structural breaks so your signals respond to the new regime.