跳到主要内容
版本:Next (V2.0)

本地订单簿维护

通过 WebSocket 增量更新维护本地订单簿,实现低延迟的深度数据访问。

核心概念

字段说明
U首个更新ID (first_update_id) - 本次推送包含的第一个更新
u末尾更新ID (last_update_id) - 本次推送包含的最后一个更新
idREST API 快照返回的序列号(需要 with_id=true

同步流程

  1. 订阅增量更新:订阅 {symbol}@order_book_update
  2. 缓存消息:在获取快照前,缓存收到的所有增量消息
  3. 获取快照:调用 REST API 获取订单簿快照(带序列号)
GET /api/v1/futures/open-api/orderbook/BTCUSDT?depth=100&with_id=true
  1. 处理缓存: 丢弃 u < id + 1 的消息(已过期) 找到 U <= id + 1 && u >= id + 1 的消息开始同步 如果 U > id + 1 说明快照落后,需要重新获取
  2. 持续更新:检查每条消息 U <= lastProcessedId + 1,否则重建

更新规则

  • 数量为 "0" 表示删除该价格档位
  • 数量非零表示更新或新增该价格档位
  • 买单 (b) 按价格从高到低排序
  • 卖单 (a) 按价格从低到高排序

伪代码示例

// 1. 建立 WebSocket 连接并订阅
ws.send(JSON.stringify({
action: 'subscribe',
streams: ['BTCUSDT@order_book_update']
}));

// 2. 缓存收到的增量消息
const buffer = [];
ws.onmessage = (msg) => {
const data = JSON.parse(msg.data);
if (data.action === 'order_book_update') {
buffer.push(data.result);
}
};

// 3. 获取 REST API 快照(带序列号)
const snapshot = await fetch('/api/v1/futures/open-api/orderbook/BTCUSDT?depth=100&with_id=true');
const { bids, asks, id: snapshotId } = snapshot.data;

// 4. 初始化本地订单簿
const orderbook = {
bids: new Map(bids.map(([p, q]) => [p, q])),
asks: new Map(asks.map(([p, q]) => [p, q])),
lastUpdateId: snapshotId
};

// 5. 处理缓存的消息
for (const update of buffer) {
if (update.u < snapshotId + 1) continue;
if (update.U > snapshotId + 1) {
rebuildOrderbook();
break;
}
applyUpdate(update);
}

// 6. 应用增量更新
function applyUpdate(update) {
for (const [price, qty] of update.b) {
if (qty === '0') orderbook.bids.delete(price);
else orderbook.bids.set(price, qty);
}
for (const [price, qty] of update.a) {
if (qty === '0') orderbook.asks.delete(price);
else orderbook.asks.set(price, qty);
}
orderbook.lastUpdateId = update.u;
}

错误处理

错误场景处理方式
WebSocket 断开自动重连,重新订阅,重建订单簿
序列号不连续 (U > lastId + 1)重新获取快照,重建订单簿
快照落后重新获取快照

注意事项

  • 增量推送频率:100ms 聚合一次
  • 价格和数量为字符串类型,避免浮点精度问题
  • 建议定期校验本地订单簿与 REST API 快照的一致性