MarketTrace
Methodology · v1.2.0 · updated 2026-10-21

Cross-exchange liquidations

How the liquidations tape is sourced, normalised, sized and read: WS feeds, schema, side semantics, adaptive bucketing, cluster detection, freshness rules.

See the live widget at /perpetuals/liquidations.

Expected liquidation levels next to the same tape: live liquidation heatmap.

Data sources

Three exchange WebSocket feeds, one normalised Redis stream per asset. Every executed liquidation print lands in the tape — we do not estimate liquidation pressure from open interest, do not infer stop zones, do not synthesise prints.

A single Rust binary mt-liqd — all nine assets across the three liquidation venues in one process — writes events into a per-asset Redis Streamprod:liq:<asset>:events capped at MAXLEN ≈ 10 000 (≈ 4 hours of cascade-heavy tape, often the full 24 h on quiet days). The backend reads from one stream per asset for both REST and WebSocket surfaces; there is no separate pubsub channel — the stream itself is the broadcast surface.

Event schema

Per-event fields are identical across the three sources. The two timestamps are deliberately kept distinct:

Side semantics

Liquidation streams encode the side from the perspective of the exchange's closing order, which is the opposite of the trader's position. We normalise to the position that lost:

One venue-specific note: Bybit's allLiquidation.S is the position side, not the closing-order side — so S: "Buy"means a long was liquidated, the inverse of Binance's forceOrder convention. mt-liqd maps it accordingly.

Tape colour follows this: red dot = long blew up (price dropped); green dot = short blew up (price rose).

Size scaling

Each dot's radius in viewBox-px is clamp(√(usd / $10 000) × 2, 4, 22). The sqrt damps linear-by-area scaling so a $1 M event reads as ~3.16× a $100 K event — not 10× — and a single cascade print can't blot out everything around it. The lower clamp keeps a readable hit zone on sub-$10 K dust; the upper clamp keeps the biggest cascade from overflowing the panel.

r = clamp(sqrt(usd / 10_000) * 2, 4, 22)   // viewBox-px

# Reference values (vs the size legend)
$10 K   → r ≈ 4
$100 K  → r ≈ 6.3
$1 M    → r = 20
$10 M+  → r = 22 (clamped)

Adaptive rendering

Raw scatter only scales to the ~15-minute regime. Past that, hundreds of small prints in a single second smear into a uniform glow, and cascade structure disappears. We switch render modes by window:

Hit-testing, top-N annotations and tooltips run against the rendered (bucketed) events; cluster detection, cumulative pane and rate sub-pane scan raw events since those signals are about per-event density and side flow, not hover targets.

Cluster detection

Price-cluster bands are detected on the raw events of the active window:

reference_price = current mid (latest event price)
bin_width       = reference_price * 0.001    // 0.1 %
bin events by round((price - reference) / bin_width)

for each bin:
  if Σ usd ≥ 15 % of window total AND distinct events ≥ 3:
    flag as cluster
    cluster_price = volume-weighted mean of bin's prices

keep top 3 clusters by Σ usd

Each cluster gets a dashed horizontal line + badge $X cluster · N× @ price. The volume-weighted mean (rather than the nominal bin midpoint) keeps the line sitting at the depth where the dollars actually concentrated.

Cascade alert threshold

A separate daemon, mt-cascade, reads the same streams and posts an alert when a window clears the bar. Every 30 s it re-reads the trailing 5-minute window per asset; a cascade fires when the window total reaches the threshold AND at least two venues contributed. The threshold is the trailing p99 of non-empty clock-aligned 5-minute liquidation buckets over a 7-day lookback, recomputed every 5 minutes and floored at $50 M; until 100 such buckets exist a $50 M default holds instead. On a detection the daemon waits 90 s and re-reads the window before posting, so the published figure is the settled peak rather than the first trigger, and that asset then stays quiet for 30 minutes. The floor went from $1 M to $50 M on 2026-08-18: an adaptive p99 tracking the prevailing regime is the point, but a quiet week had dragged the effective BTC bar down to roughly $2 M and ordinary flow was posting as a cascade.

