2、数据源接入:交易所API对接、WebSocket实时行情、RESTful历史数据

做市商这行,说白了就是跟数据打交道。你策略再牛,模型再漂亮,数据源接不进来,一切都是白搭。我刚开始做量化那会儿,就吃过这个亏——花了两周搭了一套做市策略,结果上线第一天,行情推送延迟了三秒,直接被对手盘吃干净了。嗯,从那以后,我对数据源接入这块就特别较真。

今天咱们就聊聊数据源接入的三个核心环节:交易所API对接WebSocket实时行情RESTful历史数据。这三块搞定了,你的做市系统才算真正有了"眼睛"和"耳朵"。

2.1 交易所API对接:你的第一道门槛

每个交易所的API风格都不一样。有的喜欢RESTful,有的偏爱WebSocket,还有的混合着来。我个人习惯是,先看文档,再写代码,千万别上来就撸。

核心要点:API对接不是简单的HTTP调用,你得考虑鉴权、限频、错误重试、数据校验这四个维度。

2.1.1 鉴权方式

主流交易所现在都用API Key + Secret Key的方式。我见过不少新手直接把密钥写死在代码里,结果代码一泄露,账户直接被清空。你想想看,这多可怕?

正确的做法是:

  • 密钥用环境变量或加密配置文件存储
  • 签名算法严格按照文档实现,别自己瞎改
  • 每个API Key设置IP白名单和权限限制

2.1.2 限频处理

交易所都有频率限制。比如Binance的REST API是每分钟1200次请求。我在项目中遇到过,某次行情波动剧烈,我的程序疯狂请求订单簿,直接被交易所封了IP,整整五分钟没法交易。

我的经验:用令牌桶算法做限频控制,每个请求前先"取令牌",取不到就排队等待。这样既不会触发交易所限频,又能保证请求的平滑性。

2.2 WebSocket实时行情:做市商的命脉

做市商的核心是"快"。你比别人快1毫秒,可能就多赚一个点差。WebSocket就是干这个的——它建立长连接,服务端主动推送数据,延迟通常在10-50毫秒之间。

为什么会比REST快这么多?因为REST是"你问一句,它答一句",而WebSocket是"它一直在说"。说白了,WebSocket省去了HTTP握手和请求头的开销。

2.2.1 订阅与取消订阅

WebSocket的典型流程是这样的:

  1. 建立连接(wss://stream.binance.com:9443/ws)
  2. 发送订阅消息({"method": "SUBSCRIBE", "params": ["btcusdt@depth20"], "id": 1})
  3. 接收推送数据(JSON格式的订单簿快照或增量)
  4. 心跳维持(每3-5分钟发送ping,否则连接会断开)

注意:我曾经踩过一个坑——WebSocket连接断了,程序没检测到,结果行情停了整整10分钟我才发现。那天的回撤,啧啧,不提了。所以一定要实现断线重连机制,并且每次重连后要重新订阅所有频道。

2.2.2 数据解析与缓存

WebSocket推送的数据量很大。以订单簿为例,每秒可能推送几十次增量更新。如果你每次都重新构建整个订单簿,CPU扛不住的。

我的做法是:

  • 维护一个本地订单簿副本(用红黑树或跳表实现)
  • 每次收到增量更新,只修改对应的价格档位
  • 每100次增量更新后,做一次全量校验,防止数据漂移
// 伪代码示例:订单簿增量更新
class OrderBook {
    constructor() {
        this.bids = new Map();  // 价格 -> 数量
        this.asks = new Map();
        this.updateCount = 0;
    }
    
    applyUpdate(update) {
        if (update.type === 'snapshot') {
            // 全量快照,直接替换
            this.bids = new Map(update.bids);
            this.asks = new Map(update.asks);
        } else {
            // 增量更新
            for (let [price, qty] of update.bids) {
                if (qty === '0') {
                    this.bids.delete(price);  // 撤单
                } else {
                    this.bids.set(price, qty);  // 新订单或更新
                }
            }
            // asks同理
        }
        
        this.updateCount++;
        if (this.updateCount % 100 === 0) {
            this.validate();  // 定期校验
        }
    }
}

2.3 RESTful历史数据:策略回测的基石

实时行情是"现在",历史数据是"过去"。没有历史数据,你的策略就是空中楼阁。做市策略的回测尤其依赖高质量的历史订单簿数据——不仅仅是K线,还有每一笔订单的深度变化。

2.3.1 数据获取策略

交易所的REST API通常提供以下历史数据:

数据类型 典型接口 用途
K线数据 /api/v3/klines 趋势分析、波动率计算
订单簿快照 /api/v3/depth 流动性分析、价差计算
成交记录 /api/v3/trades 交易量分析、冲击成本估算
资金费率 /api/v3/fundingRate 永续合约做市成本计算

我个人习惯是,每天定时拉取全量数据,存到本地数据库。别等到回测的时候才去拉,那时候数据可能已经被覆盖了。

2.3.2 数据清洗与对齐

原始数据直接拿来用?不行的。我遇到过好几次,交易所返回的数据有时间戳缺失、价格异常、或者重复记录的情况。

避坑指南:我曾经用某交易所的历史数据做回测,结果发现某天的订单簿深度数据里,买单价格比卖单还高——这明显是数据错误。后来我加了一层校验逻辑:如果买单最高价大于卖单最低价,直接丢弃该条数据。

数据对齐也很重要。不同交易所的时间戳格式不一样,有的用毫秒,有的用微秒。你得统一转换成UTC时间,然后按时间排序,才能做跨交易所的套利分析。

2.4 知识体系总览

下面这张图,是我自己总结的数据源接入整体架构。你看一眼,心里就有谱了。

做市商数据源接入架构 数据源层 交易所REST API WebSocket实时行情 历史数据存储 数据处理层 鉴权 · 限频 · 重试 解析 · 缓存 · 校验 清洗 · 对齐 · 存储 应用层 做市策略引擎 风险监控系统 回测分析平台 数据流方向:交易所 → 处理层 → 应用层

你看,整个架构分三层。数据源层负责"接进来",处理层负责"洗干净",应用层负责"用起来"。每一层都有各自的坑,咱们今天聊的就是第一层和第二层的核心要点。

总结一下:数据源接入不是简单的API调用,而是一个系统工程。WebSocket保证实时性,RESTful保证完整性,两者缺一不可。我个人的建议是,先用RESTful拉历史数据做回测,策略验证通过后,再上WebSocket接实时行情做实盘。别一上来就全量接入,容易翻车。

好了,数据源接入这块就聊到这儿。记住一句话:数据质量决定策略上限,接入稳定性决定下限。这两条线守住了,你的做市系统就成功了一半。


专注资料整理