4、数据完整性验证规则:检查历史数据缺失、异常值检测、复权数据一致性、数据源切换校验

数据完整性是量化回测可信度的基石。任何数据层面的缺陷都会直接传导至策略评估结果,产生“垃圾进,垃圾出”的效应。本章围绕四个核心维度展开:缺失值检测、异常值识别、复权数据一致性校验以及数据源切换的平滑验证。以下逐一拆解验证规则与工程实现要点。

核心原则:数据完整性验证应作为灰度发布流程中的前置关卡(Gate),未通过校验的数据集不得进入策略回测管道。

4.1 历史数据缺失检测

缺失数据在时间序列中表现为“空洞”,常见原因包括:交易所休市未对齐、数据采集故障、存储写入失败等。检测规则需区分连续缺失与随机缺失,并设定容忍阈值。

缺失类型 检测方法 阈值建议 处理动作
交易日连续缺失 对比交易日历,检查连续缺失天数 连续缺失 ≤ 3 个交易日 前向填充或插值;超过阈值则标记该段不可用
日内 Tick 缺失 统计每分钟/每秒的 Tick 数量 每分钟 Tick 数 ≥ 预期值的 80% 缺失比例过高时,该交易日整体剔除
随机单点缺失 相邻时间戳差值检测 单点缺失占比 ≤ 总样本的 0.1% 线性插值修复,并记录日志
# 缺失检测伪代码示例
def detect_missing(data, calendar):
    missing_segments = []
    for symbol in data.columns:
        full_index = calendar[calendar.between(data.index.min(), data.index.max())]
        missing_dates = full_index.difference(data.index)
        for gap in find_consecutive_gaps(missing_dates):
            if gap.days > 3:
                missing_segments.append((symbol, gap.start, gap.end))
    return missing_segments
工程建议:将交易日历作为独立配置文件管理,支持多交易所(如 SSE、SZSE、HKEX)的休市差异,避免因日历不匹配导致误报。

4.2 异常值检测

异常值通常由数据录入错误、极端市场事件或系统噪声引起。检测方法需兼顾统计稳健性与业务语义。

  • 统计方法:基于 Z-Score(阈值 |Z| > 3)或 IQR(下界 Q1-1.5×IQR,上界 Q3+1.5×IQR)。
  • 业务规则:价格不能为负、涨跌幅超过交易所限制(如 A 股 ±10%)、成交量突变为前 N 日均值的 50 倍以上。
  • 上下文校验:复权因子突变、除权除息日前后价格跳跃未对齐。
# 异常值检测示例(IQR 方法)
def detect_outliers_iqr(series, factor=1.5):
    Q1 = series.quantile(0.25)
    Q3 = series.quantile(0.75)
    IQR = Q3 - Q1
    lower_bound = Q1 - factor * IQR
    upper_bound = Q3 + factor * IQR
    return series[(series < lower_bound) | (series > upper_bound)]
注意:异常值检测应区分“数据错误”与“真实极端事件”(如 2015 年股灾、2020 年原油负值)。建议保留极端事件标签,供策略开发者手动审核,而非自动剔除。

4.3 复权数据一致性校验

复权数据是回测中计算收益率的基础。前复权与后复权若不一致,将导致收益率曲线失真。校验规则需覆盖以下维度:

校验项 方法 通过标准
复权因子连续性 检查复权因子序列是否单调且无突变 相邻因子变化率 < 5%
前/后复权收益率一致性 计算同一区间的前复权与后复权收益率 收益率差异 < 1e-6
除权除息日对齐 对比复权因子调整日与公司行动公告日 日期偏差 ≤ 1 个交易日
复权价格与原始价格关系 验证复权价格 = 原始价格 × 复权因子 最大相对误差 < 1e-8
# 复权一致性校验示例
def check_adjustment_consistency(price_raw, price_adj, factor):
    reconstructed = price_raw * factor
    max_error = (price_adj - reconstructed).abs().max()
    return max_error < 1e-8
最佳实践:在灰度发布环境中,同时保留原始价格、复权因子和复权价格三个字段。任何复权逻辑的修改都必须重新跑通上述四项校验。

4.4 数据源切换校验

灰度发布过程中,数据源可能从旧供应商切换到新供应商(如从 Wind 切换至聚宽或自建数据库)。切换校验的核心是保证两个数据源在重叠时间窗口内的输出一致。

  • 时间窗口对齐:选取至少 3 个月的重叠区间,覆盖不同市场状态(上涨、下跌、震荡)。
  • 字段级对比:对 Open、High、Low、Close、Volume、AdjFactor 等关键字段逐行比对。
  • 容忍度设定:价格差异 ≤ 0.001%(因四舍五入或小数精度差异),成交量差异 ≤ 0.01%。
  • 异常事件覆盖:必须包含除权除息日、停复牌日、涨跌停日等特殊日期。
# 数据源切换校验示例
def compare_sources(source_a, source_b, tolerance=1e-5):
    merged = source_a.join(source_b, lsuffix='_a', rsuffix='_b')
    diff = (merged['close_a'] - merged['close_b']).abs()
    max_diff = diff.max()
    return max_diff < tolerance, max_diff
灰度发布策略:数据源切换应采用“影子模式”——新数据源与旧数据源并行运行至少 2 周,所有回测任务同时使用两个数据源执行,对比结果一致后方可切换。

4.5 数据完整性验证流程总览

以下 SVG 图展示了数据完整性验证在灰度发布管道中的执行顺序与依赖关系。

数据完整性验证灰度发布流程 原始数据入库 缺失值检测 异常值检测 复权一致性校验 数据源切换校验 灰度发布决策 校验失败处理 • 缺失超阈值 → 标记不可用 • 异常值 → 人工审核 • 复权不一致 → 回滚数据版本 • 数据源差异 → 延迟切换

4.6 灰度发布中的校验执行策略

在灰度发布的不同阶段,数据完整性验证的粒度与频率应动态调整:

灰度阶段 校验范围 执行频率 失败处理
内部测试(Canary) 全量历史数据(5 年+) 每次数据更新后 阻断发布,自动回滚
小范围用户 近 1 年数据 + 实时流 每日定时校验 告警 + 人工确认
全量发布 增量数据 + 抽样全量 每小时增量校验 告警 + 降级至旧数据源
自动化集成:建议将数据完整性校验封装为独立的 CI/CD 管道步骤,使用 Apache Airflow 或 Prefect 编排,每次数据变更自动触发全流程校验,并生成可视化报告。