Данные рынка: кластеры, дельта, OI, стакан
Что скрипт на LootScript читает помимо свечей: кластеры, дельта, открытый интерес, фандинг, история и живой стакан, лента, скринер, другой таймфрейм и инструмент.
Кроме свечей скрипт на LootScript читает данные потока ордеров: кластеры, дельту, открытый интерес, фандинг, записанную историю стакана, живой стакан и ленту, метрики скринера. Включать ничего не нужно: как только скрипт обращается, например, к cluster.poc, терминал сам подписывается на кластеры инструмента и таймфрейма графика — даже если график показывает обычные свечи. Когда скрипт снимают с графика, подписка освобождается.
На этой странице — что есть в каждом пространстве имён, откуда берутся данные, на каких биржах они есть и как взять значения другого таймфрейма или другого инструмента.
Главное правило: нет данных — это na, а не 0
Любое значение из этой страницы может оказаться na. Так бывает, если биржа не покрыта сервером, таймфрейм не поддерживается, история ещё загружается или бар старше доступной истории. Ноль означал бы «торгов не было», а это другой факт: накопленная сумма с подставленными нулями выглядит правдоподобно и при этом неверна.
У каждого пространства есть флаг наличия — cluster.available, delta.available, oi.available и так далее. Проверяйте его или функцией na(x). Сравнение с na через == компилятор не пропустит.
indicator("Накопленная дельта без подмены нулём", overlay = false)
var float cvd = 0.0
if delta.available {
cvd := cvd + delta.value
}
plot(delta.available ? cvd : na, "CVD", color = color.teal)Почему данных нет, подсказывает легенда графика рядом с именем скрипта: «площадка не покрыта», «таймфрейм не поддерживается», «данные загружаются…», «нет открытого стакана», «скринер недоступен».
Что откуда берётся
| Пространство | Что это | История на графике |
|---|---|---|
cluster.* |
Кластеры (футпринт) бара: объём по ценам | Есть, с сервера кластеров |
delta.* |
Дельта агрессивных покупок и продаж | Есть |
oi.* |
Открытый интерес | Есть |
funding.* |
Ставка фандинга и её расчёты | Есть |
depth.* |
Стакан, записанный сервером, по барам | Есть, ограниченной глубины |
book.* |
Живой стакан | Только последний бар |
tape.* |
Живая лента сделок | Только последний бар |
screener.* |
Метрики скринера по инструменту | Только последний бар |
Кластеры: cluster.*
Объём каждого ценового уровня внутри бара с разделением на агрессивные покупки и продажи — те же данные, что рисует кластерный график. Уровни нумеруются снизу вверх, от 0 до cluster.levels - 1.
| Имя | Что возвращает |
|---|---|
cluster.available |
Есть ли кластеры на этом баре |
cluster.levels |
Число ценовых уровней в баре |
cluster.price(i) |
Цена уровня i |
cluster.bid(i) |
Агрессивные покупки на уровне i |
cluster.ask(i) |
Агрессивные продажи на уровне i |
cluster.total |
Весь объём бара |
cluster.delta |
Покупки минус продажи по всем уровням |
cluster.poc, cluster.poc_index |
Цена и номер уровня с наибольшим объёмом |
cluster.max_cell |
Объём самой крупной ячейки бара |
cluster.imbalance(i) |
Перекос уровня: +1 покупки, -1 продажи, 0 нет |
cluster.stacked_buy, cluster.stacked_sell |
Цена, с которой начинается самая длинная серия уровней с перекосом |
cluster.stacked_buy_steps, cluster.stacked_sell_steps |
Длина этой серии в уровнях |
cluster.value_area(pct) |
Нижняя и верхняя граница зоны стоимости; pct — доля объёма, 0.7 = 70 % |
cluster.grid_step |
Шаг ценовой сетки бара |
Обратите внимание на названия: cluster.bid(i) — это покупки, которые «сняли» аск, а не заявки на покупку в стакане.
Кластеры есть на таймфреймах от 30 секунд до одного дня.
indicator("POC и зона стоимости", overlay = true)
[vaLow, vaHigh] = cluster.value_area(0.7)
plot(cluster.poc, "POC", color = color.orange, style = plot.style_circles)
plot(vaHigh, "Верх зоны", color = color.gray, style = plot.style_linebr)
plot(vaLow, "Низ зоны", color = color.gray, style = plot.style_linebr)Дельта: delta.*
Разница между агрессивными покупками и продажами за бар. Объёмы — в монетах (базовой валюте).
| Имя | Что возвращает |
|---|---|
delta.value |
Дельта бара: покупки минус продажи |
delta.buy, delta.sell |
Эти две части по отдельности |
delta.cum |
Накопленная дельта от начала загруженной истории |
delta.min, delta.max |
Минимум и максимум бегущей дельты внутри бара |
delta.open, delta.high, delta.low, delta.close |
Дельта бара в виде свечи |
delta.trades |
Число сделок в баре |
delta.usd |
Дельта в валюте котировки, по суммам самих сделок |
delta.available |
Есть ли дельта на этом баре |
delta.min и delta.max из кластеров не вычислить — это путь дельты внутри бара, его считает сервер. По ним видно, что покупатели вели бар, а закрыли его продавцы. delta.usd точнее, чем delta.value * close: на резком баре цена сделок сильно отличается от цены закрытия.
delta.cum начинается с нуля на первом загруженном баре, поэтому её уровень зависит от глубины загруженной истории. Сравнивайте изменения, а не абсолютные значения.
Дельта есть на таймфреймах от 30 секунд.
indicator("Дельта и разворот внутри бара", overlay = false)
d = delta.value
reversed = delta.available and d < 0 and delta.max > -d
plot(d, "Дельта", style = plot.style_columns, color = d >= 0 ? color.teal : color.red)
plotshape(reversed, "Разворот", style = shape.xcross, location = location.top, color = color.orange, size = size.tiny)Открытый интерес: oi.*
| Имя | Что возвращает |
|---|---|
oi.open, oi.high, oi.low, oi.close |
Открытый интерес за бар в единицах, которые публикует биржа |
oi.coins |
Открытый интерес в монетах |
oi.usd |
Открытый интерес в валюте котировки |
oi.change |
Изменение oi.close к предыдущему бару |
oi.available |
Есть ли данные на этом баре |
Единицы oi.open…oi.close у бирж разные, поэтому для сравнения бирж берите oi.coins или oi.usd. Открытый интерес приходит с минутной сеткой: на секундных таймфреймах все значения — na.
indicator("Цена и открытый интерес", overlay = false)
dp = ta.change(close)
build = oi.available and dp > 0 and oi.change > 0
plot(oi.change, "Изменение OI", style = plot.style_columns, color = build ? color.teal : color.gray)Фандинг: funding.*
| Имя | Что возвращает |
|---|---|
funding.rate |
Прогноз ставки на ближайший расчёт |
funding.interval_hours |
Часов между расчётами |
funding.settled |
true на баре, где прошёл расчёт |
funding.settled_rate |
Ставка, реально списанная на этом баре; если расчётов в баре несколько — их сумма |
funding.cum |
Сумма списанных ставок за загруженную историю |
funding.available |
Есть ли фандинг у инструмента |
Ставка — доля, а не проценты: 0.0001 — это 0,01 %. График показывает проценты, язык ничего не пересчитывает. Для проверки гипотез на истории берите funding.settled_rate: funding.rate — это прогноз, он меняется до самого расчёта. У спота фандинга нет, на секундных таймфреймах значения — na.
indicator("Фандинг за расчёт, %", overlay = false)
plot(funding.rate * 100, "Прогноз ставки", style = plot.style_area, color = funding.rate >= 0 ? color.teal : color.red)
plotshape(funding.settled, "Расчёт", style = shape.circle, location = location.bottom, color = color.orange, size = size.tiny)История стакана: depth.*
Стакан в том виде, в каком его записал сервер, — те же данные, что рисует теплокарта, — разложенный по барам. В отличие от живого book.*, эти значения есть на каждом записанном баре. Цены сгруппированы в корзины, объём корзины — наибольший за бар, в монетах.
| Имя | Что возвращает |
|---|---|
depth.available |
Записан ли стакан для этого бара |
depth.levels |
Число непустых корзин в баре |
depth.price(i) |
Нижняя граница корзины i, по возрастанию |
depth.qty(i) |
Наибольший объём, стоявший в корзине за бар |
depth.side(i) |
+1 биды, -1 аски, 0 корзина была по обе стороны |
depth.at(price) |
Объём в корзине, куда попадает цена |
depth.grid_step |
Размер корзины в единицах цены |
depth.best_bid, depth.best_ask |
Лучшие цены на конец бара |
depth.max_cell |
Объём самой тяжёлой корзины |
depth.bid_sum(pct), depth.ask_sum(pct) |
Объём стороны в пределах pct % от середины |
depth.imbalance(pct) |
Перекос в той же полосе: от -1 до +1 |
depth.max_bid(pct), depth.max_ask(pct) |
Цена и объём самой тяжёлой корзины стороны в полосе |
Ограничения:
- Данные есть там же, где серверная теплокарта, и на таймфреймах от секунды.
- Сервер хранит полосу примерно ±4 % от цены. Вне её
depth.atвозвращаетna, внутри полосы пустая корзина —0. - Глубина истории ограничена: самые старые бары длинной истории дают
na. - Значения формирующегося бара меняются, пока приходят данные.
indicator("Перекос записанного стакана", overlay = false)
band = input.float(1.0, "Полоса, % от цены", minval = 0.1, maxval = 4.0, step = 0.1)
imb = depth.imbalance(band)
plot(imb, "Перекос", style = plot.style_columns, color = imb >= 0 ? color.teal : color.red)Чтобы нарисовать записанный стакан под свечами, достаточно одной строки heatmap.depth() в скрипте с overlay = true. Цвета и пороги поля — на странице Настройки и отрисовка.
indicator("Записанный стакан теплом", overlay = true)
heatmap.config(palette = heatmap.inferno, low = 25)
heatmap.depth()Живой стакан и лента: book.* и tape.*
Живой стакан и ленту никто не записывает, поэтому значения есть только на последнем баре, а на истории — всегда na. Для них нужна открытая панель стакана по тому же инструменту: иначе book.available и tape.available ложны, а в легенде — «нет открытого стакана». В режиме реплея эти данные недоступны.
| Имя | Что возвращает |
|---|---|
book.bid(i), book.ask(i) |
Цена уровня i; 0 — лучшая цена |
book.bid_qty(i), book.ask_qty(i) |
Объём на уровне, в монетах |
book.spread |
Лучший аск минус лучший бид |
book.mid |
Середина между лучшими ценами |
book.imbalance(n) |
Перекос объёма по n верхним уровням каждой стороны: от -1 до +1 |
book.available |
Есть ли снимок стакана |
tape.last_price, tape.last_qty |
Цена и объём последней сделки |
tape.last_side |
+1 покупатель-агрессор, -1 продавец, 0 — сделок ещё не было |
tape.count(ms) |
Число сделок за последние ms миллисекунд |
tape.buy_volume(ms), tape.sell_volume(ms) |
Объём агрессивных покупок и продаж за окно |
tape.max_print(ms) |
Крупнейшая сделка за окно |
tape.available |
Подключена ли лента |
Окно ленты и глубину book.imbalance задают числом в коде или настройкой input.int. Окно отсчитывается от времени последней сделки на бирже, а не от часов компьютера. Скрипту доступен только хвост ленты — около двух тысяч последних сделок, поэтому на активном рынке длинное окно покажет не весь интервал.
Когда такое значение попадает в plot, редактор предупреждает: «Данные есть только в реальном времени — на истории ряд пуст». Это ожидаемо: слева от последнего бара ряд пустой. Стратегии эти данные читать не могут — см. Стратегии и тестер.
indicator("Перекос стакана", overlay = false)
levels = input.int(20, "Уровней с каждой стороны", minval = 1, maxval = 200)
imb = book.available ? book.imbalance(levels) : na
plot(imb, "Перекос", style = plot.style_area, color = imb >= 0 ? color.teal : color.red)
hline(0, "Ноль", color = color.gray)Скринер: screener.*
Метрики скринера для инструмента графика — те же числа, что в его колонках. Истории у них нет: значение есть только на последнем баре. Окно задаётся строкой, и не у каждой метрики есть каждое окно.
| Функция | Что показывает | Окна |
|---|---|---|
screener.change(w) |
Изменение цены | "1m" "5m" "15m" "1h" "24h" |
screener.vol(w) |
Оборот | "1m" "5m" "15m" "1h" "24h" |
screener.avg_vol(w) |
Средний оборот | "1m" "5m" "15m" "1h" |
screener.rvol(w) |
Относительный объём | "1h" "24h" |
screener.natr(w) |
NATR | "1m" "5m" |
screener.oi_delta(w) |
Изменение открытого интереса | "1m" "5m" "1h" "24h" |
screener.btc_corr(w) |
Корреляция с BTC | "1m" "5m" |
screener.available |
Покрыт ли инструмент скринером | — |
Окно, которого нет в таблице, даёт na. Метрика, которая не входит в вашу подписку на скринер, — тоже na. Редактор помечает вывод этих значений тем же предупреждением, что и у стакана: на истории ряд пуст.
indicator("Скринер: RVOL и NATR", overlay = false)
plot(screener.rvol("1h"), "RVOL 1h", color = color.orange)
plot(screener.natr("5m"), "NATR 5m", color = color.teal)Покрытие бирж
| Биржа | Кластеры и дельта | Открытый интерес и фандинг |
|---|---|---|
| Binance, Bybit, OKX, Bitget, Gate.io, MEXC, KuCoin, BingX, AsterDEX | Спот и фьючерсы | Фьючерсы |
| Hyperliquid | Фьючерсы; спот — нет | Фьючерсы |
| Binance Alpha | Нет: биржа не публикует сторону агрессора | Нет |
| Upbit | Нет | Нет |
| Данные | Таймфреймы |
|---|---|
| Кластеры | От 30 секунд до 1 дня |
| Дельта | От 30 секунд |
| Открытый интерес, фандинг | От 1 минуты |
| История стакана | От 1 секунды, там же, где серверная теплокарта |
| Живой стакан, лента | Любые, при открытой панели стакана |
| Скринер | Любые, для инструментов, которые видит скринер |
Покрытие определяет сервер данных, и оно может меняться. Надёжнее всего полагаться на флаг .available и подпись в легенде.
Другой таймфрейм и другой инструмент
request.security считает выражение на другой серии — старшем таймфрейме или другой монете — и сопоставляет результат с барами графика.
request.security(symbol, timeframe, expression, gaps = false, lookahead = false, ignore_invalid_symbol = false)- symbol — в формате «БИРЖА:ТИКЕР», как в TradingView:
"BINANCE:BTCUSDT.P", где.P— бессрочный фьючерс. Инструмент графика —sym.ticker. - timeframe — строка вида
"5","60","4h","1D","1W". Таймфрейм графика —tf.period. - expression — число или несколько чисел в квадратных скобках:
[high, low].
Без заглядывания вперёд. По умолчанию бар графика видит значение последнего закрытого бара старшего таймфрейма. Поэтому часовая EMA на пятиминутках — ступенька, которая сдвигается только на закрытии часа. Так результат на истории совпадает с тем, что вы увидели бы вживую.
gaps = true— значение только на первом баре графика, где появился новый старший бар, дальшеna.ignore_invalid_symbol = true— неизвестный символ даётna. Без этого скрипт останавливается с ошибкой «Символ … неизвестен».
Внутри выражения доступны свечи другой серии и расчёты по ним. Переменную графика туда передать нельзя — только значения настроек input.*. Стакан, лента и скринер внутри запроса не компилируются, а кластеры, дельта, открытый интерес и фандинг другой серии дают na. У скрипта может быть до 8 разных пар «инструмент + таймфрейм» и до 32 вызовов request.security.
indicator("EMA старшего таймфрейма", overlay = true)
len = input.int(20, "Длина EMA", minval = 2, maxval = 500)
tfHigh = input.timeframe("60", "Старший таймфрейм")
emaHigh = request.security(sym.ticker, tfHigh, ta.ema(close, len))
plot(emaHigh, "EMA", color = color.orange, style = plot.style_stepline)indicator("Спред к другой бирже", overlay = false)
other = input.symbol("BYBIT:BTCUSDT.P", "Сравнить с")
px = request.security(other, tf.period, close, ignore_invalid_symbol = true)
plot(close - px, "Разница", color = color.orange)