← Back to the docs
LootX

Market data: footprint clusters, delta, open interest, order book

Generated: 2026-10-01 docs.lootx.trade
Основы

1Market data: footprint clusters, delta, open interest, order book

What a LootScript script can read besides candles: footprint clusters, delta, open interest, funding rate, recorded and live order book, time and sales, screener, other timeframes and instruments.

Besides candles, a LootScript script reads order flow data: footprint clusters, delta, open interest, funding rate, recorded order book history, live order book and time and sales, and screener metrics. You don’t need to enable anything: as soon as the script accesses, say, cluster.poc, the terminal subscribes to clusters for the chart’s instrument and timeframe — even if the chart shows regular candles. When the script is removed from the chart, the subscription is released.

This page covers what’s in each namespace, where the data comes from, which exchanges have it, and how to access values from another timeframe or instrument.

The main rule: no data means na, not 0

Any value on this page can be na. This happens when the exchange isn’t covered by the server, the timeframe isn’t supported, history is still loading, or the bar is older than the available history. Zero would mean “no trades happened”, which is a different fact: an accumulated sum with zeroes filled in looks plausible but is wrong.

Every namespace has an availability flag — cluster.available, delta.available, oi.available, and so on. Check it or use the na(x) function. Comparing to na with == won’t compile.

Loot
indicator("Accumulated delta without zero substitution", overlay = false)
var float cvd = 0.0
if delta.available {
    cvd := cvd + delta.value
}
plot(delta.available ? cvd : na, "CVD", color = color.teal)

The chart legend next to the script name hints why data is missing: “venue not covered”, “timeframe not supported”, “data loading…”, “no open order book”, “screener unavailable”.

Where each thing comes from

Namespace What it is History on chart
cluster.* Footprint clusters of a bar: volume by price Yes, from the cluster server
delta.* Delta of aggressive buys and sells Yes
oi.* Open interest Yes
funding.* Funding rate and its calculations Yes
depth.* Order book recorded by the server, per bar Yes, limited depth
book.* Live order book Last bar only
tape.* Live time and sales of trades Last bar only
screener.* Screener metrics for the instrument Last bar only

Clusters: cluster.*

Volume at each price level inside a bar, split into aggressive buys and sells — the same data drawn by the footprint chart. Levels are numbered from bottom to top, from 0 to cluster.levels - 1.

Name Returns
cluster.available Whether clusters are available on this bar
cluster.levels Number of price levels in the bar
cluster.price(i) Price of level i
cluster.bid(i) Aggressive buys at level i
cluster.ask(i) Aggressive sells at level i
cluster.total Total volume of the bar
cluster.delta Buys minus sells across all levels
cluster.poc, cluster.poc_index Price and index of the level with the highest volume
cluster.max_cell Volume of the largest cell in the bar
cluster.imbalance(i) Level skew: +1 buys, -1 sells, 0 none
cluster.stacked_buy, cluster.stacked_sell Price where the longest run of skewed levels starts
cluster.stacked_buy_steps, cluster.stacked_sell_steps Length of that run in levels
cluster.value_area(pct) Lower and upper bounds of the value area; pct is the share of volume, 0.7 = 70%
cluster.grid_step Price grid step of the bar

Note the names: cluster.bid(i) is the buys that “lifted” the ask, not resting buy orders in the order book.

Clusters are available on timeframes from 30 seconds to one day.

Loot
indicator("POC and value area", overlay = true)
[vaLow, vaHigh] = cluster.value_area(0.7)
plot(cluster.poc, "POC", color = color.orange, style = plot.style_circles)
plot(vaHigh, "Area high", color = color.gray, style = plot.style_linebr)
plot(vaLow, "Area low", color = color.gray, style = plot.style_linebr)

Delta: delta.*

Difference between aggressive buys and sells for a bar. Volume is in coins (base currency).

Name Returns
delta.value Bar delta: buys minus sells
delta.buy, delta.sell The two components separately
delta.cum Cumulative delta from the start of loaded history
delta.min, delta.max Minimum and maximum of running delta within the bar
delta.open, delta.high, delta.low, delta.close Bar delta as a candle
delta.trades Number of trades in the bar
delta.usd Delta in quote currency, based on actual trade amounts
delta.available Whether delta is available on this bar

delta.min and delta.max can’t be computed from clusters — that’s the intra-bar delta path, calculated by the server. They show that buyers led the bar, but sellers closed it. delta.usd is more precise than delta.value * close: on a sharp bar, trade prices differ significantly from the close.

delta.cum starts at zero on the first loaded bar, so its level depends on the depth of loaded history. Compare changes, not absolute values.

Delta is available on timeframes from 30 seconds.

