Перейти к содержимому

WebSocket-стрим

Одно соединение для рыночных данных, счёта, раскладки окон и настроек.

Адрес: ws://127.0.0.1:48180/v1/stream · Файл AsyncAPI

Соединение

  • Адрес: ws://127.0.0.1:48180/v1/stream.
  • Токен передаётся в заголовке Authorization: Bearer <token> рукопожатия. Рукопожатию нужно право market:read. Оно отклоняется по тем же правилам, что HTTP-запрос, с 401 или 403.
  • Сервер шлёт WebSocket-ping каждые 20 с. Если pong не приходит 50 с, сервер закрывает соединение.
  • Когда клиент закрывает соединение, сервер отвечает кадром закрытия с кодом клиента.
  • Закрытие сокета снимает все подписки соединения. Явный unsubscribe снимает подписку сразу.
  • Пара без подписчиков отпускается на бирже через 30 с.

Коды закрытия

КодЗначение
1001API выключили или токен перевыпустили
4008клиент слишком медленный и не успевал дольше 5 с
4029лимит соединений стрима на токен

Лимиты

Лимиты возвращает GET /v1/meta. Отказ — это кадр error с rate_limited в ответ на запрос или закрытие с кодом 4029.

ЛимитЗначение
соединений стрима на токен8
подписок на соединение100
инструментов, открытых только для API50, не считая открытых в окне
новых подписок на биржах в секунду5

Медленные клиенты

Клиент, который не читает, не замедляет ни терминал, ни других клиентов. Кадры, которые он не забрал вовремя, отбрасываются. Для trades кадр gap называет потерянные номера. Для остальных топиков следующий кадр просто новее.

Порядковые номера

seq нумерует события подписки. У trades он растёт на единицу. У топиков, где отправляется только последнее значение, пропуски в номерах — это норма.

Запросы клиента

Что программа отправляет терминалу.

subscribe

Запросить топик.

Что нужно топику, зависит от его семейства:

  • Рыночные топики — это trades, ticker, mark_price, book.top и clusters. instrument обязателен. connection_id выбирается по общему правилу. Право — market:read.
  • Топики счёта — это account.*. connection_id обязателен. instrument не используется. Право — account:read.
  • workspace и settings не принимают ни того, ни другого. Права — workspace:read и settings:read.

Только book.top использует params. Остальные топики их игнорируют.

ПолеТипОписание
typeобязательное"subscribe"
request_idstringНеобязателен. Возвращается в ответе как есть.
topicобязательноеTopic
instrumentstringАдрес инструмента, exchange:market:symbol. Обязателен для рыночных топиков.
connection_idintegerОбязателен для топиков счёта. Необязателен для рыночных топиков.
paramsobjectПараметры book.top.
params.depthintegerЧисло уровней с каждой стороны. Range: 1–200. По умолчанию: 50.
params.interval_msintegerМинимальное время между двумя кадрами, миллисекунды. Range: ≥ 50. По умолчанию: 100.
Trades of a pair
{
  "type": "subscribe",
  "request_id": "r1",
  "topic": "trades",
  "instrument": "binance:futures:BTCUSDT",
  "connection_id": 12
}
Top of the book, 10 levels every 250 ms
{
  "type": "subscribe",
  "request_id": "r2",
  "topic": "book.top",
  "instrument": "binance:futures:BTCUSDT",
  "params": {
    "depth": 10,
    "interval_ms": 250
  }
}
Fills of a connection
{
  "type": "subscribe",
  "request_id": "r3",
  "topic": "account.fills",
  "connection_id": 12
}
The layout of the windows
{
  "type": "subscribe",
  "request_id": "r4",
  "topic": "workspace"
}

unsubscribe

Снять подписку.

Принимает только sub, возвращённый в subscribed.

ПолеТипОписание
typeобязательное"unsubscribe"
request_idstring
subобязательноеstringИдентификатор из subscribed.
Пример
{
  "type": "unsubscribe",
  "request_id": "r5",
  "sub": "7:trades"
}

