Methodology

Exactly how the regime label for a given symbol is computed. If anything on this page becomes wrong, it's a bug — tell us.

The pipeline

For each (symbol, timeframe):

  1. Fetch N=320 most-recent OHLC bars from Binance (fallback Coinbase/Bybit for cross-exchange consensus).
  2. Compute log returns: rt = ln(closet / closet-1).
  3. Rolling realized volatility on the last 30 bars: RVt = stdev(rt-29..t) × √(bars_per_year). Bars-per-year at the bar interval — annualized for comparability across timeframes.
  4. Rolling baseline: μt and σt over the last 240 values of RV.
  5. z-score: zt = (RVt − μt) / σt.
  6. FSM state transitions gated by thresholds + hysteresis (see below).

The FSM

Three states — low, normal, high. Starts in normal. Transitions require enter_k consecutive observations past the threshold; exits require exit_k observations back inside. Hysteresis prevents single-bar wicks from flipping the state.

normal → high   when z ≥ high_enter for enter_k bars
normal → low    when z ≤ low_enter  for enter_k bars
high   → normal when z ≤ high_exit  for exit_k  bars
low    → normal when z ≥ low_exit   for exit_k  bars

Calibration

Per symbol, per timeframe, we grid-sweep 2,304 (high_enter, high_exit, low_enter, low_exit, enter_k, exit_k) combinations against 180 days of 1m klines, using a smoothed-percentile ground truth (top/bottom 10% of forward-window RV). For each combination we compute macro-F1 across the three classes and the mean alerts-per-day. The three named presets (conservative, balanced, aggressive) are picks on the Pareto front of (F1, alerts/day).

Per-symbol presets are stored at data/calibration/{symbol}/presets.json and loaded by the service at boot. Nightly CI reruns the sweep and opens a PR if F1 moved more than 0.001 on any preset — see changelog.

Alternative vol estimators

Alongside the close-to-close RV that drives the FSM, each /v1/regime/{symbol} response includes two intraday-efficient estimators computed over the same 30-bar window:

These are informational — useful for anyone who wants to sanity-check the RV signal or build their own thresholds off a more efficient estimator. The FSM deliberately stays on close-to-close because it's the broadly understood benchmark and every venue we read reports it cleanly. Values come through as null when the bar source (e.g. Coinbase fallback) didn't provide OHLC.

Cross-exchange consensus

A second engine polls Binance, Coinbase and Bybit independently, computes a stateless (no FSM hysteresis) regime label per venue, and reports the majority. When the three agree you're seeing structural vol; when they diverge, one venue has a book anomaly.

Honest limits

Change log

Per-symbol calibration shipped

Until this date every symbol ran on BTC/ETH-fit thresholds. After the sweep each of the remaining eighteen gets its own thresholds, lifting balanced F1 by 2–6 points for alts (LINK highest at 0.45).

4h / 1d timeframes added

Shares the same thresholds as the shorter timeframes for now. Per-tf calibration is on the list; the scale-free z framing makes the shared values reasonable in the meantime.

Cross-exchange consensus

Added Coinbase and Bybit to the poller. Stateless classification only — hysteresis would require tracking FSM state per venue, which is on the list.

Initial calibration

BTC/ETH swept over 180 days, three Pareto-front presets published. F1 0.37 / 0.39 / 0.41 at conservative / balanced / aggressive.