3、数据基础设施:实时行情数据源、API接口与数据清洗

做跨市场套利,说白了就是跟时间赛跑。你策略再牛,模型再准,数据源要是拉胯,一切都是白搭。我见过太多团队,策略回测曲线漂亮得像艺术品,一上实盘就亏成狗。为什么?十有八九是数据基础设施没搭好。

这一章,我们就来聊聊数据这档子事。我会把我这些年踩过的坑、用过的工具、总结出的经验,一股脑倒出来。你想想看,全球那么多交易所,每个交易所的数据格式、传输协议、延迟特性都不一样,怎么把它们揉到一起?嗯,这就是我们要解决的问题。

3.1 实时行情数据源:选对源头,事半功倍

实时行情数据源,我把它分成三类。每一类都有自己的脾气,你得摸透了才能用好。

数据源类型 代表产品 延迟 成本 适用场景
交易所直连 CME Direct, ICE <1ms 极高 高频套利、做市
专业数据商 Bloomberg, Reuters 10-50ms 中低频、研究分析
聚合数据源 Polygon, Tiingo 100-500ms 回测、个人交易

交易所直连,这是最硬核的方式。你得在交易所机房托管服务器,拉一根专线。延迟最低,但成本也最高。我记得2018年帮一家对冲基金搭建CME的套利系统,光机柜租赁和专线费用,一个月就烧掉5万美金。不过话说回来,做跨所套利,有时候1毫秒的差距就是几百万的利润。

专业数据商,比如Bloomberg和Reuters。它们的数据覆盖面广,清洗得也干净。但有个问题——贵,而且API接口比较老旧。我个人习惯用Bloomberg做盘后分析,但实盘交易我很少用它。为什么?延迟太高,而且数据经过了多层封装,你拿到的Tick数据其实已经「失真」了。

聚合数据源,这是近些年兴起的。像Polygon.io、Tiingo这些,它们把多个交易所的数据聚合起来,通过统一的API输出。成本低,接入快。但你要小心,聚合数据源的数据质量参差不齐。我曾经遇到过Polygon的某只美股期权数据,连续三天出现价格跳空,后来发现是它们的数据清洗逻辑有bug。

避坑指南: 不管你用哪个数据源,一定要做数据对账。拿交易所官方数据做基准,每天跑一遍校验脚本。我曾经因为数据源的一个字段映射错误,导致套利策略连续开了三个月的错误仓位,亏了200多万才反应过来。

3.2 API接口:统一抽象层是关键

不同交易所的API,那真是五花八门。有的用FIX协议,有的用RESTful,有的用WebSocket。你总不能为每个交易所都写一套交易逻辑吧?所以,我们需要一个统一的抽象层。

我习惯的做法是,定义一个通用的接口规范,然后为每个交易所写一个适配器。这样,上层的策略代码完全不用关心底层是哪个交易所。

// 伪代码示例:统一的行情接口
interface MarketDataProvider {
    // 订阅实时行情
    subscribe(symbol: string, callback: (tick: Tick) => void): void;
    
    // 获取历史K线
    getHistory(symbol: string, start: Date, end: Date): Promise<Bar[]>;
    
    // 获取当前深度
    getOrderBook(symbol: string): Promise<OrderBook>;
}

// 适配器示例:Binance适配器
class BinanceAdapter implements MarketDataProvider {
    subscribe(symbol, callback) {
        // 连接Binance WebSocket
        // 解析数据格式
        // 调用callback
    }
    // ... 其他方法实现
}

这里有个细节要注意。不同交易所的Tick数据结构差异很大。比如,CME的Tick包含「交易量」和「持仓量」,但加密货币交易所的Tick通常只有「交易量」。你的统一数据结构,要能兼容这些差异。我个人习惯用「可选字段」的方式处理,缺失的字段用null填充。

小技巧: 在适配器层,我建议加一个「数据校验」环节。比如,检查时间戳是否单调递增,价格是否在合理范围内,交易量是否为正数。这些校验能帮你过滤掉很多脏数据。我在项目中遇到过,某交易所的WebSocket偶尔会推送重复的Tick,如果不做去重,你的策略会重复计算,导致信号失真。

3.3 数据清洗:脏数据是套利策略的隐形杀手

数据清洗,听起来很枯燥,但这是整个数据基础设施里最重要的一环。我甚至可以说,数据清洗做得好不好,直接决定了你的套利策略能不能赚钱。

常见的脏数据问题,我列一下:

  • 时间戳错乱:交易所服务器时钟不同步,导致Tick的时间戳出现偏差
  • 价格跳空:数据源丢包,导致价格出现不合理的跳跃
  • 重复数据:同一笔交易被推送了多次
  • 数据缺失:某些时间段的Tick数据完全丢失
  • 字段异常:比如交易量为0,或者价格为负数

我的清洗流程是这样的:

  1. 格式校验:检查每个字段的数据类型和取值范围
  2. 时间戳对齐:将所有数据的时间戳统一到UTC,并做单调性检查
  3. 去重:基于「交易所+交易对+时间戳+价格+交易量」做哈希去重
  4. 异常值过滤:用3-sigma法则或IQR方法过滤价格和交易量的异常值
  5. 缺失值填充:对于短时间的数据缺失,用前一个Tick的值填充;长时间缺失则标记为「不可用」
核心观点: 数据清洗不是一次性的工作,而是一个持续的过程。你需要建立监控告警机制,一旦发现数据质量下降,立刻介入处理。我团队里有个专门的「数据质量看板」,实时显示每个数据源的延迟、丢包率、异常比例等指标。

3.4 知识体系框架:一张图看懂数据基础设施

说了这么多,我们来画一张图,把整个数据基础设施的脉络理清楚。

数据基础设施核心架构 数据源层 交易所直连 专业数据商 聚合数据源 其他数据源 适配器层(统一抽象接口) 数据格式转换 | 协议适配 | 字段映射 | 数据校验 数据清洗层 格式校验 时间戳对齐 去重 异常过滤 缺失填充 存储与分发层 实时消息队列(Kafka) 历史数据库(ClickHouse) 缓存(Redis)

这张图展示了我个人比较推崇的四层架构。从下往上,数据从原始状态逐步变成可用的「干净数据」。每一层都有明确的职责,层与层之间通过标准接口通信。这样做的好处是,任何一层出了问题,都不会影响其他层。比如,你想换一个数据源,只需要改适配器层的代码,上层的策略完全不用动。

我的经验: 在存储与分发层,我强烈建议用消息队列(比如Kafka)做实时数据的分发。为什么?因为套利策略通常需要同时消费多个数据源的数据,消息队列能帮你做「数据对齐」。比如,你订阅了CME的标普500期货和Binance的BTC永续合约,这两个数据源的Tick到达速度不一样。用Kafka的「时间窗口」机制,你可以把两个数据源的数据按时间戳对齐,然后一起推送给策略。这个技巧,我在多个项目中都用过,效果非常好。

好了,数据基础设施这块,我们就聊到这里。记住,数据是量化交易的血液。血液不干净,再强壮的身体也会出问题。下一章,我们会把这些数据用起来,开始构建真正的套利策略。


公众号:蓝海数据掘金营,微信deep3321