3、实时数据管道:行情数据接入(Tick级、OrderBook深度),数据清洗与标准化,消息队列选型(Kafka/Pulsar)

做市商的风控系统,说白了就是跟时间赛跑。你想想看,行情数据晚到1毫秒,可能一笔订单就已经穿仓了。所以实时数据管道,是整个风控系统的「主动脉」。这一章,我重点聊聊行情接入、数据清洗,以及消息队列的选型。

3.1 行情数据接入:Tick级与OrderBook深度

做市商最怕什么?怕行情断层。你看到的买一价和实际成交价差了十万八千里,那风控模型就是瞎算。所以接入行情,必须做到Tick级和OrderBook深度。

Tick级数据,就是每一笔成交的明细。谁在什么时间、以什么价格、买了多少。我个人习惯,Tick数据必须包含:

  • 时间戳:精确到微秒,最好是交易所的撮合时间,不是本地接收时间。
  • 价格:成交价,注意是净价还是全价。
  • 成交量:币种或合约的单位。
  • 买卖方向:主动买还是主动卖,这个对判断资金流向很重要。

OrderBook深度,就是盘口数据。一般至少取前10档,甚至50档。我在项目中遇到过,有些交易所只给前5档,结果做市策略在极端行情下根本看不到流动性枯竭的迹象。所以,我建议至少订阅前20档的增量更新。

核心要点:Tick数据用于事后分析,OrderBook用于实时风控。两者缺一不可。

3.2 数据清洗与标准化

行情数据进来之后,不能直接用。为什么?因为不同交易所的格式千奇百怪。有的用Unix时间戳,有的用字符串;有的价格是整数,有的是浮点数。不洗一下,风控引擎会直接崩溃。

我一般做三步清洗:

  1. 去重:网络重传会导致重复数据。用时间戳+交易ID做唯一键,直接过滤。
  2. 补全:有些交易所的OrderBook增量更新会漏掉中间档位。这时候需要做插值,或者直接丢弃不完整的快照。
  3. 标准化:统一时间格式为纳秒级整数,价格转为定点数(避免浮点精度问题)。

举个例子,标准化后的数据结构大概长这样:

// 标准化后的Tick结构
struct Tick {
    int64_t timestamp_ns;   // 纳秒时间戳
    double price;           // 价格,定点数表示
    int64_t volume;         // 成交量
    uint8_t side;           // 0:买, 1:卖
    uint32_t exchange_id;   // 交易所编号
};

避坑指南:我曾经因为浮点数精度问题,导致风控系统误判了价差。后来全部改用定点数,再也没出过问题。记住,金融计算里,浮点数就是魔鬼。

3.3 消息队列选型:Kafka vs Pulsar

数据清洗完了,怎么喂给风控引擎?消息队列是标配。目前主流就两个:Kafka和Pulsar。我两个都用过,说说我的感受。

特性 Kafka Pulsar
吞吐量 极高,百万级/秒 高,但略低于Kafka
延迟 毫秒级 亚毫秒级
持久化 基于磁盘,依赖PageCache 分层存储,支持BookKeeper
扩容 需要重分区,较麻烦 支持无感扩容
运维复杂度 中等 较高

我的建议

  • 如果团队运维能力强,追求极致延迟,选Pulsar。它的亚毫秒级延迟在做市商场景下很有优势。
  • 如果团队规模小,追求稳定和生态,选Kafka。毕竟Kafka的社区和工具链更成熟。

我个人习惯,在风控系统里用Kafka。原因很简单:我踩过Pulsar的坑。有一次Pulsar的BookKeeper集群因为磁盘IO打满,导致消息积压了十几秒,风控直接失效。而Kafka的PageCache机制,在同等硬件下表现更稳定。

注意:无论选哪个,一定要配置好消息的ACK机制。风控数据不允许丢失,建议用「所有副本确认」模式。

3.4 整体数据流架构

说了这么多,画个图总结一下。下面这张SVG图,展示了从行情接入到风控引擎的完整数据流。

实时数据管道架构 交易所A 交易所B 交易所C 数据清洗层 去重 补全 标准化 格式统一 定点数转换 消息队列 Kafka / Pulsar Topic: tick Topic: orderbook Topic: trades 风控 引擎

这张图很直观。行情从交易所进来,先经过数据清洗层,然后进入消息队列,最后被风控引擎消费。每一步都不能掉链子。

个人经验:我在搭建这套管道时,特意在清洗层加了一个「延迟监控」模块。如果某条链路的延迟超过5毫秒,立刻报警。做市商的风控,本质上就是跟延迟做斗争。

好了,这一章的内容就到这里。实时数据管道是风控系统的地基,地基不稳,上面盖再漂亮的房子也是白搭。下一章,我们会聊聊风控引擎的核心计算逻辑。


公众号:蓝海资料掘金营,微信deep3321