---
title: "Liquidation bursts"
description: "Long and short liquidations in USD in their own pane under the chart, one column per bar: long liquidations in orange at its foot and short liquidations in…"
order: 85
section: "cookbook"
---

<!-- source: docs/indicators/cookbook/liquidation-bursts.md; generated by packages/cli/scripts/gen-indicator-docs.ts, do not edit -->

# Liquidation bursts

![Mirrored liquidation histogram with burst size tags on BTC](/wrun/images/liquidation-bursts.png)

Long and short liquidations in USD in their own pane under the chart, one column per bar: long liquidations in orange at its foot and short liquidations in amber stacked on them, so the column is the bar's total and the legend reads each side in dollars ("Long liquidations $14.1M"). A bar whose liquidations on one side jump past the rolling norm (a z-score over the window) is tagged on price with the size in money, "$12.4M" or "$850K", in rose: a long flush is tagged under the bar's low, a short squeeze over its high, the text running right of the bar. One tag per bar, the bigger side.

The parts are two `liquidations` inputs split by side ([Data sources](../core-concepts/data-sources.md)), two histogram outputs stacked into one column, the `Sma` and `Stdev` helpers behind the z-score ([TA library](../functions/ta-library.md)), and label handles in chart time and price for the tags ([Drawing objects](../presentation/drawing-objects.md)). This is also the `liquidation-bursts` template: the **Liquidation Bursts** card under **Order flow** in the editor's starter list, and it compiles as written.

## The wrun indicator

```typescript sample=liquidation-bursts
// Liquidation Bursts: long and short liquidations in USD in their own pane, one column per bar, longs in orange at
// its foot and shorts in amber stacked on them. A bar whose liquidations jump past the rolling norm (a z-score over
// the window) is tagged on price with the size in money: a long flush under the bar's low, a short squeeze over its high.

param.number("burst_z", 3.0, { min: 1.0, max: 8.0, step: 0.1, label: "Burst threshold in deviations", description: "A bar is a burst when its liquidations sit this many deviations above the window's mean" });
param.int("window", 96, { min: 10, max: 500, label: "Window in bars", description: "Bars the mean and deviation are taken over" });
param.int("tags_kept", 40, { min: 1, max: 60, label: "Tags kept", description: "Tags kept on the chart; the oldest is recycled" });
legend({ title: "({{window}})" }); // the words after the name in the legend: the window, read by name
input("close", ohlcv.close); // the primary input: the chart's own candles define the grid every other input lines up on
input("long_liq", liquidations.liquidations, { side: "SELL", missing: "zero" }); // longs are liquidated by forced sells; a bar with none reads 0
input("short_liq", liquidations.liquidations, { side: "BUY", missing: "zero" }); // shorts are liquidated by forced buys
output("long_liqs", histogram, lower, { color: "#f86800", stack: "liqs", label: "Long liquidations", format: "usd" }); // at the foot of the column, in dollars
output("short_liqs", histogram, lower, { color: "#f8c000", stack: "liqs", label: "Short liquidations", format: "usd" }); // stacked on the longs: the column is the bar's total
output("burst", none); // data-only: -1 a long flush, +1 a short squeeze, 0 none; read it in the Console or fire an alert(...) on it
string("text", { max_bytes: 40 }); // one bounded slot every label is written through
handles.label({ size: 11, color: "#fb7185" }); // the tags (chart time and price) and the one line of words when the market has no liquidations

const MAX_TAGS = 60; // tags ride a ring: the oldest is recycled
const tags: LabelHandle[] = []; // handle objects allocate once
for (let i = 0; i < MAX_TAGS; i += 1) tags.push(draw.label(i));
const notice = draw.label(100); // ids are one space across kinds
const SLATE = rgba(148, 163, 184, 255);

let burstZ = 3.0; // settings, read in onStart()
let tagsKept = 40;
let longMean = new Sma(96); // rebuilt in onStart()
let longDev = new Stdev(96);
let shortMean = new Sma(96);
let shortDev = new Stdev(96);
let liquidationsSeen = 0.0; // every liquidation seen: 0 means the market has none
let rangeAvg = NaN; // a running mean of high - low: the tag's distance from the bar
let bursts = 0; // how many have been tagged: the ring position

function isBurst(value: f64, mean: f64, dev: f64): bool { // past the norm, with a norm to speak of
  return value > 0.0 && !isNaN(mean) && !isNaN(dev) && dev > 0.0 && value >= mean + burstZ * dev;
}

function sbMoney(usd: f64): void { // "$12.4M", "$850K", "$920"
  sb_text("$");
  if (usd >= 1.0e9) {
    sb_f64(usd / 1.0e9, 2);
    sb_text("B");
  } else if (usd >= 1.0e6) {
    sb_f64(usd / 1.0e6, 1);
    sb_text("M");
  } else if (usd >= 1.0e3) {
    sb_f64(usd / 1.0e3, 0);
    sb_text("K");
  } else {
    sb_f64(usd, 0);
  }
}

function onStart(): void {
  burstZ = p_burst_z();
  tagsKept = i32(p_tags_kept());
  const window = i32(p_window());
  longMean = new Sma(window);
  longDev = new Stdev(window);
  shortMean = new Sma(window);
  shortDev = new Stdev(window);
}

// onBar() runs once per bar: both sides into their norms, the burst test per side, the tag's place; then the two stacked
// histograms on every bar, a tag on a burst bar, and the notice on the live bar only.
function onBar(): void {
  const high = bar.high();
  const low = bar.low();
  const barTime = bar.time();
  const longLiq = in_long_liq();
  const shortLiq = in_short_liq();
  liquidationsSeen += longLiq + shortLiq;
  const range = high - low;
  rangeAvg = isNaN(rangeAvg) ? range : rangeAvg + (range - rangeAvg) * 0.1;
  const longBurst = isBurst(longLiq, longMean.update(longLiq), longDev.update(longLiq));
  const shortBurst = isBurst(shortLiq, shortMean.update(shortLiq), shortDev.update(shortLiq));
  let burst = 0;
  let tagX = NaN;
  let tagY = NaN;
  let tagUsd = NaN;
  if (longBurst && (!shortBurst || longLiq >= shortLiq)) { // one tag per bar: the bigger side
    burst = -1;
    tagX = barTime;
    tagY = low - rangeAvg * 0.6;
    tagUsd = longLiq;
  } else if (shortBurst) {
    burst = 1;
    tagX = barTime;
    tagY = high + rangeAvg * 0.6;
    tagUsd = shortLiq;
  }
  out_long_liqs(longLiq);
  out_short_liqs(shortLiq);
  out_burst(f64(burst));
  if (!isNaN(tagX)) {
    const k = bursts % tagsKept; // the ring position: the oldest tag is reused
    bursts += 1;
    sb_clear();
    sbMoney(tagUsd);
    tags[k].set(tagX, tagY).text(str_text_sb);
    tags[k].align(ALIGN_LEFT).valign(burst > 0 ? VALIGN_BOTTOM : VALIGN_TOP); // the text runs right of the bar and clear of it, away from the chart's own High and Low tags, which run left
  }
  if (bar.isLast() && liquidationsSeen <= 0.0) { // the market served no liquidations at all: say so once, top right
    sb_clear();
    sb_text("No liquidations on this market");
    notice.set(16, 14).text(str_text_sb);
    notice.anchor(ANCHOR_TOP_RIGHT).align(ALIGN_RIGHT).color(SLATE);
  }
}
```