Кадры сервера

Что терминал отвечает и присылает сам, кроме событий.

subscribed

Подписка заведена.

sub обозначает подписку во всех следующих кадрах. Это "{stream}:{topic}" у рыночных топиков, "{connection}:account.<topic>" у топиков счёта и "workspace" или "settings" у двух остальных. Все клиенты, подписанные на одну пару и топик, получают один и тот же sub. connection_id есть у рыночных топиков и топиков счёта. У workspace и settings его нет.

ПолеТипОписание
typeобязательное"subscribed"
request_idstring
subобязательноеstring
connection_idintegerВыбранное подключение. Отсутствует у workspace и settings.
Пример
{
  "type": "subscribed",
  "request_id": "r1",
  "sub": "7:trades",
  "connection_id": 12
}

unsubscribed

Подписка снята.

ПолеТипОписание
typeобязательное"unsubscribed"
request_idstring
subобязательноеstring
Пример
{
  "type": "unsubscribed",
  "request_id": "r5",
  "sub": "7:trades"
}

error

Запрос отклонён либо подписка снята сервером.

С request_id это ответ на запрос клиента. С sub и без request_id — подписку снял сервер. Коды — те же, что у HTTP-операций.

ПолеТипОписание
typeобязательное"error"
request_idstringПрисутствует, когда кадр отвечает на запрос.
substringПрисутствует, когда кадр относится к подписке.
codeобязательноеErrorCode
messageобязательноеstringТекст для человека.
A refused request
{
  "type": "error",
  "request_id": "r1",
  "code": "not_found",
  "message": "no connection for the instrument"
}
A subscription removed by the server
{
  "type": "error",
  "sub": "7:trades",
  "code": "unavailable",
  "message": "the exchange refused the subscription"
}

gap

Сделки, которые потерял клиент.

Отправляется только для trades, перед первым кадром после потери. Клиент не читал, и события с from_seq по to_seq потеряны. Прочитайте их ещё раз через GET /v1/market/trades с since_ts.

ПолеТипОписание
typeобязательное"gap"
subобязательноеstring
from_seqобязательноеinteger
to_seqобязательноеinteger
reasonобязательноеstringslow_consumer.
Пример
{
  "type": "gap",
  "sub": "7:trades",
  "from_seq": 42,
  "to_seq": 57,
  "reason": "slow_consumer"
}

Топики

У всех событий один конверт; data зависит от топика.

ПолеТипОписание
typeобязательное"event"
subобязательноеstringПодписка, к которой относится событие.
seqобязательноеintegerНомер события в подписке.
tsобязательноеintegerКогда кадр собран, миллисекунды UTC.
dataобязательноеanyДанные события. Их форма зависит от топика.
ТопикТребуетПравоДоставка
tradesinstrumentmarket:readпо порядку, о пропусках сообщается
tickerinstrumentmarket:readтолько последнее значение
mark_priceinstrumentmarket:readтолько последнее значение
book.topinstrumentmarket:readтолько последнее значение
clustersinstrumentmarket:readтолько последнее значение
account.ordersconnection_idaccount:readтолько последнее значение
account.positionsconnection_idaccount:readтолько последнее значение
account.balancesconnection_idaccount:readтолько последнее значение
account.fillsconnection_idaccount:readкадр на каждое событие
workspaceничегоworkspace:readтолько последнее значение
settingsничегоsettings:readкадр на каждое событие

trades

Сделки пары, по порядку.

data — массив сделок, как в GET /v1/market/trades. Сделки идут по порядку. Если клиент отстаёт, кадр gap называет, что потеряно.

Данные: Trade[]

Пример
{
  "type": "event",
  "sub": "7:trades",
  "seq": 41,
  "ts": 1730294400130,
  "data": [
    {
      "id": null,
      "price": "67000.1",
      "qty": "0.012",
      "side": "buy",
      "ts": 1730294400125,
      "exchange_ts": 1730294400119
    }
  ]
}

ticker

Суточный тикер пары.

