Skip to content
ChartDeck ChartScript docs Account Open the terminal

Liquidation data

The liquidation model in a script, with the levels now (liq.levels, observed positions included), the hourly heat field and the legend facts.

ChartDeck estimates where leveraged positions would be liquidated, from open interest, price and typical leverage on each venue. It is a model, not exchange data. Where an exchange publishes positions (Hyperliquid, dYdX, Lighter) the observed levels come with it. The built-in Liquidation Levels and Liquidation Heatmap studies draw this data; a script reads the same with the liq functions. (The realized liquidations, the force-closes that happened, are the series liq.long_usd, liq.short_usd and liq.total_usd: see ChartDeck data; placed on each bar as the Liquidation candles mark them, they are liq.long_liq_usd, liq.short_liq_usd and liq.events: see Liquidations on each bar.)

#The levels now

liq.levels(side) returns the model's biggest levels (12 per side, 40 on Pro and Elite) and the observed ones, as liq.level values. It describes now, so it is filled on the newest bar only: every other bar gets an empty array. Draw from it inside if (barstate.islast).

FieldTypeMeaning
pricefloatwhere the liquidations sit
sidestring"long" (below the price: longs liquidated on a fall) or "short" (above)
notionalfloatthe estimated size, in the quote currency
observedbooltrue = positions seen on an exchange; false = model estimate
venuesstringthe venue of an observed level, the model's scope otherwise
updatedintwhen the data was last updated (ms)
ChartScriptOpen in editor
//@chartscript 1
indicator("Liquidation lines", { overlay: true, max_lines_count: 100 })
state lines = array.new<line>()
if (barstate.islast) {
    for (const l of lines) {
        l.delete()
    }
    lines.clear()
    for (const lv of liq.levels()) {
        const col = lv.side == "long" ? color.up : color.down
        lines.push(line.new(time, lv.price, time_close, lv.price, xloc.bar_time, extend.both, color.new(col, lv.observed ? 0 : 60), line.style_solid, lv.observed ? 2 : 1))
    }
}

liq.levels("long") and liq.levels("short") keep one side.

#The heat field

liq.heat() gives the model's field over the bar as a heatmap.column: 240 price rows between 10% below the lowest and 10% above the highest price of the window, the values in the quote currency (smoothed between rows, as the built-in draws them). The field is hourly: every bar inside one hour gets that hour's column (its span says 1 hour), and a bar longer than an hour gets the largest value of each row over its hours. It is a Pro feature, as the Liquidation Heatmap is: on other plans liq.heat() is na. See Heatmaps for an example.

#For the legend

FunctionGives
liq.updated()when the data was last updated (ms)
liq.venues()the model's scope as text, for example "All venues (14 listed)"
liq.window()"7d" or "30d" (Elite)
liq.is_model()true for the model; false when a venue with observed positions is pinned
ChartScriptOpen in editor
//@chartscript 1
indicator("Liquidation legend", { overlay: true })
if (barstate.islast) {
    legend.info(liq.venues())
    legend.info("updated " + str.format_time(liq.updated(), "HH:mm", "UTC") + " UTC")
    legend.badge(liq.is_model() ? "Model estimate" : "Observed", "Model estimate, not exchange data.")
}

#Where it comes from

The data is the Liquidation studies' own, with their settings: the window (7 or 30 days), a pinned venue and the observed layers you chose in the Liquidation panel apply to scripts on that chart too. It is refreshed every 5 minutes; a change runs the script again. A script on ChartDeck's servers (a protected script, a script alert) reads the 7-day window over all venues with every observed layer your plan includes.

#Liquidations on each bar

The Liquidation candles chart type marks the liquidations that happened: longs liquidated and shorts liquidated, as exact prints where ChartDeck records them (bars under 1 hour, the last day) and hourly rows otherwise. A script reads the same marks on its own bars (Pro and Elite):

NameGives
liq.long_liq_usd, liq.short_liq_usdthe USD of longs / shorts liquidated in the bar
liq.events(back)the bar's liquidations: time, price, usd, side ("long" or "short"), venues, exact
liq.events_since()where the data starts (7 days back, 30 on Elite)
ChartScriptOpen in editor
//@chartscript 1
indicator("Liquidations per bar")
plot(liq.long_liq_usd, "Longs liquidated", { color: color.red, style: plot.style_columns })
plot(-liq.short_liq_usd, "Shorts liquidated", { color: color.green, style: plot.style_columns })

An hourly row goes on a bar of its hour whose range holds its price, as the candles place it. Before the data starts the values are na, never 0; a bar inside the data with no liquidation reads 0. These are measured liquidations placed on your bars, unlike liq.long_usd and liq.short_usd, which keep their hourly totals. On other plans every value is na and the legend says "Liquidation candles: not included in your plan".

liq.events(back) lists a bar's liquidations by time. exact tells an exact print from an hourly row:

ChartScriptOpen in editor
//@chartscript 1
indicator("Large exact liquidations", { overlay: true, max_labels_count: 200 })
const minUsd = input.float(250000, "Mark from (USD)")
for (const e of liq.events()) {
    if (e.exact && e.usd >= minUsd) {
        label.new(e.time, e.price, "", xloc.bar_time, yloc.price, e.side == "long" ? color.down : color.up, label.style_circle, na, size.tiny)
    }
}

The data is asked again every minute. In Bar replay a liquidation appears once its bar (an exact print) or its hour (an hourly row) has ended. A script on ChartDeck's servers (a protected script, a script alert) reads the same data with the same rules, for the plan of the member viewing it or of the alert's owner. The per-bar values also work inside a request; the lists read the chart's own bars only.

The ChartScript documentation is in English for now; translations will follow.