1. 行情数据基础:理解Level-1与Level-2行情、快照与增量数据的概念、为什么需要合并
做量化交易这些年,我见过不少新手一上来就扎进策略堆里,结果连行情数据都没搞明白。说实话,行情数据是整个交易系统的地基。地基不稳,上面盖多高的楼都得塌。
今天咱们就聊聊行情数据最核心的几个概念。嗯,这些东西我当年也是踩了不少坑才真正吃透的。
1.1 Level-1 与 Level-2 行情:到底差在哪?
先问个问题:你在券商APP上看到的行情,和量化机构用的行情,是一回事吗?
答案很明确——不是。
国内交易所把行情数据分成了两个等级:Level-1 和 Level-2。说白了,一个是大路货,一个是VIP专享。
| 对比项 | Level-1 行情 | Level-2 行情 |
|---|---|---|
| 推送频率 | 约3秒一次 | 约0.5秒一次,甚至逐笔推送 |
| 盘口深度 | 5档买卖盘 | 10档买卖盘 |
| 逐笔成交 | 无 | 有(逐笔成交明细) |
| 费用 | 免费 | 付费(每年数万到数十万) |
| 适用场景 | 普通看盘、长线 | 高频交易、做市、量化 |
我个人习惯用Level-2做日内策略。为什么?因为3秒一次的Level-1,对于高频场景来说,信息滞后太严重了。你想想看,3秒在A股市场里,足够价格跳好几个档位了。
核心区别一句话总结:Level-1告诉你「刚才发生了什么」,Level-2告诉你「正在发生什么」。
1.2 快照与增量数据:两个完全不同的东西
好,接下来聊快照和增量。这两个概念,我建议你一定要分清楚。
快照(Snapshot),就是某一时刻的完整行情状态。比如10:00:00这一秒,某只股票的买一价、卖一价、成交量、持仓量……所有数据打包给你。
增量(Incremental/Delta),则是两次快照之间的变化。比如从10:00:00到10:00:03,买一价从10.01变成了10.02,成交量增加了100手。增量只告诉你「变了什么」,不告诉你「全部是什么」。
举个例子你就明白了:
// 快照数据(10:00:00)
{
"symbol": "600519",
"time": "10:00:00.000",
"last_price": 1880.00,
"volume": 1250000,
"bid1_price": 1879.50,
"bid1_volume": 200,
"ask1_price": 1880.50,
"ask1_volume": 150
}
// 增量数据(10:00:03)
{
"symbol": "600519",
"time": "10:00:03.000",
"last_price": 1881.00, // 变了
"volume": 1250100, // 增加了100手
"bid1_price": 1880.00, // 变了
"bid1_volume": 180, // 变了
"ask1_price": 1881.00, // 变了
"ask1_volume": 120 // 变了
}
看到没?增量数据只包含了变化的部分。如果某个字段没变,增量里可能压根就不出现。
小技巧:我在项目中遇到过,有些交易所的增量数据格式很「偷懒」——只推送变化字段,没变化的直接省略。所以解析时一定要做空值判断,别想当然地认为每个字段都有值。
1.3 为什么需要合并?不合并行不行?
你可能会问:既然快照已经包含了完整数据,我直接用快照不就行了?干嘛还要合并增量?
嗯,这个问题问得好。原因有三:
- 带宽和性能:快照数据量大,如果每秒推送一次快照,网络带宽和CPU开销都扛不住。增量数据小得多,传输效率高。
- 实时性要求:快照通常几秒才推送一次,但增量可以毫秒级推送。如果你只靠快照,中间这几秒的行情变化你就错过了。
- 历史回放:做回测时,你需要精确到每一笔的行情变化。只存快照会丢失中间细节,存增量+定期快照才是标准做法。
说白了,快照是「锚点」,增量是「变化流」。两者结合,才能既保证数据完整,又保证实时高效。
注意:合并增量时,一定要处理好时序问题。我曾经踩过一个坑——增量数据到达的顺序和实际发生顺序不一致,导致合并出来的快照数据错乱。后来我加了个序列号校验,才彻底解决。
1.4 合并的核心逻辑:一张图看懂
下面这张图,是我自己总结的合并流程。你看完应该就明白了。
流程其实很简单:
- 先拿一个快照作为「基准状态」
- 然后不断接收增量数据
- 把增量「叠」到快照上,更新对应字段
- 最终得到的就是最新的完整行情
我在实际项目中,通常每5分钟或者每收到1000条增量后,重新拉一次快照。为什么?因为增量数据在传输过程中可能有丢包,时间久了误差会累积。定期用快照「校准」一下,能保证数据一致性。
一句话记住:快照是「底图」,增量是「更新层」。底图定期换,更新层实时刷,两者结合就是完整的行情视图。
1.5 实际开发中的几个坑
最后分享几个我踩过的坑,希望能帮你少走弯路:
- 增量乱序:网络延迟可能导致后发的增量先到。解决方案是给每条增量加一个单调递增的序列号,合并前先排序。
- 快照与增量重叠:有时候快照到达时,增量已经处理了一部分。这时候要小心,别把增量覆盖了。我一般会记录快照的生成时间,只合并该时间之后的增量。
- 内存管理:如果你同时监控几千只股票,每只股票都维护一个快照对象,内存开销不小。建议用对象池或者直接复用数据结构,减少GC压力。
好了,这一章的内容就到这里。行情数据的基础概念,说白了就是这些。下一章咱们会深入代码层面,看看怎么用Java/C++实现一个高效的合并引擎。
公众号:蓝海资料掘金营,微信deep3321