data — тикер, как ticker в GET /v1/market/snapshot. Отправляется только последнее значение.

Данные: Ticker

Пример
{
  "type": "event",
  "sub": "7:ticker",
  "seq": 12,
  "ts": 1730294400130,
  "data": {
    "price": "67000.1",
    "change_24h_pct": "1.25",
    "volume_24h": "81234.5",
    "high_24h": null,
    "low_24h": null,
    "best_bid": null,
    "best_ask": null,
    "ts": 1730294400120
  }
}

mark_price

Цена маркировки (mark) пары.

Отправляется только последнее значение.

Данные: MarkPrice

Пример
{
  "type": "event",
  "sub": "7:mark_price",
  "seq": 5,
  "ts": 1730294400130,
  "data": {
    "mark_price": "67001.0",
    "ts": 1730294400120
  }
}

book.top

Верхушка стакана пары.

Каждый подписчик задаёт свои depth и interval_ms. Значения вне границ отклоняются с invalid_request. Первый кадр приходит, как только стакан готов. Дальше приходит не больше одного кадра за interval_ms, с последним стаканом. seq — версия стакана.

Данные: BookTop

Пример
{
  "type": "event",
  "sub": "7:book.top",
  "seq": 9031,
  "ts": 1730294400130,
  "data": {
    "ts": 1730294400123,
    "depth": 10,
    "bids": [
      [
        "67000.1",
        "1.25"
      ]
    ],
    "asks": [
      [
        "67000.2",
        "0.40"
      ]
    ]
  }
}

clusters

Кластеры объёма инструмента.

data — один бакет, как элемент data в GET /v1/market/clusters. Кадр приходит по каждому изменившемуся бакету, не чаще раза в 16 мс, с его последним состоянием. Смена интервала в терминале видна в interval.

Данные: ClusterBucket

account.orders

Заявки и триггерные заявки одного инструмента после изменения.

Отправляется только последнее состояние инструмента. Подписка не обращается к бирже, и события идут с того момента, как их присылает подключение. Кадра-снимка при подписке нет. Текущее состояние читайте через GET /v1/account/orders.

Данные: InstrumentOrders

account.positions

Позиция одного инструмента после изменения.

Отправляется только последнее состояние. Закрытая позиция приходит как "position": null. Кадра-снимка при подписке нет.

Данные: InstrumentPosition

account.balances

Баланс одной валюты.

data — один баланс, как элемент data в GET /v1/account/balances. Отправляется только последнее значение. Кадра-снимка при подписке нет.

Данные: Balance

account.fills

Одно исполнение.

Один кадр на исполнение. Если клиент отстаёт, кадр теряется, и seq показывает пропуск. Прочитайте исполнения ещё раз через GET /v1/account/fills с since_ts.

Данные: Fill

workspace

Раскладка окон целиком.

data — раскладка, как data в GET /v1/workspace. Первый кадр — текущая раскладка, он отправляется сразу при подписке. Дальше кадр приходит на каждое изменение. Отправляется только последнее состояние.

Данные: WorkspaceSnapshot

settings

Одна записанная строка настроек.

Один кадр на каждую запись в таблицу настроек: из API, из Settings App и из самого окна. Снимка при подписке нет. Текущие значения читайте через GET /v1/settings. Если клиент отстаёт, кадр теряется, и seq показывает пропуск.

Данные: SettingWritten

Пример
{
  "type": "event",
  "sub": "settings",
  "seq": 3,
  "ts": 1730294400130,
  "data": {
    "scope": "global",
    "scope_id": "default",
    "connection_id": null,
    "category": "multiview",
    "key": "stack_width_px",
    "value": 300
  }
}

Типы данных

Объекты, которые несут события. Те же объекты возвращают операции HTTP.

Topic

tradestickermark_pricebook.topclustersaccount.ordersaccount.positionsaccount.balancesaccount.fillsworkspacesettings

ErrorCode

unauthorizedforbiddenforbidden_scopenot_foundinvalid_requestunsupportednot_activenot_tradablerate_limitedunavailable

