数据获取与清洗:Level2行情与资金流计算

做量化交易的朋友都知道一句话:垃圾进,垃圾出。数据质量不过关,再牛的策略也是白搭。今天咱们就来聊聊资金流模型的第一步——怎么拿到靠谱的Level2数据,怎么处理那些烦人的盘口挂单,以及如何计算逐笔成交的资金流。

我个人习惯把数据获取和清洗看作整个回测流程的「地基」。地基打不牢,后面建多高的楼都悬。好,咱们直接开干。

一、Level2行情数据从哪来?

Level2数据,说白了就是比普通行情更细一档的数据。普通行情只能看到五档买卖盘,Level2能看到十档,还能看到逐笔成交、委托队列这些核心信息。

目前国内能拿到Level2数据的渠道主要有这么几个:

  • 券商API:比如华泰、中信、国泰君安这些大券商,都有自研的量化接口
  • 第三方数据商:万得、聚宽、米筐、恒生聚源等
  • 交易所直连:这个门槛比较高,一般机构才用得上

我在项目中遇到过最头疼的问题——不同数据源的时间戳格式不统一。有的用毫秒,有的用微秒,还有的直接用字符串。你想想看,如果时间对不上,后面算资金流的时候全乱套了。

我的建议:刚开始做回测,别追求太复杂的数据源。先用聚宽或米筐的免费Level2数据跑通流程,等策略稳定了再考虑换更高质量的数据。

二、盘口挂单数据怎么处理?

盘口挂单数据,就是买卖双方的委托队列。Level2能看到十档,每档都有价格和委托量。但这里有个坑——挂单数据是动态变化的,每秒都在变。

我一般会做这几步处理:

  1. 去重:同一时刻的重复记录只保留一条
  2. 排序:按时间戳升序排列,确保顺序正确
  3. 对齐:把不同股票的盘口数据对齐到同一时间点
  4. 计算买卖压力:用买一至买十的总量减去卖一至卖十的总量

举个例子,假设某只股票的盘口数据长这样:

时间戳: 2024-01-15 09:30:00.123
买一: 10.00元, 1000手
买二: 9.99元, 2000手
...
卖一: 10.01元, 1500手
卖二: 10.02元, 1800手
...

我会计算一个「买卖压力比」:

买盘总量 = 1000 + 2000 + ... (前十档)
卖盘总量 = 1500 + 1800 + ... (前十档)
压力比 = 买盘总量 / 卖盘总量

压力比大于1,说明买方力量强;小于1,说明卖方占优。这个指标在后面的资金流模型里会用到。

注意:盘口数据里经常出现「撤单」的情况。我曾经因为没处理撤单,导致算出来的买卖压力比严重失真。后来加了个逻辑——如果某档委托量突然减少,就标记为撤单,不参与计算。

三、逐笔成交资金流怎么算?

逐笔成交数据,是Level2里最有价值的部分。它记录了每一笔成交的详细信息:成交时间、成交价格、成交量、买卖方向。

计算资金流的逻辑其实很简单:

  • 主动买入:以卖一价或更高价格成交的,算作买方主动
  • 主动卖出:以买一价或更低价格成交的,算作卖方主动
  • 中性成交:价格在买卖价之间的,算作中性

然后,资金流 = 主动买入金额 - 主动卖出金额。正值表示资金净流入,负值表示净流出。

嗯,这里要注意一个细节——大单和小单的处理方式不一样。我个人习惯把单笔成交金额超过50万的算作「大单」,低于5万的算作「小单」,中间的算「中单」。这样能更精细地分析资金流向。

核心公式: 净资金流 = Σ(主动买入金额) - Σ(主动卖出金额) 大单净资金流 = Σ(大单主动买入金额) - Σ(大单主动卖出金额)

四、数据清洗与对齐

数据清洗,说白了就是「去脏数据」。我总结了几类常见问题:

问题类型 表现 处理方法
缺失值 某段时间没有数据 向前填充或插值
异常值 价格或成交量明显偏离 用3σ原则剔除
重复值 同一笔数据出现多次 保留第一条,删除其余
时间错位 不同数据源时间不一致 统一转换为毫秒时间戳

数据对齐这块,我踩过不少坑。最典型的一次——盘口数据和逐笔成交数据的时间戳差了0.5秒,导致算出来的资金流方向完全反了。后来我强制要求所有数据源都统一到毫秒级时间戳,并且做了一次「时间对齐」:

# 伪代码示例
def align_data(tick_data, order_data):
    # 将两个数据集的时间戳统一到毫秒
    tick_data['time_ms'] = tick_data['timestamp'] // 1000000
    order_data['time_ms'] = order_data['timestamp'] // 1000000
    
    # 按毫秒时间戳合并
    merged = pd.merge(tick_data, order_data, on='time_ms', how='outer')
    
    # 向前填充缺失值
    merged = merged.fillna(method='ffill')
    
    return merged

你想想看,如果时间没对齐,后面算出来的资金流指标全是错的。回测结果再好也是假的。

五、知识体系总览

下面这张图,是我自己总结的数据获取与清洗的完整流程。你可以把它当作一个检查清单:

数据获取与清洗流程 Level2数据源 盘口挂单数据 逐笔成交数据 去重 & 排序 异常值处理 缺失值填充 时间戳对齐(统一到毫秒) 计算资金流(大单/中单/小单)

这张图把整个流程串起来了。从数据源开始,经过清洗、对齐,最后计算出资金流。每一步都不能跳过,每一步都有坑。

避坑指南:我曾经在数据对齐这一步偷懒,直接用默认的merge方式,结果发现盘口数据和成交数据差了整整1秒。后来我加了个「时间窗口匹配」的逻辑——允许前后0.5秒的偏差,效果好了很多。

好了,数据获取与清洗这部分就聊到这儿。记住一句话:数据质量决定策略上限。花80%的时间在数据上,剩下20%的时间写策略,这才是量化交易的正确姿势。


专注资料整理