Tick级数据结构:Level1与Level2行情数据、Order Book的构建、Tick数据的存储格式

各位同学,咱们今天聊点实在的。

做高频交易,第一关就是搞懂Tick数据。说白了,Tick就是市场最原始的脉搏。你连心跳都摸不准,还谈什么交易策略?

我个人习惯把Tick数据比作「市场的DNA」。Level1是简化版,Level2是完整版。咱们一个一个拆开看。

Level1行情数据:市场的「快照」

Level1,也叫Top of Book。它只告诉你当前最优的买一和卖一价格和数量。

举个例子,你在交易软件上看到的「最新价:100.50,买一:100.48,卖一:100.52」,这就是Level1。

我在项目中遇到过不少新手,拿着Level1数据做高频策略,结果回测漂亮,实盘一跑就崩。为什么?因为Level1信息量太少了。它看不到市场的深度,看不到大单在哪个价位埋伏。

Level1的核心字段:

  • 时间戳(精确到微秒或纳秒)
  • 最新成交价
  • 买一价 & 买一量
  • 卖一价 & 卖一量
  • 当日开盘价、最高价、最低价、收盘价
  • 成交量、成交额

嗯,这里要注意。Level1的更新频率一般是每笔成交或每500毫秒一次。对于高频交易来说,这个粒度太粗了。你想想看,500毫秒够市场发生多少次变化?

Level2行情数据:市场的「CT扫描」

Level2就不一样了。它给你的是整个订单簿的深度信息。能看到买一到买N档,卖一到卖N档。国内A股一般是10档,美股可以到几十档。

Level2数据里,我最看重的是「逐笔成交」和「逐笔委托」。这两个东西,才是真正还原市场博弈过程的利器。

我的经验:Level2数据里有一个容易被忽略的字段——「委托序号」。它能帮你还原订单的先后顺序。我曾经靠这个字段,发现了一个机构拆单的规律,做出了一个不错的统计套利策略。

Level2的数据量有多大?我给你们算笔账:

数据类型 单条数据大小 日均条数(A股) 日均数据量
Level1快照 ~200字节 ~10万条 ~20MB
Level2快照 ~2KB ~50万条 ~1GB
Level2逐笔成交 ~100字节 ~500万条 ~500MB
Level2逐笔委托 ~80字节 ~2000万条 ~1.6GB

看到没?Level2的数据量是Level1的几十倍。这就是为什么存储格式变得至关重要。

Order Book(订单簿)的构建:从数据流到实时状态

订单簿,说白了就是一个「价格-数量」的映射表。买盘按价格从高到低排,卖盘从低到高排。

构建订单簿的核心逻辑其实不复杂:

# 伪代码示意
class OrderBook:
    def __init__(self):
        self.bids = {}  # 买盘:价格 -> 数量
        self.asks = {}  # 卖盘:价格 -> 数量
    
    def update(self, price, quantity, side):
        if quantity == 0:
            # 撤单或成交完毕,删除该价位
            del self.book[side][price]
        else:
            # 新增或修改
            self.book[side][price] = quantity
    
    def get_top(self, n=10):
        # 获取前n档买卖盘
        sorted_bids = sorted(self.bids.items(), reverse=True)[:n]
        sorted_asks = sorted(self.asks.items())[:n]
        return sorted_bids, sorted_asks

但实际项目中,坑比你想的多。我曾经踩过一个坑:不同交易所的订单簿更新机制不一样。有的是「增量更新」,只发变化的部分;有的是「全量快照」,每次发全部数据。

避坑指南:我曾经因为没处理好增量更新的时序问题,导致订单簿状态错乱,回测结果完全失真。后来我加了一个「快照校验」机制——每收到1000条增量后,强制拉一次全量快照做对比。这个习惯救了我很多次。

构建订单簿时,还有几个关键点:

  • 时间同步:不同数据源的时间戳可能不同步,需要做对齐处理
  • 乱序处理:网络延迟会导致数据包乱序到达,需要缓存排序
  • 内存管理:高频场景下,订单簿对象需要复用,避免频繁GC

Tick数据的存储格式:Parquet vs Arrow

说到存储,这是很多人的盲区。觉得随便存个CSV就行。我告诉你,高频数据用CSV存,你连回测都跑不动。

目前业界主流就两个选择:Parquet和Arrow。我两个都用过,说说我的感受。

Parquet:列式存储的王者

Parquet是Hadoop生态出来的,专为分析型查询设计。它的核心优势是:

  • 列式压缩:同一列的数据类型相同,压缩率极高。我实测过,Tick数据用Parquet存,体积只有CSV的1/5到1/10
  • 谓词下推:查询时只读取需要的列和行,IO开销小
  • Schema自描述:文件里自带字段定义,不用额外维护元数据

但Parquet也有缺点:写入速度慢,不适合实时写入。而且读取时需要反序列化,延迟在毫秒级。

Arrow:内存中的利器

Arrow是专门为「零拷贝」设计的。数据在内存里就是列式排布的,CPU可以直接访问,不需要序列化/反序列化。

Arrow的核心优势:

  • 读取延迟在微秒级,比Parquet快两个数量级
  • 支持向量化计算,配合NumPy/Pandas效率极高
  • 跨语言共享内存,C++写的策略可以直接读Python写的数据

但Arrow是内存格式,持久化到磁盘时,其实还是需要转成Parquet或Feather。

我的建议是:

  • 历史数据存储:用Parquet,压缩率高,查询方便
  • 实时计算管道:用Arrow,低延迟,零拷贝
  • 两者结合:磁盘存Parquet,加载到内存后转Arrow做计算

知识体系总览

下面这张图,是我自己梳理的Tick数据结构知识体系。你们可以保存下来,当个地图用。

Tick级数据结构知识体系 Tick数据 Level1 行情 Level2 行情 存储格式 买一/卖一 最新成交价 成交量/额 开高低收 多档买卖盘 逐笔成交 逐笔委托 委托序号 Parquet Arrow Order Book 订单簿构建 增量更新 全量快照 乱序处理 时间同步 核心:数据质量 > 策略复杂度

这张图把今天讲的内容串起来了。从Level1到Level2,再到订单簿构建和存储格式,每一步都有坑,也都有技巧。

最后分享一个我的习惯:每次接入新的数据源,我都会先花一周时间做数据质量检查。检查时间戳是否连续、价格是否有跳变、买卖盘是否平衡。这些脏数据,才是策略最大的敌人。

好了,Tick数据结构这块,咱们今天就聊到这儿。记住一句话:数据是高频交易的基石,地基不牢,楼盖得再高也得塌。

专注资料整理