Стабильный код, часть контракта. Могут добавляться новые коды.

КодHTTPКогда
unauthorized401токен неверный или API выключен
forbidden403заголовок Origin или чужой Host
forbidden_scope403у токена нет права этой операции
not_found404нет такой операции или подключения, или для инструмента нет подключения
invalid_request400неверный параметр: инструмент, интервал, глубина, чужой connection_id
unsupported501биржа — MOEX, терминал собран без рыночных данных, или настройка не пишется через API
not_active409кластеры инструмента ещё не посчитаны, или его плечо ещё не загружено
not_tradable409подключение не может торговать: оно выключено, только для чтения или без учётных данных
rate_limited429превышен лимит: соединений, подписок, инструментов, новых подписок в секунду, торговых команд, команд рабочего пространства или записей настроек
unavailable503хранилище, биржа или окно не ответили, терминал занят, или данных ещё нет

Trade

ПолеТипОписание
idобязательноеstring | nullВ v1 всегда null.
priceобязательноеstring
qtyобязательноеstring
sideобязательное"buy" | "sell"
tsобязательноеintegerКогда терминал получил сделку, миллисекунды UTC.
exchange_tsобязательноеintegerВремя биржи.

Ticker

Суточный тикер.

ПолеТипОписание
priceобязательноеstring
change_24h_pctобязательноеstring | null
volume_24hобязательноеstring
high_24hобязательноеstring | null
low_24hобязательноеstring | null
best_bidобязательноеstring | null
best_askобязательноеstring | null
tsобязательноеinteger

MarkPrice

ПолеТипОписание
mark_priceобязательноеstring
tsобязательноеinteger

BookTop

Верхушка стакана: биды от лучшей цены вниз, аски от лучшей цены вверх.

ПолеТипОписание
tsобязательноеinteger
depthобязательноеinteger
bidsобязательноеPriceLevel[]
asksобязательноеPriceLevel[]

ClusterBucket

ПолеТипОписание
intervalобязательноеstring
tsобязательноеintegerНачало бакета, миллисекунды UTC.
end_tsобязательноеinteger
volumeобязательноеstring
buy_volumeобязательноеstring
sell_volumeобязательноеstring
tradesобязательноеinteger
vwapобязательноеstring | null
min_priceобязательноеstring | null
max_priceобязательноеstring | null
completedобязательноеboolean
last_trade_tsобязательноеintegerВремя последней сделки бакета. 0 у бакета из истории, у которого такого времени нет.
levelsобязательноеClusterLevel[]Все ценовые уровни бакета, от низшей цены к высшей.

InstrumentOrders

ПолеТипОписание
instrumentобязательноеstring
ordersобязательноеOrder[]
triggersобязательноеTrigger[]

InstrumentPosition

ПолеТипОписание
instrumentобязательноеstring
positionобязательноеPosition | null

Balance

ПолеТипОписание
currencyобязательноеstring
totalобязательноеstring
availableобязательноеstring | null
lockedобязательноеstring | null
tsобязательноеinteger

Fill

ПолеТипОписание
trade_idобязательноеstring
order_idобязательноеstringБиржевой id заявки.
instrumentобязательноеstring
sideобязательноеstringbuy или sell.
priceобязательноеstring
qtyобязательноеstring
feeобязательноеstring
fee_currencyобязательноеstring
position_sideобязательноеstring | nulllong или short на биржах с режимом хеджирования, иначе null.
tsобязательноеintegerВремя биржи.

WorkspaceSnapshot

ПолеТипОписание
windowsобязательноеWindow[]По возрастанию id.

SettingWritten

Строка настроек, как она записана, без writable.

ПолеТипОписание
scopeобязательноеstring
scope_idобязательноеstring | null
connection_idобязательноеinteger | null
categoryобязательноеstring
keyобязательноеstring
valueобязательноеanyЛюбое значение JSON.

PriceLevel

string[]

[price, size], оба значения — десятичные строки.