fire when  Σ usd over the trailing 300 s ≥ max(p99(5-min buckets, 7 d), $50M)
      and  distinct venues ≥ 2
      and  no alert for this asset in the last 1800 s

Top-N inline annotations

Up to three of the largest dots in the window get an inline $amount · time · venue|N× label so the eye lands on the biggest cascade immediately. The $50 K floor avoids labelling dust. Label anchors flip based on which half of the plot the dot is in, so the text never spills past the right axis or under the left edge.

Liquidation rate sub-pane

Under the cumulative pane, a mirrored bar chart shows Σ usdper time bucket split by side: shorts extend UP from the baseline (green), longs DOWN (red). Bucket size follows the scatter's adaptive thresholds (30 s at ≤ 15 m, 1 min at 1–4 h, 5 min at 24 h) so the columns visually align with the dots above.

Feed health

A per-(asset, exchange) status hash prod:liq:status:<asset>:<exchange> is refreshed every 5 s with a 60 s TTL. The backend converts that into three states:

The latency p50 / p99 numbers in the health tooltip are sampled from the mt-liqd binary's rolling 200-event ring buffer of producer_ts_ms − ts_ms.

Empty-time bands

Contiguous spans of the window with no liquidations at all get a subtle background tint. Without this, a 24 h view with 6 h of local data reads as a broken renderer rather than as “there were no cascades in that stretch”. The threshold is gap ≥ 5 % of window — short enough to flag a quiet 30 m on a 24 h view, long enough to avoid striping the chart with micro-bands during quiet seconds.

Caching

Liquidation heatmap model (liqmap_model_v1)

The liquidation heatmap draws expected liquidation levels next to the tape described above. The expected layer is a model with five rules. Every API response and every hit-rate row carries its version, liqmap_model_v1, and a change to any rule is a new version.

  1. Lots. Open interest is read in steps (1 minute on the 24h map, or 15 minutes until 7 days of minute data exist) for Binance, Bybit and OKX together. Each rise opens a lot at that step's close, and the taker buy ratio splits it into a long part and a short part.
  2. Leverage. Each part is split into equal thirds at 25x, 50x and 100x. A long third is liquidated at close × (1 − 1/L + MMR), a short third at close × (1 + 1/L − MMR), where MMR is each venue's maintenance margin rate weighted by that venue's open interest.
  3. Shrinking. A fall in open interest shrinks every open lot by the same fraction.
  4. Hits. A long part leaves the map once a step's low reaches its level, a short part once a step's high does. That crossing is a hit.
  5. Grid. Levels are counted in price buckets about 0.06% of the price wide, and the map shows the dollars still expected in each bucket at each step. A lead-in of history before the window (7 days for the 24h map) seeds the lots, so the left edge is not empty.

Realized layer

Liquidations from Binance, Bybit and OKX, at the trade price at the moment of liquidation where one is known, otherwise within that step's price range. Binance publishes at most one per symbol per second, so its count is a floor; OKX publishes an official sample. Hyperliquid has no liquidation feed: its open interest is left out of the model, and none of its liquidations are on the realized layer.

Hit-rate

Every hour, each hit is matched with realized liquidations of the same side within one step and 0.3% of the level, and each realized cell counts once. Two numbers come out: the share of hits with at least $100,000 or 1% of the expected dollars realized nearby, and realized over expected dollars. Minutes inside a feed gap are left out of both sides. The numbers are published once the tape covers at least 90 days, feed gaps stay under 1% of it, and the model has been unchanged for 30 days.

Limitations

Versioning

Methodology version v1.2.0 · updated 2026-10-21. v1.2.0 on 2026-10-21: the liquidation heatmap model (liqmap_model_v1), its realized layer and its hit-rate. v1.1.0 on 2026-09-02: USD notionals relabelled as estimates built on each venue's source reference price (2026-08-04), and the cascade-alert threshold documented, with its floor raised to $50 M (2026-08-18). Material changes (new venues, formula tweaks, threshold changes) bump the version and update dateModified in the structured data above.