第二十五讲:订单簿数据源——主流交易所API、数据格式与数据清洗

做量化交易,数据就是你的弹药。订单簿数据更是重中之重。

我个人习惯把订单簿比作市场的「心电图」——每一笔挂单、撤单、成交,都是市场情绪的跳动。今天咱们就聊聊,怎么从交易所拿到这些数据,怎么读懂它们,以及怎么把脏数据洗干净。

一、主流交易所API概览

先说说我常用的几个交易所。说实话,每个交易所的API设计思路都不一样,踩过的坑也不少。

交易所 REST API WebSocket 限频规则
Binance GET /api/v3/depth wss://stream.binance.com:9443/ws 1200次/分钟
OKX GET /api/v5/market/books wss://ws.okx.com:8443/ws/v5/public 20次/秒
Bybit GET /v5/market/orderbook wss://stream.bybit.com/v5/public/linear 50次/秒

嗯,这里要注意:Binance的限频虽然看着宽松,但它的深度快照有大小限制。我记得有一次做高频策略,拉100档深度,结果被限频了——后来才发现,Binance的深度数据分「快照」和「增量」两种模式。

二、数据格式解析

订单簿数据长什么样?说白了就是两个列表:买单(bids)和卖单(asks)。每个列表里是一堆价格-数量对。

举个例子,Binance返回的原始数据是这样的:

{
  "lastUpdateId": 1027024,
  "bids": [
    ["0.0024", "10"],   // 价格,数量
    ["0.0023", "20"]
  ],
  "asks": [
    ["0.0026", "15"],
    ["0.0027", "25"]
  ]
}

你想想看,这个结构其实很直观。但坑在哪里?

  • 价格和数量都是字符串——不是浮点数!我刚开始做的时候直接当float处理,结果精度丢失,亏了一笔小钱。
  • 排序规则:买单按价格降序(价高者优先),卖单按价格升序(价低者优先)。
  • 更新ID:这个字段很重要,用来判断数据是否连续。

核心要点:订单簿数据分为「快照」和「增量」两种。快照是全量数据,增量是变化数据。做实时策略时,必须把两者结合起来。

三、数据清洗实战

数据清洗,说白了就是「去伪存真」。我在项目中遇到过不少奇葩数据,比如价格为零、数量为负、时间戳乱跳……

下面是我常用的清洗流程:

  1. 去重:同一个价格点出现多次,只保留最新一条。
  2. 过滤异常:价格小于等于0、数量小于等于0的直接扔掉。
  3. 排序校验:检查买单是否降序、卖单是否升序。
  4. 时间戳对齐:不同交易所的时间戳格式不同,统一转成毫秒级Unix时间戳。

来看一段Python代码,这是我常用的清洗函数:

def clean_orderbook(raw_data):
    """
    清洗订单簿数据
    raw_data: 交易所返回的原始字典
    """
    cleaned = {
        'bids': [],
        'asks': [],
        'timestamp': int(time.time() * 1000)
    }
    
    # 清洗买单
    for price_str, qty_str in raw_data.get('bids', []):
        price = float(price_str)
        qty = float(qty_str)
        if price > 0 and qty > 0:
            cleaned['bids'].append([price, qty])
    
    # 清洗卖单
    for price_str, qty_str in raw_data.get('asks', []):
        price = float(price_str)
        qty = float(qty_str)
        if price > 0 and qty > 0:
            cleaned['asks'].append([price, qty])
    
    # 排序校验
    cleaned['bids'].sort(key=lambda x: x[0], reverse=True)
    cleaned['asks'].sort(key=lambda x: x[0])
    
    return cleaned

避坑指南:我曾经遇到过某个交易所的WebSocket推送数据,价格字段里居然混入了空格和换行符。后来我加了一层strip()处理,才彻底解决。

四、知识体系图

下面这张图,是我对订单簿数据源整个流程的理解。从交易所API到清洗后的可用数据,每一步都有讲究。

订单簿数据源处理流程 交易所API WebSocket流 历史数据文件 原始数据(JSON格式,含字符串价格/数量) 去重 过滤异常 排序校验 时间戳对齐 清洗后的订单簿数据(可用数据)

五、实战中的注意事项

最后,分享几个我踩过的坑:

  • WebSocket断线重连:别指望连接永远稳定。我建议每次重连后,先拉一次快照,再订阅增量更新。
  • 数据延迟:不同交易所的延迟不一样。Binance的WebSocket延迟通常在10-50ms,OKX稍高一些。做套利策略时,这个差异必须考虑进去。
  • 存储策略:全量数据存起来太占空间。我个人习惯只存增量数据,需要时再重建快照。

小技巧:如果你用Python做数据清洗,推荐用decimal.Decimal代替float处理价格。虽然慢一点,但精度有保障。尤其是做高频策略时,小数点后第8位的差异都可能影响盈亏。

嗯,关于订单簿数据源,今天就聊到这儿。数据清洗这块,说白了就是「慢工出细活」。你花在清洗上的每一分钟,都会在后续的策略回测和实盘交易中回报给你。