3、市场数据事件:行情数据订阅、Tick数据解析、K线数据合成、实时数据推送架构

做量化交易,说白了就是跟数据打交道。而市场数据,是所有策略的起点。

我个人习惯把市场数据比作「原油」——它很原始,很粗糙,但经过提炼之后,就能变成驱动你策略引擎的燃料。这一章,我们就来聊聊这个「提炼」的过程。

3.1 行情数据订阅:你得先连上「水龙头」

要拿到行情数据,第一步就是订阅。你想想看,交易所每分钟产生海量的数据,你不可能全拉下来,也没那个必要。你需要的是「订阅」——告诉数据源:我只关心这几只股票,或者这几个合约。

在实际项目中,我遇到过不少新手直接去拉全市场快照,结果带宽打满,策略延迟高得离谱。嗯,这里要注意:订阅一定要精准

核心要点:

  • 订阅粒度:按合约代码订阅,不要按板块订阅
  • 订阅频率:区分高频和低频数据流
  • 重连机制:网络抖动是常态,必须自动重连

举个例子,如果你做股指期货,你只需要订阅 IF、IC、IH 这几个主力合约。别把中证500的所有股票都拉进来,那是给自己找麻烦。

# 伪代码示例:订阅行情
market_data_client.subscribe(
    symbols=['IF2409', 'IC2409'],
    data_type=['tick', 'depth'],
    callback=on_market_data
)

3.2 Tick数据解析:最原始的「心跳」

Tick 数据是什么?就是交易所每笔成交的「快照」。它包含了价格、成交量、买卖盘口等信息。每一笔 Tick,都是市场的一次心跳。

我曾经在解析 Tick 时踩过一个坑:某家数据商的 Tick 时间戳是本地时间,不是交易所时间。结果我拿来做回测,策略信号全偏了。所以,拿到 Tick 后第一件事,检查时间戳的时区

避坑指南:

我曾经因为 Tick 数据中的「成交量」是累计值还是单笔值没搞清楚,导致策略开仓逻辑完全错误。一定要确认数据字段的定义。

一个标准的 Tick 数据结构通常包含以下字段:

字段名 含义 示例值
symbol 合约代码 IF2409
timestamp 时间戳(毫秒) 1693123456789
last_price 最新成交价 3720.5
volume 成交量(累计) 123456
bid_price 买一价 3720.2
ask_price 卖一价 3720.8

小技巧:解析 Tick 时,建议用结构体或命名元组,别用字典。字典的哈希查找在高频场景下太慢了。

3.3 K线数据合成:从「心跳」到「心电图」

Tick 数据太细碎了,就像心跳的每一次搏动。而 K 线,就像是心电图——它把一段时间内的搏动归纳成几个关键指标:开盘、收盘、最高、最低。

K 线合成的逻辑其实不复杂,但细节决定成败。我见过有人直接用 Tick 的最后一笔价格当收盘价,结果遇到最后一笔是异常单,整个 K 线都废了。

标准的合成逻辑是这样的:

  1. 收到第一个 Tick,记录开盘价
  2. 每个 Tick 更新最高价和最低价
  3. 最后一个 Tick 的价格作为收盘价
  4. 成交量累加
class KLineBuilder:
    def __init__(self, period=60):
        self.period = period  # 60秒K线
        self.reset()
    
    def reset(self):
        self.open = 0
        self.high = 0
        self.low = float('inf')
        self.close = 0
        self.volume = 0
        self.count = 0
    
    def update(self, tick):
        if self.count == 0:
            self.open = tick.last_price
        self.high = max(self.high, tick.last_price)
        self.low = min(self.low, tick.last_price)
        self.close = tick.last_price
        self.volume += tick.volume
        self.count += 1

注意:合成 K 线时,一定要处理「跨周期」的情况。比如 60 秒 K 线,第 59 秒的 Tick 和第 61 秒的 Tick 不能混在一起。

3.4 实时数据推送架构:让数据「流」起来

数据拿到了,解析好了,K 线也合成了。接下来最关键的一步:怎么把这些数据高效地推送给策略引擎?

我个人比较推崇「发布-订阅」模式。说白了,就是有一个数据总线,谁需要什么数据,自己来订阅。策略模块不需要关心数据从哪里来,只需要关心数据怎么用。

这里我画了一张架构图,帮你理解整个流程:

交易所数据源 行情订阅模块 Tick 解析器 K线合成器 实时数据总线(发布-订阅) 策略引擎 原始数据 解析后Tick 合成K线 订阅数据

这张图展示了从数据源到策略引擎的完整链路。你想想看,如果没有这个架构,每个策略都自己去连交易所,那得多乱?

我的经验:数据总线建议用内存队列实现,比如 ZeroMQ 或 Redis Stream。别用数据库,IO 延迟太高了。

3.5 避坑总结

做市场数据这一块,我踩过的坑不少。这里列几个最常见的,你遇到了可以少走弯路:

  • 时间戳问题:不同数据源的时间戳格式可能不同,一定要统一成 UTC 毫秒
  • 数据对齐:Tick 数据和 K 线数据的时间窗口要对齐,否则策略信号会错位
  • 内存管理:Tick 数据量很大,不要全部缓存,用环形缓冲区或滑动窗口
  • 异常处理:网络断开、数据缺失、字段异常,都要有兜底逻辑

嗯,市场数据这块就聊到这儿。数据是策略的血液,把这一层做好了,后面的策略开发才会顺畅。


蓝海数据掘金营,专注资料整理