行情数据源接入:交易所API协议对比与实战
做市商系统里,行情数据源接入是第一道关卡。说白了,你连数据都拿不到,后面策略再牛也是白搭。今天我们就聊聊交易所API协议的选择、数据格式标准化,以及连接池和心跳管理这些实战细节。
一、三大协议:FIX、WebSocket、REST
我个人习惯把交易所API协议分成三类:FIX、WebSocket、REST。它们各有各的脾气,选错了后面会很难受。
| 协议 | 延迟 | 吞吐量 | 复杂度 | 典型场景 |
|---|---|---|---|---|
| FIX | 极低(微秒级) | 高 | 高 | 高频做市、机构级交易 |
| WebSocket | 低(毫秒级) | 中高 | 中 | 实时行情推送、零售交易 |
| REST | 高(秒级) | 低 | 低 | 历史数据查询、订单管理 |
1. FIX协议:老牌劲旅
FIX协议在传统金融领域用了二十多年。我在项目中遇到过一家交易所只支持FIX,当时团队里没人熟悉这个协议,折腾了两周才搞定。FIX的优点在于标准化程度高,字段定义清晰,而且支持会话级别的恢复机制。但缺点也很明显——报文是二进制或纯文本格式,解析起来比JSON麻烦得多。
核心要点:FIX的会话层有严格的序列号管理,断线重连后可以自动补发丢失的报文。这一点在行情数据接入中非常关键。
2. WebSocket:现代主流
现在大部分数字货币交易所都支持WebSocket。为什么?因为它天然支持全双工通信,服务端可以主动推送数据。你想想看,做市商需要实时获取买卖盘口变化,用REST轮询的话,延迟高不说,还会浪费带宽。
我记得有一次帮客户优化行情接入,他们原来用REST每100ms轮询一次,结果交易所直接限流了。改成WebSocket后,延迟从200ms降到了5ms,而且带宽占用减少了80%。
避坑指南:WebSocket虽然好,但要注意心跳机制。我曾经遇到过交易所的WebSocket连接在空闲30秒后自动断开,而我们的心跳间隔设成了60秒,导致频繁断线重连。后来统一改成15秒心跳,问题解决。
3. REST:简单但慢
REST适合做两件事:一是查询历史数据,二是下单。实时行情用REST?别闹了。我见过有人用REST做高频行情,结果服务器CPU全耗在HTTP连接上了。
二、行情数据格式标准化
不同交易所返回的行情数据格式五花八门。有的用JSON,有的用Protobuf,有的甚至用自定义二进制格式。如果不做标准化,你的策略代码会变得非常混乱。
我个人习惯的做法是:在数据接入层统一转换成内部标准格式。比如这样:
// 内部标准行情结构
struct MarketData {
string symbol; // 统一交易对名称,如"BTC-USDT"
int64_t timestamp; // 纳秒级时间戳
double bid_price; // 买一价
double ask_price; // 卖一价
double bid_size; // 买一量
double ask_size; // 卖一量
double last_price; // 最新成交价
double volume; // 24小时成交量
};
为什么要这么做?因为不同交易所对交易对的命名规则不一样。比如币安叫"BTCUSDT",OKX叫"BTC-USDT",火币叫"btcusdt"。如果不统一,你的策略里到处都是if-else判断,维护起来想死的心都有。
注意:时间戳的精度问题。有的交易所给毫秒级,有的给微秒级,有的甚至给秒级。我建议统一转成纳秒级,因为做市商策略对时间精度要求极高,毫秒级的误差都可能导致滑点。
三、连接池与心跳管理
连接池和心跳管理,听起来简单,但做起来坑很多。我见过一个团队,连接池配置不当,导致行情数据延迟从5ms飙升到500ms,最后发现是连接池满了,新请求在排队等待。
1. 连接池设计原则
- 按交易所隔离:每个交易所独立连接池,避免一个交易所出问题影响其他交易所。
- 动态扩容:根据行情数据量自动调整连接数。比如开盘时数据量大,可以多开几个连接。
- 健康检查:定期检查连接是否可用,发现异常立即重建。
我曾经在项目中用过一个简单的连接池实现:
class ConnectionPool {
int max_connections;
int min_connections;
vector<Connection> connections;
void health_check() {
for (auto& conn : connections) {
if (!conn.is_alive()) {
conn.reconnect();
}
}
}
Connection* get_connection() {
// 轮询或最小连接数策略
return &connections[rand() % connections.size()];
}
};
2. 心跳机制实战
心跳是维持长连接的关键。不同交易所的心跳要求不一样:
| 交易所 | 心跳间隔 | 超时时间 | 备注 |
|---|---|---|---|
| 币安 | 3分钟 | 10分钟 | 支持Ping/Pong |
| OKX | 15秒 | 30秒 | 需要主动发送心跳 |
| Coinbase | 30秒 | 60秒 | 自动心跳 |
经验之谈:心跳间隔不要设得太长。我曾经把心跳设成5分钟,结果交易所那边网络波动了一下,连接断了我们完全不知道,直到策略报错才发现。后来统一改成30秒心跳,配合3次重试,基本没再出过问题。
四、整体架构图
下面这张图展示了行情数据接入的整体流程。从交易所API到内部标准化数据,再到策略引擎,每一步都有讲究。
嗯,这张图基本把行情数据接入的四个层次说清楚了。从数据源到接入层,再到处理层,最后到应用层,每一层都有明确的职责。
五、实战避坑总结
最后,我把自己踩过的坑总结一下:
- 协议选择:高频做市用FIX,实时行情用WebSocket,历史数据用REST。别混用。
- 数据标准化:一定要在接入层做,不要在策略层做。否则策略代码会变得又臭又长。
- 心跳间隔:建议设为交易所要求的一半。比如交易所要求30秒,你就设15秒,留出容错空间。
- 连接池大小:不是越大越好。我见过有人开100个连接,结果交易所直接封IP。一般5-10个连接就够了。
一个小技巧:在连接池里加一个监控指标,记录每个连接的延迟和丢包率。一旦发现某个连接异常,自动切换到备用连接。这个功能救过我好几次。
行情数据接入看起来简单,但细节决定成败。希望今天的分享能帮你少走一些弯路。