ClusterLevel

ПолеТипОписание
priceобязательноеstring
volumeобязательноеstring
buy_volumeобязательноеstring
sell_volumeобязательноеstring
buy_tradesобязательноеinteger
sell_tradesобязательноеinteger

Order

ПолеТипОписание
keyобязательноеstring | nullКлюч заявки в терминале, t-…. null, пока он неизвестен.
exchange_idобязательноеstring | nullБиржевой id заявки. null, пока биржа не приняла заявку.
instrumentобязательноеstring
sideобязательное"buy" | "sell"
typeобязательное"limit" | "market"
priceобязательноеstring
sizeобязательноеstringВ базовой монете.
filledобязательноеstring
remainingобязательноеstring
notionalобязательноеstring | nullСумма в валюте котировки, которую ввёл трейдер. null у заявки из снимка биржи.
statusобязательное"pending" | "open" | "partially_filled"
created_tsобязательноеinteger | nullnull, если заявка пришла из снимка биржи без времени.

Trigger

ПолеТипОписание
idобязательноеstringЧисловой id, по которому триггер снимают и меняют.
instrumentобязательноеstring
typeобязательноеTriggerKind
trigger_priceобязательноеstring
ruleобязательноеTriggerRule
sizeобязательноеstring | nullВ базовой монете.
notionalобязательноеstring | nullВ валюте котировки.
statusобязательное"open" | "finished" | "inactive" | "invalid"
order_typeобязательноеstring | nullТип заявки биржи, как пришёл.
client_idобязательноеstring | nullКлюч, возвращённый при постановке триггера.
created_tsобязательноеinteger | null

Position

ПолеТипОписание
instrumentобязательноеstring
sideобязательное"long" | "short"
sizeобязательноеstringВ базовой монете.
lot_sizeобязательноеstringБазовых единиц в одном лоте.
entry_priceобязательноеstring
notionalобязательноеstringВ валюте котировки.
unrealized_pnlобязательноеstringКак считает терминал.
mark_priceобязательноеstring | nullЛучший bid для лонга, лучший ask для шорта. null до первого тика стакана.

Window

ПолеТипОписание
idобязательноеinteger
mainобязательноеbooleanГлавное окно. Его закрытие завершает терминал.
chart_windowобязательноеbooleanВынесенное окно графиков.
focusedобязательноеbooleanОкно в фокусе ОС.
geometryобязательноеobjectПоложение и размер в логических пикселях экрана.
geometry.xобязательноеinteger
geometry.yобязательноеinteger
geometry.widthобязательноеinteger
geometry.heightобязательноеinteger
geometry.maximizedобязательноеboolean
monitorобязательноеstring | nullИмя монитора по данным ОС.
tabsобязательноеTab[]

TriggerKind

stop_losstake_profitstop

TriggerRule

price_above_or_equalprice_below_or_equal

Tab

ПолеТипОписание
idобязательноеintegerНумеруется в каждом окне с единицы.
nameобязательноеstring
activeобязательноеbooleanВ окне активна ровно одна вкладка.
stacksобязательноеStack[]
chartsобязательноеChart[]

Stack

Стакан с лентой сделок и кластерами.

ПолеТипОписание
widget_idобязательноеinteger
instrumentобязательноеstring | nullnull, пока стек пуст.
connection_idобязательноеinteger | null
emptyобязательноеboolean
frozenобязательноеbooleanСтек заморожен.
positionобязательноеCell | null

Chart

ПолеТипОписание
widget_idобязательноеinteger
instrumentобязательноеstring | null
connection_idобязательноеinteger | null
intervalобязательноеstringИнтервал свечей: 1m, 5m, …
owner_widget_idобязательноеinteger | nullСтек, за которым следует график. null у самостоятельного графика.
positionобязательноеCell | null

Cell

Ячейка сетки вкладки: колонка слева, строка сверху, ячейка внутри строки.

ПолеТипОписание
columnобязательноеinteger
rowобязательноеinteger
cellобязательноеinteger

На этой странице