数据采集与存储:WebSocket实时订阅、REST API历史数据拉取、Parquet与HDF5存储格式选择

做市商这个行当,说白了就是跟时间赛跑。

你比别人快1毫秒,可能就多赚一笔。你比别人慢1毫秒,可能就被对手盘吃掉。所以数据采集和存储,是整个策略的命门。我见过太多团队,策略模型写得漂漂亮亮,结果数据链路一塌糊涂,实盘跑起来直接崩掉。

今天咱们就把这块硬骨头啃下来。

一、实时数据订阅:WebSocket才是王道

做市商需要实时盯盘口。盘口数据变化极快,每秒可能几百次甚至上千次。用REST API轮询?别闹了,那玩意儿延迟太高,而且容易被交易所限流。

我个人习惯,所有实时数据都用WebSocket。它建立一次连接,服务端主动推送,延迟通常在1-10毫秒以内。

核心要点:WebSocket是长连接,一旦建立,双方可以随时互发消息。做市商策略订阅的是「深度增量」而非「全量快照」。

举个例子,币安的WebSocket深度流:

import websocket
import json

def on_message(ws, message):
    data = json.loads(message)
    # 处理增量数据
    bids = data['b']  # 买单
    asks = data['a']  # 卖单
    # 更新本地订单簿
    update_orderbook(bids, asks)

def on_error(ws, error):
    print(f"连接异常: {error}")
    # 自动重连逻辑
    reconnect()

ws = websocket.WebSocketApp(
    "wss://stream.binance.com:9443/ws/btcusdt@depth20@100ms",
    on_message=on_message,
    on_error=on_error
)
ws.run_forever()

这里有个坑,我曾经踩过。交易所的WebSocket偶尔会断连,或者推送的数据包顺序错乱。你想想看,如果本地订单簿更新顺序错了,整个策略就废了。

避坑指南:一定要实现「序列号校验」和「自动重连」机制。每个数据包都带一个递增的序列号,本地校验,发现跳跃或重复就重新拉取全量快照。

二、历史数据拉取:REST API的优雅用法

实时数据搞定了,但策略回测、模型训练都需要历史数据。这时候REST API就派上用场了。

REST API的特点是「请求-响应」模式。你发一个请求,它返回一段数据。适合拉取过去几小时、几天甚至几个月的数据。

我一般这样设计拉取逻辑:

  1. 确定时间范围:比如从2024-01-01到2024-06-30
  2. 分片拉取:每次只拉取1小时的数据,避免请求超时
  3. 并发控制:交易所通常有频率限制,比如每秒最多10次请求
  4. 断点续传:记录上次拉取到的位置,中断后可以继续
import requests
import time
from datetime import datetime, timedelta

def fetch_klines(symbol, start_time, end_time):
    url = "https://api.binance.com/api/v3/klines"
    all_data = []
    current = start_time
    
    while current < end_time:
        params = {
            'symbol': symbol,
            'interval': '1m',
            'startTime': int(current.timestamp() * 1000),
            'limit': 1000
        }
        resp = requests.get(url, params=params)
        data = resp.json()
        
        if not data:
            break
            
        all_data.extend(data)
        # 更新当前时间到最后一根K线的时间
        current = datetime.fromtimestamp(data[-1][0] / 1000) + timedelta(minutes=1)
        time.sleep(0.1)  # 控制请求频率
    
    return all_data

小技巧:拉取历史数据时,建议用「异步IO」+「信号量」来控制并发。我常用 asyncio + aiohttp,比同步请求快10倍以上。

三、存储格式选择:Parquet vs HDF5

数据拉下来了,存哪儿?怎么存?

做市商的数据量巨大。一个币种,一天就有1440根1分钟K线,加上盘口快照,轻松上百万条记录。存成CSV?那玩意儿又慢又占空间。

我主要用两种格式:ParquetHDF5。它们都是列式存储,压缩率高,读取快。

特性 Parquet HDF5
压缩率 极高(Snappy/ZSTD) 高(GZIP/LZF)
读取速度 快(列裁剪、谓词下推) 快(支持分块读取)
生态兼容 Pandas、Spark、Dask Pandas、NumPy、PyTorch
适用场景 大规模数据分析、数据湖 科学计算、深度学习
元数据管理 弱(依赖外部目录) 强(内置层级结构)

我个人习惯:

  • 盘口快照数据:用Parquet。因为盘口数据字段多(几十档买卖单),Parquet的列裁剪能只读取需要的列,节省大量IO。
  • K线数据:用HDF5。因为K线数据通常需要按时间序列分析,HDF5支持高效的切片和索引。
  • 策略回测结果:用Parquet。方便后续用Spark或Dask做大规模回测。

我的经验:曾经有个项目,盘口数据每天产生50GB。用CSV存,查询一次要5分钟。换成Parquet后,同样的查询只要3秒。压缩后存储空间从50GB降到8GB。这差距,你品品。

四、知识体系总览

说了这么多,咱们用一张图把整个数据采集与存储的脉络理清楚。

做市商数据采集与存储体系 交易所数据源 WebSocket 实时订阅 REST API 历史拉取 盘口快照 / 深度增量 K线数据 / 成交明细 Parquet 列式存储 HDF5 层级存储 策略回测 / 模型训练 / 实盘监控

这张图把整个流程串起来了。从交易所数据源出发,实时数据走WebSocket,历史数据走REST API。采集到的盘口数据和K线数据,分别用Parquet和HDF5存储。最终服务于策略回测、模型训练和实盘监控。

最后说一句:数据采集和存储是地基。地基不稳,楼盖得再高也得塌。我建议你在正式跑策略之前,花一周时间把数据链路彻底测试一遍。模拟各种异常场景——断网、数据延迟、格式错误——确保系统能自动恢复。

嗯,今天就到这儿。记住,做市商拼的不是策略有多复杂,而是数据有多干净、链路有多稳定。


公众号:蓝海资料掘金营,微信deep3321