跳到主要内容

深度(订单簿)

通道名

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"]]
}
}
字段类型描述
symbolstring交易对标识符,如 DFUSDT
last_update_idinteger快照时刻的引擎单调计数器。用于对齐后续差分 — 参见顺序
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": []
}
}
字段类型描述
symbolstring交易对标识符。
update_id_firstinteger本次差分覆盖的第一个引擎序列号。
update_id_lastinteger本次差分覆盖的最后一个引擎序列号。
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

顺序

  1. 订阅 → 收到 last_update_id = Nspot_depth_snapshot
  2. 开始缓冲后续到达的 spot_depth_diff 帧。
  3. 丢弃所有 update_id_last <= N 的差分。
  4. 应用第一个 update_id_first == N + 1(或 update_id_first <= N + 1 <= update_id_last)的差分。
  5. 按到达顺序应用后续所有差分。
  6. 若某个差分的 update_id_first 大于 last_update_id_applied + 1,说明帧被丢弃 — 重新订阅以获取新快照。

更多细节参见快照与实时同步顺序

推送频率

每次引擎事件导致订单簿变动时,即推送一条 spot_depth_diff

  • 限价单挂单(新增档位或增加已有档位的数量)。
  • 撤单(减少或删除档位)。
  • 成交(减少挂单侧;可能完全删除该档位)。

无固定定时器 — 更新由事件驱动,在引擎事件发生后数毫秒内到达。

代码示例

const ws = new WebSocket('wss://api-sepolia.p99.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;
}