3. 缺失行情概述

在证券停复牌与行情修复的整个工程链路中,缺失行情是最基础也最容易被低估的概念。很多量化策略回测表现优异、实盘却频频失效,根源往往不是模型本身,而是输入数据中隐藏的行情缺口。本节将从定义、成因、表现和影响四个层面,建立对缺失行情的完整认知。

一、什么是缺失行情

缺失行情,指在某一交易标的的行情时间序列中,本应存在却被遗漏、置空或异常中断的行情记录。它不等同于"停牌"——停牌是交易所正式披露的、有明确起止时间的状态;而缺失行情可能是停牌造成的,也可能是数据采集、传输、存储等环节引入的"非预期空洞"。

判断一条记录是否属于缺失行情,核心是回答三个问题:该时点标的是否处于可交易状态?该时点的行情是否本应产生?缺失是"真实无成交"还是"数据未到达"?只有厘清这三点,才能避免把正常无成交误判为数据缺失。

核心原理:行情数据的完整性由"时间轴 × 标的 × 字段"三维构成。缺失行情本质上是这个三维张量中的空洞。修复的目标不是简单填充数值,而是还原该空洞对应的真实市场状态。

二、缺失行情的产生原因

缺失行情的成因可归为四类,理解成因有助于在修复时选择正确的策略:

  • 制度性原因:停牌、涨跌停封板、临时停市、集合竞价无成交等。这类缺失有明确规则可循,属于"可预期缺失"。
  • 技术性原因:行情源推送丢包、网络抖动、采集程序崩溃、磁盘写入失败、时区或时间戳错位。这类缺失具有随机性和隐蔽性。
  • 标的性原因:新股上市首日、退市整理期、代码变更、跨市场转板等,导致标的在时间轴上出现"身份断层"。
  • 处理性原因:数据清洗规则过严误删、复权计算错误、多源合并时优先级冲突,人为制造了缺口。

其中技术性与处理性原因最危险,因为它们不伴随任何官方公告,策略开发者往往在回测中"看不见"这些空洞。

三、常见表现形态

缺失行情在数据层面有多种表现,识别它们是修复的第一步:

表现形态典型特征常见成因
整段缺失连续多分钟/多日无任何记录停牌、采集中断
单点缺失时间轴上孤立跳空一个tick或K线丢包、写入失败
字段缺失记录存在但价格/成交量字段为空或为0解析错误、字段映射错位
时间戳错位记录存在但时间偏移或重复时区、时钟同步问题
伪连续用前值填充后看似连续,实则失真不当的填充处理

需要特别警惕"伪连续":它表面上没有缺口,但填充值会污染波动率、成交量和因子计算,是量化分析中最隐蔽的陷阱。

缺失行情在时间轴上的表现形态 t0 tN 正常行情 整段缺失(停牌) 单点缺失(丢包) 字段缺失示例 时间戳 价格 成交量 09:30:00 10.25 1200 09:30:03 -- 0 09:30:06 10.26 800

四、对量化分析与交易的影响

缺失行情对量化体系的影响是系统性的,可归纳为四个层面:

  1. 因子计算失真:动量、波动率、换手率等因子依赖连续价格序列。一个被前值填充的缺口会人为压低波动率,使策略低估风险。
  2. 回测结果虚高:若缺失被错误填充为"可成交",回测会假设在根本不存在的价格上完成交易,产生虚假收益。
  3. 信号错位:时间戳错位会导致信号与真实市场时刻不匹配,实盘中表现为"追高杀跌"。
  4. 风控失效:停牌期间若数据被填充为连续行情,风控模块无法识别流动性枯竭,可能触发错误平仓或加仓。

误区警示:很多开发者习惯用 ffill() 一键填充所有缺失。这在停牌场景下会制造"虚假连续交易",在丢包场景下会掩盖真实缺口。正确做法是先分类缺失类型,再选择填充、标记或剔除策略。

五、识别与初步处理流程

面对一份行情数据,建议按以下流程快速定位缺失:

# 1. 构建完整时间轴(以交易日历为准)
full_index = trading_calendar(start, end, freq='1min')

# 2. 重索引,暴露缺口
df = df.reindex(full_index)

# 3. 分类缺失:停牌 / 无成交 / 技术缺失
missing = df[df['close'].isna()]
suspended = missing.index.isin(suspend_records)
tech_gap = missing.index.difference(suspend_records)

# 4. 输出缺失报告
print(f"总缺失: {len(missing)}, 停牌: {len(suspended)}, 技术缺失: {len(tech_gap)}")

复盘要点:缺失行情的处理质量,直接决定后续停复牌修复和因子计算的可靠性。建议在数据入库阶段就建立缺失监控看板,按标的、按日期统计缺失率,把"看不见的空洞"变成"可度量的指标"。