第二章:订单流数据采集
数据采集,是整个订单流分析体系的基石。
我见过太多人,策略写得花里胡哨,结果数据源一塌糊涂。说白了,数据不准,后面全是白搭。今天咱们就把这块硬骨头啃下来。
2.1 交易所API对接:选对路子
对接交易所API,是第一步。我个人习惯,先看文档,再看社区反馈。
主流交易所的API,大体分两类:
- REST API:请求-响应模式。适合拉取历史数据、查询账户信息。延迟高,但稳定。
- WebSocket API:全双工通信。适合实时行情、订单流推送。延迟低,但连接管理麻烦。
我在项目中遇到过,有人用REST API去轮询Tick数据,结果被交易所限流,直接封了IP。嗯,这里要注意:实时数据,必须用WebSocket。
核心原则:
- 历史数据用REST,批量拉取
- 实时数据用WebSocket,持续监听
- 下单接口用REST,确保幂等性
2.2 WebSocket实时流:心跳与重连
WebSocket连接,说白了就是一条长管道。管道断了,数据就断了。
你想想看,如果行情正剧烈波动,你的WebSocket突然断开,那几秒钟的Tick数据丢失,可能就错过了一波行情。
我曾经踩过一个坑:交易所的WebSocket服务器,每30秒会发一个ping帧。如果客户端没及时回复pong,连接就会被断开。后来我加了个心跳检测,每15秒主动发一次ping,问题就解决了。
避坑指南:
我曾经在对接某二线交易所时,发现它的WebSocket每隔一小时会自动断开。后来查文档才知道,这是它的「安全策略」。解决方案:实现自动重连机制,断线后立即重新订阅。
一个典型的WebSocket订阅流程:
// 伪代码示例
ws.connect('wss://api.exchange.com/ws')
ws.on('open', () => {
// 订阅订单簿深度
ws.send(JSON.stringify({
event: 'subscribe',
channel: 'depth',
symbol: 'BTCUSDT'
}))
})
ws.on('message', (data) => {
// 解析Tick数据
const tick = JSON.parse(data)
processTick(tick)
})
ws.on('close', () => {
// 自动重连
setTimeout(() => reconnect(), 1000)
})
2.3 数据清洗与存储:脏数据是毒药
原始数据,永远是脏的。为什么?
- 网络抖动导致数据重复
- 交易所撮合引擎延迟导致时间戳错乱
- 部分Tick数据缺失(比如盘口快照丢失)
我见过最离谱的一次,某交易所的API在高峰期返回了重复的成交记录,时间戳一模一样。如果不做去重,你的回测结果会直接翻倍。
警告:
千万不要把原始数据直接喂给策略!一定要经过清洗。我曾经因为偷懒,没做去重,结果策略在实盘时频繁开仓,亏了六位数。
数据清洗的标准流程:
- 去重:按交易ID或时间戳+价格+数量组合去重
- 排序:按时间戳升序排列,确保时序正确
- 补全:对于缺失的Tick,用前一个有效值填充(或者丢弃)
- 校验:检查价格是否在合理范围内(比如BTC价格不会突然从1万跳到100万)
存储方面,我个人推荐用时序数据库,比如InfluxDB或TimescaleDB。关系型数据库(MySQL)在存储高频Tick数据时,写入性能会成问题。
-- 创建Tick数据表(TimescaleDB示例)
CREATE TABLE ticks (
time TIMESTAMPTZ NOT NULL,
symbol TEXT NOT NULL,
price DOUBLE PRECISION,
volume DOUBLE PRECISION,
side TEXT,
trade_id BIGINT
);
-- 转换为超表
SELECT create_hypertable('ticks', 'time');
2.4 Tick级数据解析:毫秒定胜负
Tick级数据,就是每一笔成交的原始记录。它包含:
- 时间戳(精确到毫秒甚至微秒)
- 成交价格
- 成交数量
- 买卖方向(主动买还是主动卖)
- 交易ID
为什么Tick数据这么重要?因为订单流分析,就是基于这些「微观」数据来推断「宏观」趋势的。
举个例子:如果连续10笔Tick都是主动买(即买方吃单),说明买方力量强,价格大概率要涨。这就是订单流的基本逻辑。
关键字段解析:
| 字段 | 含义 | 注意事项 |
|---|---|---|
| time | 成交时间 | 注意交易所时区,统一转成UTC |
| price | 成交价格 | 浮点数精度问题,建议用整数存储(如乘以1e8) |
| volume | 成交数量 | 注意合约的乘数(比如永续合约的volume是张数) |
| side | 买卖方向 | buy/sell,注意有些交易所用'B'/'S' |
解析Tick数据时,有个小技巧:不要直接解析JSON字符串。我在项目中试过,用Python的json.loads()解析每秒上千条Tick,CPU直接飙到80%。后来改用Protocol Buffers或者MessagePack,性能提升了5倍。
性能优化建议:
如果数据量极大(比如每秒上万条Tick),可以考虑用C++或Rust编写解析模块,通过Python的C扩展调用。我曾在某家做市商公司见过,他们用Rust写的解析器,单机每秒处理50万条Tick。
2.5 知识体系总览
下面这张图,是我自己总结的订单流数据采集全流程。你照着这个框架搭,基本不会出大问题。
嗯,这套流程,我在多个项目中验证过。从数据源到最终存储,每一步都有坑。但只要按这个框架走,至少能保证数据质量过关。