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 с.
Коди закриття
| Код | Значення |
|---|---|
1001 | API вимкнено або токен перевипущено |
4008 | клієнт надто повільний і не встигав довше ніж 5 с |
4029 | ліміт з’єднань стріму на токен |
Ліміти
GET /v1/meta повертає ліміти. Відмова — це кадр error з
rate_limited у відповідь на запит або закриття з кодом 4029.
| Ліміт | Значення |
|---|---|
| з’єднань стріму на токен | 8 |
| підписок на з’єднання | 100 |
| інструментів, відкритих лише для API | 50, не рахуючи відкритих у вікні |
| нових підписок на біржах на секунду | 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_id | string | Необов’язковий. Повертається у відповіді без змін. |
topicобов’язкове | Topic | |
instrument | string | Адреса інструмента, exchange:market:symbol. Обов’язкова для ринкових топіків. |
connection_id | integer | Обов’язковий для топіків рахунку. Необов’язковий для ринкових топіків. |
params | object | Параметри book.top. |
params.depth | integer | Рівнів з кожного боку. Range: 1–200. За замовчуванням: 50. |
params.interval_ms | integer | Найменший час між двома кадрами, мілісекунди. Range: ≥ 50. За замовчуванням: 100. |
{
"type": "subscribe",
"request_id": "r1",
"topic": "trades",
"instrument": "binance:futures:BTCUSDT",
"connection_id": 12
}{
"type": "subscribe",
"request_id": "r2",
"topic": "book.top",
"instrument": "binance:futures:BTCUSDT",
"params": {
"depth": 10,
"interval_ms": 250
}
}{
"type": "subscribe",
"request_id": "r3",
"topic": "account.fills",
"connection_id": 12
}{
"type": "subscribe",
"request_id": "r4",
"topic": "workspace"
}unsubscribe
Зняти підписку.
Приймає лише sub, повернутий у subscribed.
| Поле | Тип | Опис |
|---|---|---|
typeобов’язкове | "unsubscribe" | |
request_id | string | |
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_id | string | |
subобов’язкове | string | |
connection_id | integer | Вибране підключення. Відсутнє для workspace і settings. |
{
"type": "subscribed",
"request_id": "r1",
"sub": "7:trades",
"connection_id": 12
}unsubscribed
Підписку знято.
| Поле | Тип | Опис |
|---|---|---|
typeобов’язкове | "unsubscribed" | |
request_id | string | |
subобов’язкове | string |
{
"type": "unsubscribed",
"request_id": "r5",
"sub": "7:trades"
}error
Запит відхилено або підписку знято сервером.
З request_id кадр відповідає на запит клієнта. З sub і без request_id — сервер зняв підписку. Коди — це коди HTTP-операцій.
| Поле | Тип | Опис |
|---|---|---|
typeобов’язкове | "error" | |
request_id | string | Присутній, коли кадр відповідає на запит. |
sub | string | Присутній, коли кадр стосується підписки. |
codeобов’язкове | ErrorCode | |
messageобов’язкове | string | Текст для людини. |
{
"type": "error",
"request_id": "r1",
"code": "not_found",
"message": "no connection for the instrument"
}{
"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обов’язкове | string | slow_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 | Дані події. Їхня форма залежить від топіка. |
| Топік | Потребує | Право | Доставка |
|---|---|---|---|
trades | instrument | market:read | за порядком, про пропуски повідомляється |
ticker | instrument | market:read | лише останнє значення |
mark_price | instrument | market:read | лише останнє значення |
book.top | instrument | market:read | лише останнє значення |
clusters | instrument | market:read | лише останнє значення |
account.orders | connection_id | account:read | лише останнє значення |
account.positions | connection_id | account:read | лише останнє значення |
account.balances | connection_id | account:read | лише останнє значення |
account.fills | connection_id | account: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
24-годинний тікер пари.
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 | Коли |
|---|---|---|
unauthorized | 401 | токен неправильний або API вимкнено |
forbidden | 403 | заголовок Origin або чужий Host |
forbidden_scope | 403 | токен не має права операції |
not_found | 404 | такої операції чи підключення немає, або для інструмента немає підключення |
invalid_request | 400 | неправильний параметр: інструмент, інтервал, глибина, чужий connection_id |
unsupported | 501 | біржа — MOEX, термінал зібрано без ринкових даних, або налаштування не записується через API |
not_active | 409 | кластери інструмента ще не обчислено, або його плече ще не завантажено |
not_tradable | 409 | підключення не може торгувати: воно вимкнене, лише для читання або не має облікових даних |
rate_limited | 429 | перевищено ліміт: з’єднань, підписок, інструментів, нових підписок на секунду, торгових команд, команд робочого простору або записів налаштувань |
unavailable | 503 | сховище, біржа або вікно не відповіли, термінал зайнятий, або даних ще немає |
Trade
| Поле | Тип | Опис |
|---|---|---|
idобов’язкове | string | null | У v1 завжди null. |
priceобов’язкове | string | |
qtyобов’язкове | string | |
sideобов’язкове | "buy" | "sell" | |
tsобов’язкове | integer | Коли термінал отримав угоду, мілісекунди UTC. |
exchange_tsобов’язкове | integer | Час біржі. |
Ticker
24-годинний тікер.
| Поле | Тип | Опис |
|---|---|---|
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
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 | Ідентифікатор заявки на біржі. |
instrumentобов’язкове | string | |
sideобов’язкове | string | buy або sell. |
priceобов’язкове | string | |
qtyобов’язкове | string | |
feeобов’язкове | string | |
fee_currencyобов’язкове | string | |
position_sideобов’язкове | string | null | long або 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 | Ідентифікатор заявки на біржі. 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 | null | null для заявки зі знімка біржі, яка не має часу. |
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
Stack
Стакан зі стрічкою угод і кластерами.
| Поле | Тип | Опис |
|---|---|---|
widget_idобов’язкове | integer | |
instrumentобов’язкове | string | null | null, поки стек порожній. |
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 |
Налаштування стакана для інструмента GET
Налаштування стакана інструмента такими, як їх бачить стек цього підключення, за категорією і ключем. Значення береться з першого місця, де воно є: рядок пари на підключенні, типове значення підключення, рядок пари без підключення, глобальне типове значення. `resolved_from` називає це місце.
Python SDK
Клієнт, стрім, пошук термінала й помилки пакета spectre-terminal.