Loot
indicator("Delta and intra-bar reversal", overlay = false)
d = delta.value
reversed = delta.available and d < 0 and delta.max > -d
plot(d, "Delta", style = plot.style_columns, color = d >= 0 ? color.teal : color.red)
plotshape(reversed, "Reversal", style = shape.xcross, location = location.top, color = color.orange, size = size.tiny)

Open interest: oi.*

Name Returns
oi.open, oi.high, oi.low, oi.close Open interest for the bar in the units the exchange publishes
oi.coins Open interest in coins
oi.usd Open interest in quote currency
oi.change Change in oi.close from the previous bar
oi.available Whether data is available on this bar

Units of oi.open…oi.close differ across exchanges, so for cross-exchange comparisons use oi.coins or oi.usd. Open interest comes on a minute grid: on second-based timeframes all values are na.

Loot
indicator("Price and open interest", overlay = false)
dp = ta.change(close)
build = oi.available and dp > 0 and oi.change > 0
plot(oi.change, "OI change", style = plot.style_columns, color = build ? color.teal : color.gray)

Funding rate: funding.*

Name Returns
funding.rate Predicted rate for the next settlement
funding.interval_hours Hours between settlements
funding.settled true on the bar where settlement occurred
funding.settled_rate Rate actually charged on this bar; if there are multiple settlements in a bar, their sum
funding.cum Sum of charged rates over loaded history
funding.available Whether the instrument has funding

The rate is a fraction, not percent: 0.0001 means 0.01%. The chart shows percent; scripts don’t convert. For backtesting, use funding.settled_rate: funding.rate is a prediction and changes until settlement. Spot has no funding, and on second-based timeframes values are na.

Loot
indicator("Funding per settlement, %", overlay = false)
plot(funding.rate * 100, "Rate prediction", style = plot.style_area, color = funding.rate >= 0 ? color.teal : color.red)
plotshape(funding.settled, "Settlement", style = shape.circle, location = location.bottom, color = color.orange, size = size.tiny)

Recorded order book: depth.*

The order book as the server recorded it — the same data drawn by the heatmap — laid out per bar. Unlike live book.*, these values exist on every recorded bar. Prices are grouped into buckets; each bucket’s volume is the maximum during the bar, in coins.

Name Returns
depth.available Whether the order book is recorded for this bar
depth.levels Number of non-empty buckets in the bar
depth.price(i) Lower bound of bucket i, ascending
depth.qty(i) Maximum volume resting in the bucket during the bar
depth.side(i) +1 bids, -1 asks, 0 bucket was on both sides
depth.at(price) Volume in the bucket at that price
depth.grid_step Bucket size in price units
depth.best_bid, depth.best_ask Best prices at bar close
depth.max_cell Volume of the heaviest bucket
depth.bid_sum(pct), depth.ask_sum(pct) Side volume within pct% from mid
depth.imbalance(pct) Skew in the same band: from -1 to +1
depth.max_bid(pct), depth.max_ask(pct) Price and volume of the heaviest bucket on each side within the band

Limitations:

  • Data is available where the server-side heatmap is, and on timeframes from one second.
  • The server stores a band of about ±4% from price. Outside it depth.at returns na; inside the band an empty bucket is 0.
  • History depth is limited: the oldest bars of a long history return na.
  • Values for the forming bar change as data arrives.
Loot
indicator("Recorded order book skew", overlay = false)
band = input.float(1.0, "Band, % of price", minval = 0.1, maxval = 4.0, step = 0.1)
imb = depth.imbalance(band)
plot(imb, "Skew", style = plot.style_columns, color = imb >= 0 ? color.teal : color.red)

To draw the recorded order book under candles, one line heatmap.depth() in a script with overlay = true is enough. Colors and field thresholds are on the Inputs and drawing page.

Loot
indicator("Recorded order book as heat", overlay = true)
heatmap.config(palette = heatmap.inferno, low = 25)
heatmap.depth()

Live order book and time and sales: book.* and tape.*

Live order book and time and sales are not recorded, so values exist only on the last bar and are always na on history. They require an open order book panel for the same instrument: otherwise book.available and tape.available are false and the legend shows “no open order book”. In replay mode these data are unavailable.

Name Returns
book.bid(i), book.ask(i) Price of level i; 0 is best price
book.bid_qty(i), book.ask_qty(i) Volume at the level, in coins
book.spread Best ask minus best bid
book.mid Midpoint between best prices
book.imbalance(n) Volume skew across the top n levels of each side: from -1 to +1
book.available Whether an order book snapshot is available
tape.last_price, tape.last_qty Price and volume of the last trade
tape.last_side +1 aggressive buyer, -1 aggressive seller, 0 no trades yet
tape.count(ms) Number of trades in the last ms milliseconds
tape.buy_volume(ms), tape.sell_volume(ms) Aggressive buy and sell volume over the window
tape.max_print(ms) Largest trade in the window
tape.available Whether the time and sales feed is connected

