深度(订单簿)
通道名
spot:depth:{symbol}
鉴权:不需要(公开通道)。
描述
订阅时推送完整的订单簿快照,此后每次订单簿变动(挂单、撤单或成交)均推送增量差分。每次差分只包含发生变化的档位 — 未变动的档位不会重复出现。
订阅
发送:
{ "type": "subscribe", "channel": "spot:depth:DFUSDT" }
服务端先返回 subscribed 确认,随即发送初始快照:
{ "type": "subscribed", "channel": "spot:depth:DFUSDT" }
紧接着:
{
"type": "spot_depth_snapshot",
"channel": "spot:depth:DFUSDT",
"data": {
"symbol": "DFUSDT",
"last_update_id": 12345,
"bids": [
["0.5000", "100"],
["0.4999", "200"],
["0.4998", "500"]
],
"asks": [
["0.5001", "150"],
["0.5002", "180"],
["0.5003", "300"]
]
}
}
推送格式
spot_depth_snapshot
订阅后发送一次,紧随 subscribed 确认之后。每侧最多包含 1000 档。
{
"type": "spot_depth_snapshot",
"channel": "spot:depth:DFUSDT",
"data": {
"symbol": "DFUSDT",
"last_update_id": 12345,
"bids": [["0.5000", "100"], ["0.4999", "200"]],
"asks": [["0.5001", "150"], ["0.5002", "180"]]
}
}
| 字段 | 类型 | 描述 |
|---|---|---|
symbol | string | 交易对标识符,如 DFUSDT。 |
last_update_id | integer | 快照时刻的引擎单调计数器。用于对齐后续差分 — 参见顺序。 |
bids | [price, qty][] | 所有挂单买档,最优价格优先。两个值均为字符串。 |
asks | [price, qty][] | 所有挂单卖档,最优价格优先。两个值均为字符串。 |
spot_depth_diff
每次订单簿变动时推送,只包含已变化的档位。
{
"type": "spot_depth_diff",
"channel": "spot:depth:DFUSDT",
"data": {
"symbol": "DFUSDT",
"update_id_first": 12346,
"update_id_last": 12346,
"bids": [["0.5000", "70"]],
"asks": []
}
}
| 字段 | 类型 | 描述 |
|---|---|---|
symbol | string | 交易对标识符。 |
update_id_first | integer | 本次差分覆盖的第一个引擎序列号。 |
update_id_last | integer | 本次差分覆盖的最后一个引擎序列号。 |
bids | [price, qty][] | 变化的买档。qty == "0" 表示该档位已清空 — 从本地订单簿中删除。 |
asks | [price, qty][] | 变化的卖档。删除规则同上。 |
示例:一笔成交吃掉一个卖档并部分减少另一个。
{
"type": "spot_depth_diff",
"channel": "spot:depth:DFUSDT",
"data": {
"symbol": "DFUSDT",
"update_id_first": 12347,
"update_id_last": 12347,
"bids": [],
"asks": [
["0.5001", "0"],
["0.5002", "80"]
]
}
}
"0.5001" 被删除(qty = "0");"0.5002" 更新为 80。
顺序
- 订阅 → 收到
last_update_id = N的spot_depth_snapshot。 - 开始缓冲后续到达的
spot_depth_diff帧。 - 丢弃所有
update_id_last <= N的差分。 - 应用第一个
update_id_first == N + 1(或update_id_first <= N + 1 <= update_id_last)的差分。 - 按到达顺序应用后续所有差分。
- 若某个差分的
update_id_first大于last_update_id_applied + 1,说明帧被丢弃 — 重新订阅以获取新快照。
更多细节参见快照与实时同步顺序。
推送频率
每次引擎事件导致订单簿变动时,即推送一条 spot_depth_diff:
- 限价单挂单(新增档位或增加已有档位的数量)。
- 撤单(减少或删除档位)。
- 成交(减少挂单侧;可能完全删除该档位)。
无固定定时器 — 更新由事件驱动,在引擎事件发生后数毫秒内到达。
代码示例
const ws = new WebSocket('wss://api.prex.world/ws');
let localBook = { bids: new Map(), asks: new Map() };
let snapshotId = null;
let pendingDiffs = [];
ws.onopen = () => {
ws.send(JSON.stringify({ type: 'subscribe', channel: 'spot:depth:DFUSDT' }));
setInterval(() => ws.send(JSON.stringify({ type: 'ping' })), 30000);
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.type === 'spot_depth_snapshot') {
// Seed local book
localBook.bids = new Map(msg.data.bids.map(([p, q]) => [p, q]));
localBook.asks = new Map(msg.data.asks.map(([p, q]) => [p, q]));
snapshotId = msg.data.last_update_id;
// Apply any buffered diffs
for (const diff of pendingDiffs) applyDiff(diff);
pendingDiffs = [];
}
if (msg.type === 'spot_depth_diff') {
if (snapshotId === null) {
pendingDiffs.push(msg.data);
return;
}
if (msg.data.update_id_last <= snapshotId) return; // stale, discard
applyDiff(msg.data);
}
};
function applyDiff(diff) {
for (const [price, qty] of diff.bids) {
if (qty === '0') localBook.bids.delete(price);
else localBook.bids.set(price, qty);
}
for (const [price, qty] of diff.asks) {
if (qty === '0') localBook.asks.delete(price);
else localBook.asks.set(price, qty);
}
snapshotId = diff.update_id_last;
}