Why a Calm Tape Is the Most Dangerous Thing in Your Portfolio

The worst drawdowns rarely start in chaos. They start in the calm. A coin that has drifted sideways for three weeks lulls a sizing model into stacking leverage — right before the band snaps and a 4% day becomes a 40% liquidation cascade.

That is the core insight of volatility-targeting: compressed vol is the most dangerous regime, not the loudest one. Low realized vol is dry tinder. It is the regime that precedes the move, and it is exactly when most strategies are carrying the most risk.

The new /api/v1/volatility/regime endpoint turns that intuition into a number for every asset in the perps + Binance-spot universe: realized vol three ways, a 90-day vol percentile, term structure, and a position-size scalar. It is Regime #13 of 14 in the regime taxonomy — the risk-sizing overlay.

What the Volatility Regime Endpoint Returns

Each asset carries a single regime label plus a vol block holding the raw realized-vol estimators, percentiles, term structure, and the sizing multiplier. One call covers the whole universe.

curl -H "X-API-Key: cdk_live_yourkey" \
  "https://cryptodataapi.com/api/v1/volatility/regime?regime=compressed&sort=days_compressed&order=desc&limit=5"

One symbol in the response:

{
  "symbol": "LINK",
  "source": "binance_spot",
  "price": 13.82,
  "regime": "compressed",
  "is_stable": false,
  "vol": {
    "rv_cc_7": 31.4, "rv_cc_30": 38.9,
    "rv_parkinson_30": 36.2,
    "rv_gk_7": 29.7, "rv_gk_30": 35.1,
    "rv_1h": 41.0,
    "vol_pctile_30": 11.4, "vol_pctile_7": 18.2,
    "rv_z_30": -1.21, "rv_z_7": -0.88,
    "term_structure_ratio": 0.846,
    "vol_target_multiplier": 1.709,
    "days_compressed": 12, "days_shock": 0,
    "days_in_regime": 9, "prev_regime": "normal",
    "regime_changed": false
  }
}

That record says LINK's 30-day Garman-Klass vol (35.1% annualized) sits in the bottom 11.4% of its trailing 90 days, it has been compressed for 12 straight bars, and a vol-targeter would size it 1.7× base. The calm is funding the leverage.

Realized Vol, Three Ways — and Why the vol Block Has So Many Fields

Close-to-close vol only sees the closing print. Range-based estimators see the wicks. We compute all three so you can read the gap between them — a wide range with a quiet close is a different risk than a clean trend.

The Five Volatility Regimes and What to Do in Each

Classification is a priority cascade off the GK percentiles and the 7d/30d term ratio. The first rule that matches wins, so the labels are mutually exclusive.

RegimeTriggerWhat it meansWhat to do
vol_shock7d vol percentile ≥ 90Acute spike, top decile of 90d rangeCut size; fade only with confirmation
expandingterm ratio ≥ 1.15 & 30d pctile ≥ 50Front vol breaking outTrail stops wider; let breakouts run
compressed30d vol percentile ≤ 20The dangerous calm before a moveDe-lever despite the quiet; pre-position
mean_revertingterm ratio ≤ 0.85 & 30d pctile ≥ 60Elevated but front coolingFade the spike back toward the mean
normalfallthroughNo edge from vol structureSize at baseline

Note the trap in compressed: the multiplier is highest exactly when the regime is most fragile. days_compressed is your fuse length — the longer the streak, the more asymmetric the eventual expansion. Pair a long squeeze with the liquidation heatmap to see where the fuel sits.

How Do I Size Positions From a Volatility Regime API?

This is the field most agents actually consume. vol_target_multiplier is target_vol / current_vol, capped to the range [0.25, 3.0]. The target_vol numerator is 60% annualized — the vol level a 1.0× position is sized for.

