4、事件源设计(一):市场行情事件源(Tick、K线、订单簿)、事件标准化与封装
各位同学,今天我们来聊聊事件驱动型套利系统的第一个核心环节——事件源设计。说白了,就是你的系统怎么感知市场的变化。
我个人习惯把事件源比作系统的「眼睛」。眼睛要是瞎了,后面策略再牛也没用。我在早期做高频套利时,就吃过行情源不稳定的亏,那感觉,就像在高速公路上蒙着眼开车。
4.1 市场行情事件源的三大基石
市场行情数据,通常分为三个层次。你想想看,一个交易员盯盘,他看什么?无非就是这三样:
- Tick 数据:最原始的交易记录。每一笔成交,就是一个 Tick。
- K 线数据:对 Tick 数据的聚合。按时间窗口(1分钟、5分钟)统计出开盘、收盘、最高、最低。
- 订单簿数据:市场深度。显示当前所有挂单的买价、卖价和数量。
嗯,这里要注意:不是所有套利策略都需要这三样。比如做跨期套利,你可能更关注 Tick 和订单簿;做统计套利,K 线就够了。
核心观点:事件源设计的本质,是把「市场发生了什么」翻译成「系统能理解的事件」。
4.2 Tick 事件源:最原始的市场脉搏
Tick 数据长什么样?我直接给你看一个典型的结构:
{
"symbol": "BTCUSDT",
"exchange": "binance",
"timestamp": 1696000000123,
"price": 27500.50,
"volume": 0.15,
"side": "buy", // 主动买还是主动卖
"trade_id": "123456789"
}
为什么 Tick 重要?因为它最真实。K 线可以造假(比如对敲拉收盘价),但 Tick 是逐笔成交,很难完全伪造。
我在项目中遇到过一个问题:Tick 数据量太大。一个主流交易所,每秒可能产生几千笔 Tick。如果每个 Tick 都触发一次策略计算,CPU 直接拉满。怎么办?
我的经验:不要直接消费原始 Tick。加一个「节流阀」——比如每 10 毫秒聚合一次,或者只处理价格变化超过 0.1% 的 Tick。
4.3 K 线事件源:聚合后的市场视图
K 线是 Tick 的「压缩包」。它牺牲了细节,换来了可读性。一个典型的 K 线事件:
{
"symbol": "ETHUSDT",
"interval": "1m",
"open_time": 1696000000000,
"close_time": 1696000059999,
"open": 1850.00,
"high": 1855.50,
"low": 1848.20,
"close": 1853.10,
"volume": 1250.0
}
做 K 线事件源时,有个坑:K 线是「闭合」后才推送的。也就是说,当你知道这根 K 线收盘价时,它已经结束了。对于套利来说,这往往太晚了。
避坑指南:我曾经因为依赖 K 线收盘事件做开仓判断,结果滑点大得离谱。后来改成用「实时 K 线」——也就是当前正在形成的 K 线,每来一个 Tick 就更新一次。
4.4 订单簿事件源:市场的「暗流」
订单簿是套利系统的重头戏。它告诉你:谁在什么价位等着成交。
一个典型的订单簿快照:
{
"symbol": "BTCUSDT",
"bids": [
[27500.00, 1.5], // 买价, 数量
[27499.50, 2.3],
...
],
"asks": [
[27501.00, 0.8],
[27501.50, 1.2],
...
],
"timestamp": 1696000000123
}
订单簿事件有两种模式:
- 全量快照:每隔一段时间(比如 100ms)推送整个订单簿。简单,但数据量大。
- 增量更新:只推送变化的部分。比如「买一价变了」、「卖二数量减少了」。效率高,但实现复杂。
我个人建议:用增量更新 + 本地维护全量订单簿。这样既省带宽,又能随时拿到完整深度。
关键点:订单簿的「深度」比「价格」更重要。套利机会往往藏在挂单量的突变中。
4.5 事件标准化与封装:让数据「说同一种语言」
好了,现在你有了 Tick、K 线、订单簿。但问题来了——不同交易所的数据格式不一样。
币安的 Tick 字段叫 "price",OKX 的可能叫 "px"。你总不能为每个交易所写一套策略吧?
所以我们需要一个「事件标准化层」。它的作用很简单:把各种原始数据,翻译成统一的内部事件。
我设计的一个标准事件接口:
// 统一市场事件接口
interface MarketEvent {
event_type: 'tick' | 'kline' | 'orderbook';
symbol: string;
exchange: string;
timestamp: number; // 统一用毫秒时间戳
data: any; // 具体数据
raw: any; // 保留原始数据,方便调试
}
为什么要保留 raw?因为有时候标准化会丢失信息。比如某个交易所的 Tick 里带了一个「交易者 ID」,标准化时你可能没考虑这个字段。保留 raw,方便后续回溯。
小技巧:在标准化层加一个「校验器」。检查时间戳是否合理、价格是否为正数、数量是否异常。我曾经因为交易所推送了一个价格为 0 的 Tick,差点导致策略爆仓。
4.6 整体架构图
下面这张图,展示了事件源在整个系统中的位置。你可以看到,原始数据经过「适配器」变成标准事件,然后进入事件总线,供策略消费。
4.7 总结与个人心得
事件源设计,说白了就是三个字:收、转、发。
- 收:从不同交易所接收原始数据。
- 转:转换成统一的标准事件。
- 发:推送到事件总线,供下游消费。
我在做这个系统时,最深的体会是:不要过度设计。一开始你只需要支持 Tick 和订单簿就够了。K 线可以后面再加。先跑起来,再优化。
最后一句:事件源是系统的「地基」。地基不稳,楼盖得再高也是危房。花时间把这块做扎实,后面你会感谢自己的。
公众号:蓝海资料掘金营,微信deep3321