The time and sales window and book.imbalance depth are set as numbers in code or via an input.int setting. The window counts from the last trade time on the exchange, not from the computer clock. The script only sees the tail of the time and sales — about the last two thousand trades, so on an active market a long window won’t cover the whole interval.

When such a value is used in plot, the editor warns: “Data is available only in real time — the series is empty on history”. This is expected: to the left of the last bar the series is empty. Strategies cannot read these data — see Strategies and tester.

Loot
indicator("Order book skew", overlay = false)
levels = input.int(20, "Levels per side", minval = 1, maxval = 200)
imb = book.available ? book.imbalance(levels) : na
plot(imb, "Skew", style = plot.style_area, color = imb >= 0 ? color.teal : color.red)
hline(0, "Zero", color = color.gray)

Screener: screener.*

screener metrics for the chart’s instrument — the same numbers as in its columns. There is no history: a value exists only on the last bar. The window is a string, and not every metric has every window.

Function Shows Windows
screener.change(w) Price change "1m" "5m" "15m" "1h" "24h"
screener.vol(w) Turnover "1m" "5m" "15m" "1h" "24h"
screener.avg_vol(w) Average turnover "1m" "5m" "15m" "1h"
screener.rvol(w) Relative volume "1h" "24h"
screener.natr(w) NATR "1m" "5m"
screener.oi_delta(w) Open interest change "1m" "5m" "1h" "24h"
screener.btc_corr(w) Correlation with BTC "1m" "5m"
screener.available Whether the instrument is covered by the screener —

A window not listed in the table returns na. A metric not included in your screener subscription also returns na. The editor marks output of these values with the same warning as for the order book: the series is empty on history.

Loot
indicator("Screener: RVOL and NATR", overlay = false)
plot(screener.rvol("1h"), "RVOL 1h", color = color.orange)
plot(screener.natr("5m"), "NATR 5m", color = color.teal)

Exchange coverage

Exchange Clusters and delta Open interest and funding
Binance, Bybit, OKX, Bitget, Gate.io, MEXC, KuCoin, BingX, AsterDEX Spot and futures Futures
Hyperliquid Futures; no spot Futures
Binance Alpha No: exchange doesn’t publish aggressor side No
Upbit No No
Data Timeframes
Clusters 30 seconds to 1 day
Delta 30 seconds and up
Open interest, funding 1 minute and up
Recorded order book 1 second and up, where server-side heatmap is available
Live order book, time and sales Any, with an open order book panel
Screener Any, for instruments the screener sees

Coverage is determined by the data server and may change. The most reliable approach is to rely on the .available flag and the legend caption.

Another timeframe and another instrument

request.security evaluates an expression on another series — a higher timeframe or another coin — and maps the result to the chart’s bars.

TEXT
request.security(symbol, timeframe, expression, gaps = false, lookahead = false, ignore_invalid_symbol = false)
  • symbol — in “EXCHANGE:TICKER” format, as in TradingView: "BINANCE:BTCUSDT.P", where .P is a perpetual futures contract. The chart’s instrument is sym.ticker.
  • timeframe — a string like "5", "60", "4h", "1D", "1W". The chart’s timeframe is tf.period.
  • expression — one number or multiple numbers in square brackets: [high, low].

No lookahead. By default, a chart bar sees the value of the last closed bar of the higher timeframe. That’s why an hourly EMA on 5-minute bars is a step that only moves when the hour closes. This makes the backtest match what you would have seen live.

  • gaps = true — value appears only on the first chart bar where a new higher-timeframe bar appeared, then na.
  • ignore_invalid_symbol = true — an unknown symbol returns na. Without this, the script stops with the error “Symbol … unknown”.

Inside the expression you can use the other series’ candles and calculations on them. You cannot pass a chart variable there — only values from input.* settings. The order book, time and sales, and screener don’t compile inside the request, and clusters, delta, open interest, and funding for another series return na. A script can have up to 8 different “instrument + timeframe” pairs and up to 32 request.security calls.

Loot
indicator("Higher-timeframe EMA", overlay = true)
len = input.int(20, "EMA length", minval = 2, maxval = 500)
tfHigh = input.timeframe("60", "Higher timeframe")
emaHigh = request.security(sym.ticker, tfHigh, ta.ema(close, len))
plot(emaHigh, "EMA", color = color.orange, style = plot.style_stepline)
Loot
indicator("Spread to another exchange", overlay = false)
other = input.symbol("BYBIT:BTCUSDT.P", "Compare to")
px = request.security(other, tf.period, close, ignore_invalid_symbol = true)
plot(close - px, "Difference", color = color.orange)

Next

https://docs.lootx.trade/en/loot/market-data