If an asset's 30d GK vol is 35%, the scalar is 60 / 35 = 1.71×, so a vol-targeter sizes up. If vol runs hot to 120%, the scalar is 0.5×, sizing down. The cap stops a dead-calm coin from demanding unbounded leverage — the floor caps the cut in a shock.

import httpx

HDR = {"X-API-Key": "cdk_live_yourkey"}
BASE = "https://cryptodataapi.com/api/v1/volatility"

# 1. Pull every asset a vol-targeter would size up
items = httpx.get(
    f"{BASE}/regime", headers=HDR,
    params={"sort": "vol_target_multiplier", "order": "desc", "limit": 20},
).json()["items"]

BASE_NOTIONAL = 10_000  # your 1.0x sleeve per name
for r in items:
    mult = r["vol"]["vol_target_multiplier"] or 1.0
    notional = BASE_NOTIONAL * mult
    print(r["symbol"], r["regime"], f"{mult}x", f"${notional:,.0f}")

Sort keys for the screener: vol_pctile_30 (default), rv_gk_30, rv_gk_7, term_structure_ratio, vol_target_multiplier, days_compressed, and symbol. Default limit 250, max 500; filter with source and regime.

The Market-Wide Composite: One Number for Gross Exposure

When you want a single dial for whole-book risk instead of a per-asset list, hit /volatility/regime/score — open to any valid key.

curl -H "X-API-Key: cdk_live_yourkey" \
  "https://cryptodataapi.com/api/v1/volatility/regime/score"
{
  "as_of": "2026-06-11T14:00:00+00:00",
  "composite_score": 38.5,
  "sentiment": "calm",
  "target_vol": 60.0,
  "gross_exposure_multiplier": 1.0,
  "median_vol_pctile_30": 27.0,
  "aggregate": {
    "compressed": 91, "expanding": 24, "vol_shock": 7,
    "mean_reverting": 33, "normal": 188, "total": 343,
    "pct_compressed": 26.5, "pct_shock": 2.0
  }
}

The composite_score runs 0-100 off a 50 baseline: +35 per unit share of vol_shock, +20 expanding, +5 mean-reverting, -20 compressed. Higher = more market-wide stress, so you size down.

The sentiment band reads it directly: stressed (≥70), elevated (55-69), normal (45-54), calm (30-44), and dormant (<30) — the dangerously-quiet, broadly-compressed state. gross_exposure_multiplier maps the score to a 0.5-1.0 book scalar: ~1.0 calm, ~0.5 at max stress.

Per-Symbol Detail, 60-Day History, and Backfill

For a single asset with a sparkline-ready series, /volatility/regime/{symbol} returns the same item plus a 60-bar history array (date, close, rv_cc_30, rv_gk_30). It is Pro+; /volatility/regime/refresh (POST) force-recomputes the cache and is also Pro+.

curl -H "X-API-Key: cdk_live_yourkey" \
  "https://cryptodataapi.com/api/v1/volatility/regime/BTC" | jq '.history[-1]'
{
  "date": "2026-06-11T00:00:00+00:00",
  "close": 71240.5,
  "rv_cc_30": 42.1,
  "rv_gk_30": 39.8
}

Because the whole regime replays from daily klines, it is backfillable — every archived daily snapshot carries the universe-wide summary plus a full by_symbol map for point-in-time backtests. The only field that stays null on historical days is the live-only rv_1h. That mirrors the approach behind the technical / structural regime overlay, which shares the same universe and cached kline fetch.

When to Reach for the Volatility Regime

Volatility Regime is the risk-sizing layer — Regime #13 of 14 in the 14-regime framework. Reach for it in three concrete cases:

What it isn't: a direction signal. Vol tells you how much to bet, never which way. Pair it with a trend or structure regime for direction — that is the whole point of the regime taxonomy: one layer per question.

Probabilistic companion: the new quant HMM engine scores a live vol_spike regime and a forward volatility head every hour, and its Monte Carlo of tomorrow hands you P(volatility spike) and the p5–p95 return band straight into your sizing logic.