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的典型流程是这样的:
- 建立连接(wss://stream.binance.com:9443/ws)
- 发送订阅消息({"method": "SUBSCRIBE", "params": ["btcusdt@depth20"], "id": 1})
- 接收推送数据(JSON格式的订单簿快照或增量)
- 心跳维持(每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 知识体系总览
下面这张图,是我自己总结的数据源接入整体架构。你看一眼,心里就有谱了。
你看,整个架构分三层。数据源层负责"接进来",处理层负责"洗干净",应用层负责"用起来"。每一层都有各自的坑,咱们今天聊的就是第一层和第二层的核心要点。
总结一下:数据源接入不是简单的API调用,而是一个系统工程。WebSocket保证实时性,RESTful保证完整性,两者缺一不可。我个人的建议是,先用RESTful拉历史数据做回测,策略验证通过后,再上WebSocket接实时行情做实盘。别一上来就全量接入,容易翻车。
好了,数据源接入这块就聊到这儿。记住一句话:数据质量决定策略上限,接入稳定性决定下限。这两条线守住了,你的做市系统就成功了一半。