提升加密资产策略精度:我们在本地维护订单簿深度的实战经验

用户头像sh_****559rtx
2026-06-08 发布

做量化交易的朋友都知道,回测和实盘之间最大的鸿沟,往往不是策略逻辑,而是数据精度。特别是涉及加密货币这类高波动品种时,如果只依赖K线或成交数据,市场微观结构中的很多信号会被完全忽略。过去一年,我们在内部策略研发中全面转向本地订单簿重建,效果非常显著。今天把这一路的经验和同好分享。

痛点:深度数据缺失导致因子失真

举一个真实案例:我们曾开发过一组基于买卖压力的短期反转因子,在第三方数据平台的聚合深度上回测表现极佳,但上线后却出现了严重的滑点和信号滞后。追查之后发现,聚合深度并非来自单一交易所,且更新频率不稳定。当市场剧烈波动时,本地看到的深度已经完全过时。如果你的因子依赖于某个价格档位的挂单量,你必须保证该数据与交易所的实时撮合引擎保持同步。 这就是我们决心自建订单簿同步系统的起点。

数据需求:快照为基,增量驱新

要精确还原交易所订单簿,数据必须满足两条:

  • 初始全量快照:提供某一时刻所有有效挂单。
  • 有序增量更新:包含每一笔导致簿结构变化的事件,且带有严格递增的序号。

我们考察了多种数据渠道,在实际生产中,AllTick 等数据供应商的 WebSocket 推送能够满足快照初始化和增量序列追踪的要求,极大地简化了我们的开发工作量。

本地重建的核心实现

技术上我们选择了 Python 生态里的 SortedDict,它兼具哈希表的快速存取和树结构的有序性,非常适合管理价格队列。

from sortedcontainers import SortedDict

# 买方价格队列,高到低
bids = SortedDict(lambda x: -x)
# 卖方价格队列,低到高
asks = SortedDict()

WebSocket 消息处理模块只做一件事:解析 JSON,遍历 bidsasks 列表,按数量是否为 0 决定增删。代码很精练,但稳定性极佳。

import websocket
import json
from sortedcontainers import SortedDict

bids = SortedDict(lambda x: -x)
asks = SortedDict()

def on_message(ws, message):
    data = json.loads(message)
    # 处理订单簿更新
    process_orderbook(data)

def process_orderbook(data):
    global bids, asks
    for update in data.get("bids", []):
        price, size = update
        if size == 0:
            bids.pop(price, None)
        else:
            bids[price] = size
    for update in data.get("asks", []):
        price, size = update
        if size == 0:
            asks.pop(price, None)
        else:
            asks[price] = size

ws = websocket.WebSocketApp("wss://api.alltick.co/crypto/orderbook",
                            on_message=on_message)
ws.run_forever()

防止“失帧”的序列监测

我们对增量流实施了严格的序列号校验。每处理完一条消息,记录其 ID,下一条必须连续。若发现跳号,立即触发快照重载——宁可短暂丢弃中间状态,也不允许一个错误的价格档位残留在本地簿中。同时,对 WebSocket 连接设置心跳与自动重连,保证 7×24 小时无人值守。

从簿数据到因子

订单簿稳定运行之后,我们可以随时导出任意时刻的快照。利用本地簿,我们构建了不平衡深度、加权买卖均价、订单流毒性等一系列高频因子。举个例子,当卖单深度在某个价位突然增厚,同时买单没有相应反应,这往往预示着短期抛压。

本地数据还能方便地生成可视化报告:

import matplotlib.pyplot as plt

def plot_orderbook():
    plt.plot(list(bids.keys()), list(bids.values()), color='green', label='Bids')
    plt.plot(list(asks.keys()), list(asks.values()), color='red', label='Asks')
    plt.legend()
    plt.show()

由于簿数据完全由自己掌控,因子计算不再受制于第三方聚合偏差,回测与实盘一致性大幅提升。如果社区里的朋友正在折腾高频或微观结构策略,非常建议你投入精力把数据根基打牢——你会发现很多之前难以捉摸的市场规律,一下子变得清晰起来。

6da906de54126200a692ac9ee276ae81.jpg

评论