## How it works

**A liquidation's side is the forced order's side.** `input("long_liq", liquidations.liquidations, { side: "SELL", missing: "zero" })` reads longs liquidated by forced sells and its BUY twin reads shorts liquidated by forced buys, the same reading the native Liquidations indicator uses for its Longs and Shorts. A bar with none reads 0. `long_liqs` and `short_liqs` share `stack: "liqs"`: the longs fill the foot of each column in orange and the shorts stack on them in amber, both written positive and printed in dollars (`format: "usd"`), so the column's height is the bar's total and neither side reads negative.

**A burst is a z-score.** Each side's liquidations against their mean and standard deviation over `window` (96) bars give a z-score; a bar is a burst when the bigger side sits `burst_z` (3.0) deviations above the mean. `burst` carries -1 for a long flush, +1 for a short squeeze, 0 otherwise: a data-only signal a declared alert can fire on.

**The tag is money.** On a burst bar the size is written in money through the one bounded slot ("$12.4M", "$850K", "$920") to a rose label handle placed under the bar's low for a flush and over its high for a squeeze, x from `bar.time()`. `valign(VALIGN_TOP)` hangs a flush tag below its point and `valign(VALIGN_BOTTOM)` stands a squeeze tag above it, and `align(ALIGN_LEFT)` runs the text right of the bar, so a tag never sits on the chart's own High and Low tags, which run left from their candle. One tag per bar, the bigger side; `tags_kept` (40, 1 to 60) tags stay on the chart and the oldest is recycled.

## Where it runs

Perps (Binance Futures, Hyperliquid). The pane's axis is in USD. The threshold is a ratio to the market's own norm, so a thin market whose bars mostly carry no liquidations tags small sizes ("$413" on a quiet alt) while BTC tags millions; raise `burst_z` to keep only the biggest.

## When data is missing

Spot, prediction markets, stocks and FX have no liquidations: both histograms stay at zero and one slate line of words sits at the top right of the chart, "No liquidations on this market".

## Customize it

- **Fewer tags.** Raise `burst_z`; the histograms keep every bar.
- **A longer norm.** `window` up to 500 bars smooths the mean and the deviation.
- **Both sides tagged.** Tag each side that bursts instead of the bigger one; the ring then spends two ids on such a bar.
- **Alert on a burst.** Bind `burst` to a `const` and declare `alert("liquidation_burst", { when: ... })`: it fires on the bar a burst starts. Once the indicator is published and on a chart, the signal is in the chart's alert dialog ([Alerts](../functions/alerts.md)).

## Run it

1. In the editor's Explorer, press the **Templates** icon ("Browse starter templates") and pick **Liquidation Bursts** under **Order flow**.
2. Press **Run** on a perp, such as BTCUSDT on Binance Futures: the stacked columns fill and the bursts are tagged on price.
3. At the editor's Console prompt, type `last 60 burst` to read the burst sign of the last 60 bars.

## Concepts used

- [Data sources](../core-concepts/data-sources.md) for the `liquidations` source and its sides
- [TA library](../functions/ta-library.md) for `Sma` and `Stdev`
- [Drawing objects](../presentation/drawing-objects.md) for label handles in chart time and price and the text slot
