数据采集与存储:API接口对接与高效落地
做高频交易,数据就是你的弹药。弹药质量不行,枪法再好也白搭。这一章,咱们聊聊怎么把CTP、易盛这些期货柜台的数据,稳稳当当地接到本地,再存成能快速读取的格式。
我个人习惯把数据采集分成三步:对接、落地、压缩。每一步都有坑,我踩过不少,今天一并说清楚。
API接口对接:CTP与易盛
CTP(综合交易平台)和易盛,是国内期货市场两大主流柜台。接口风格不太一样,但核心逻辑相通。
CTP接口对接要点
CTP的API是C++写的,Python调用得用封装库。我常用的是vnpy的封装,或者自己用ctypes直接调。
核心流程就三步:
- 初始化:创建交易和行情两个API实例
- 登录:填上你的经纪商账号、密码、交易服务器地址
- 订阅行情:传入合约代码,比如
rb2401
这里有个坑——行情数据是异步推送的。你订阅后,数据会通过回调函数传回来。我曾经在项目里忘了处理回调队列,结果数据全丢了,排查了一下午才发现是队列满了没消费。
关键代码片段:CTP行情订阅
from vnpy_ctp import CtpMdApi
class MyMdApi(CtpMdApi):
def on_tick(self, tick):
# 这里拿到每笔行情
print(tick.last_price, tick.volume)
api = MyMdApi()
api.connect("tcp://180.168.146.187:10131", "你的账号", "密码")
api.subscribe("rb2401")
易盛接口对接要点
易盛的API设计更现代一些,支持多账户同时登录。我个人觉得它的行情推送更稳定,但文档写得比较简略。
对接易盛时,注意它的合约编码规则。比如郑商所的合约,在易盛里可能是ZC401而不是ZC2401。我刚开始对接时,因为这个编码差异,折腾了两天才发现是合约代码写错了。
小技巧:建议写一个合约映射表,把不同柜台的合约代码统一映射成标准格式。这样切换柜台时,只需要改映射表,不用改业务代码。
数据落地:Parquet与Arrow格式
数据拿到手了,存成什么格式?CSV?别闹了。高频数据动辄每天几千万条,CSV读写慢、占空间大,根本扛不住。
我推荐两种格式:Parquet和Arrow。
| 特性 | Parquet | Arrow |
|---|---|---|
| 存储方式 | 列式存储,压缩率高 | 列式内存格式,可持久化 |
| 读取速度 | 快(支持谓词下推) | 极快(零拷贝) |
| 适用场景 | 长期存储、数据分析 | 实时计算、进程间通信 |
| 压缩比 | 高(默认Snappy) | 中等 |
我的做法是:热数据用Arrow,冷数据用Parquet。当天交易的数据,用Arrow存内存或SSD上,方便回测时快速读取。历史数据,压缩成Parquet归档。
代码示例:将Tick数据写入Parquet
import pandas as pd
import pyarrow.parquet as pq
# 假设tick_data是DataFrame
tick_data = pd.DataFrame({
'datetime': ['2024-01-15 09:30:00.123'],
'last_price': [3985.0],
'volume': [120],
'symbol': ['rb2401']
})
# 写入Parquet,使用Snappy压缩
tick_data.to_parquet(
'data/rb2401_20240115.parquet',
compression='snappy',
engine='pyarrow'
)
数据压缩策略
压缩不是随便选个算法就完事了。你得考虑读写速度和压缩比的平衡。
我常用的压缩策略:
- Snappy:压缩快,解压也快。适合高频场景,我90%的场景都用它
- Zstd:压缩比高,但速度慢一些。适合归档数据
- Gzip:不推荐。压缩慢,解压也慢,除非你有特殊需求
注意:不要对单个字段做压缩。Parquet和Arrow都是列式存储,它们会在列级别自动压缩。你手动压缩反而会破坏列式存储的优势。
另外,时间分区也是一种隐形的压缩策略。按天、按小时分区存储,查询时只扫描需要的分区,速度能快几十倍。
我的习惯:每天收盘后,把当天的Tick数据按合约+日期分区存储。比如data/rb2401/2024/01/15/。这样回测时只需要加载指定日期的数据,内存压力小很多。
知识体系总览
下面这张图,把数据采集到存储的整个链路串起来了。你可以对照着看,心里有个全局观。
你看,整个链路其实不复杂。关键是每个环节都要稳。接口对接要处理好异步回调,数据落地要选对格式,压缩策略要平衡速度和空间。
我曾经在一个项目里,因为压缩策略没选好,导致回测时I/O成了瓶颈。后来换成Snappy+时间分区,速度提升了5倍。嗯,这些细节,往往决定了你的策略能不能跑起来。