数据与算法

金融时序数据缺失值插补:量化回测中的精度修正方案

df["close"] = df["close"].ffill()

金融时序数据缺失值插补:量化回测中的精度修正方案

这行代码可以修复一段价格序列。也可以直接制造前瞻偏差。区别不在语法,而在执行时点、缺失机制和字段语义。

量化回测中的缺失值不是普通表格里的空单元格。价格缺失、成交量缺失、因子缺失、交易日缺失,分别对应不同的数据生成过程。统一填充,等于把不同的随机变量强行归入同一个分布。结果通常不稳定。

金融时序数据缺失值插补的目标,不是让数据表看起来完整。目标是让回测使用的信息集合与真实交易时点一致。任何使用未来数据完成当前修复的操作,都会改变策略的统计性质。

缺失值先分类,再决定是否插补

金融时序中的缺失机制通常分为三类:

1. 完全随机缺失,即缺失与当前变量、其他变量及时间状态都无关。英文称为完全随机缺失,简称 MCAR。

2. 随机缺失,即缺失概率与其他已观测变量有关,但在控制这些变量后,与缺失值本身无关。英文称为随机缺失,简称 MAR。

3. 非随机缺失,即缺失概率直接依赖未观测值或其隐含状态。英文称为非随机缺失,简称 MNAR。

这三个分类不是统计学装饰。它们决定了删除、前向填充、模型插补是否会改变样本分布。

完全随机缺失:可以考虑删除

如果一列因子随机丢失少量记录,缺失比例低于 5%,且缺失位置没有明显的时间聚集,删除对应样本通常比强行插补更干净。

删除法的前提有三个:

  • 缺失比例低;
  • 缺失位置没有集中在开盘、收盘或极端波动区间;
  • 被删除样本不会改变标签分布和交易信号分布。

例如,一个日频横截面因子只有少量随机缺失。直接删除对应股票当天的因子记录,可能只减少少量样本。此时用均值填充,反而会压缩截面方差,改变因子的排序结果。

截面排序策略尤其敏感。假设某个因子原本服从近似正态分布,缺失值全部填充为截面均值。均值附近的股票数量会被人为增加。因子排名的尾部结构被削弱。多空组合的分位数边界也会移动。

这不是数据完整性问题。是分布问题。

随机缺失:需要建模变量之间的关系

如果成交量缺失与交易状态、证券类别、交易所或其他已观测字段有关,但并不直接依赖缺失的成交量本身,可以使用多变量插补。

这类场景通常出现在:

  • 多因子数据中部分指标缺失;
  • 基本面数据更新日期不一致;
  • 不同数据供应商的字段覆盖范围不同;
  • 日频价格、成交量、波动率和行业因子存在局部缺口。

这里不能只看单列缺失率。还要看缺失与其他变量的相关结构。

如果某个因子只在小盘股中缺失,整体缺失率可能不高,但缺失不是随机分布。直接删除会改变股票池结构。填充为均值则会把小盘股推向截面中心。两种处理都会影响组合暴露。

非随机缺失:插补本身可能改变研究结论

非随机缺失更难处理。

例如,极端行情下数据源中断。缺失发生在波动率突然升高、价格跳跃或成交量急剧放大的时段。缺失概率与市场状态直接相关。此时缺失不是噪声,而是状态变量的一部分。

如果把这些缺失记录按普通日处理,得到的回测收益可能被平滑。最大回撤、波动率和换手率都会被低估。

对非随机缺失,第一步通常不是插补,而是定位缺失的产生原因:

  • 数据源是否在特定时段中断;
  • 某个交易所是否存在独立缺口;
  • 缺失是否集中在涨跌停、停牌或开闭市附近;
  • 缺失前后是否出现时间戳跳跃;
  • 缺失是否只发生在某些合约、品种或证券状态下。

没有原因模型时,插补只能生成一个形式完整的数据集。不能证明它接近真实路径。

回测数据的完整,不等于信息集合的真实。填满空值只是表面修复,防止未来信息进入当前时点才是核心约束。

价格序列:前向填充是默认方案,不是万能方案

价格数据通常以时间索引排列。缺失值出现在某个时间点时,最容易犯的错误是直接使用后面的观测值反推当前价格。

后向填充为什么会产生前瞻偏差

假设时间序列如下:

时间收盘价
09:30100
09:31缺失
09:32102

如果在 09:31 使用后向填充,得到的价格是 102。这个值在 09:31 的交易决策中不可获得。它来自 09:32。

回测程序不会因为代码运行在历史数据上,就自动遵守时间约束。bfill 只按照数组顺序填值。它不知道策略在 09:31 是否已经完成下单。

线性插值也有相同问题。09:31 的插值结果通常依赖 09:30 和 09:32 两个端点。后一个端点属于未来信息。样条插值使用的邻域更大,未来数据范围可能更长。平滑程度提高,因果性消失。

因此,价格序列的 bfilllinear 不能作为无条件默认值。它们适合离线可视化、数据探索或明确不参与历史决策的展示数据。不适合作为标准回测输入。

前向填充的因果性

前向填充使用最近一次已经观测到的价格:

时间原始收盘价前向填充后
09:30100100
09:31缺失100
09:32102102

09:31 使用 09:30 的信息。没有读取 09:32。因果关系成立。

在价格未发生有效交易、数据只是在时间轴上留下空洞时,前向填充通常是合理的基础处理。它保留最后已知状态,不生成新的价格路径。

但前向填充也有边界:

  • 缺失持续时间过长时,旧价格不能代表当前市场;
  • 跨越交易日时,前一交易日收盘价不一定适合填充下一交易日的所有字段;
  • 合约换月、复权调整和交易状态变化时,旧价格的语义可能已经失效;
  • 盘口数据中买一价、卖一价和中间价不能简单等同处理;
  • 长缺口会让收益率序列出现人为零波动。

因此,ffill 应当配合最大连续缺失长度。短缺口可以前向填充。超过阈值的长缺口,应保留为缺失,或直接剔除对应样本。

价格字段不能混用填充规则

常见的价格字段包括开盘价、最高价、最低价、收盘价和结算价。它们不是同一个变量。

对 OHLC 数据直接按列统一前向填充,会产生结构约束错误。假设某根 K 线的开盘价缺失,但最高价和最低价仍然存在。使用上一根 K 线的开盘价填充当前开盘价,可能导致:

  • 开盘价高于当前最高价;
  • 开盘价低于当前最低价;
  • 当前 K 线的价格范围不再闭合;
  • 基于真实波幅的指标出现异常。

如果整根 K 线缺失,处理方式与单字段缺失不同。整根缺失可能表示没有交易、数据源中断或时间戳错误。不能把它简单视为价格保持不变。

在日频股票数据中,非交易日通常不应被补成交易日。交易日历先于插值规则。把周末和节假日加入连续时间索引,再对收盘价做前向填充,会制造虚假的持仓日和收益率路径。

成交量缺失:零值代表无交易,不代表未知价格

成交量字段的默认处理与价格不同。

证券交易中,成交量缺失通常填充为 0,表示该时间段没有成交。不能使用价格类的均值填充,也不能直接沿用上一时点成交量。

字段常见默认处理统计含义
收盘价前向填充延续最近一次已知价格状态
成交量填充为 0该时间段没有成交
换手率结合流通股本和成交量重新计算避免独立插值破坏变量关系
波动率通常不直接填充需要依据原始价格窗口重新计算
技术指标由清洗后的原始序列重算避免填充中间结果
交易状态使用交易所或数据源状态字段不应由价格推断

成交量为 0 会影响许多指标,但这是正确的影响。成交量加权平均价、资金流量指标、量价相关系数、成交量移动平均都应看到真实的零成交状态。

如果将缺失成交量填成均值,相当于在没有交易的时间段制造成交。策略中的流动性过滤、冲击成本、成交量突破和成交量异常检测都会被改变。

价格与成交量必须保持联合逻辑

价格不动、成交量为 0,可能是合法状态。价格缺失、成交量为 0,则需要进一步判断。两者的组合不能仅凭单列规则处理。

可以建立简单的状态检查:

  • 价格缺失且成交量为 0:可能是无交易,也可能是数据断档;
  • 价格存在且成交量缺失:优先确认数据源字段是否独立中断;
  • 最高价、最低价存在但收盘价缺失:检查 K 线是否完整;
  • 成交量为正但全部价格缺失:通常不能直接填充,应追溯原始记录;
  • 同一时刻所有证券同时缺失:更像数据源或接口级故障,而非个别资产问题。

这一层判断不依赖复杂机器学习。依赖字段之间的约束。

缺失比例不是唯一阈值,连续缺口更危险

整体缺失率容易计算。也容易误导。

某列总共缺失 4%,看起来低于常用的 5%删除阈值。但如果这 4%全部集中在连续的一周,影响可能高于分散在全年各处的 8%缺失。时间序列对连续缺口更敏感。

至少要同时统计以下指标:

1. 总缺失率:缺失记录数除以总记录数。

2. 最长连续缺口:连续缺失的最大长度。

3. 缺失区间数量:缺失是否由少数长区间组成。

4. 缺失时间分布:是否集中在开盘、收盘、夜盘或结算时段。

5. 资产覆盖率:缺失是否只影响少数证券,还是全市场同步出现。

6. 标签重叠率:缺失区间是否与未来收益、极端波动或交易信号重叠。

单一比例无法描述时间结构。

例如,分钟数据中连续缺失 30 个时间点,可能意味着半小时没有成交,也可能意味着数据接口中断。对于低频策略,30 个点未必影响模型。对于低延迟策略,它可能直接破坏信号计算。

缺失率阈值的使用方式

在工程实践中,可以采用分层规则:

  • 缺失比例低于 5%,且缺失近似随机:优先考虑删除或局部插补;
  • 某特征缺失率高于 30%,且与目标变量及其他特征关联弱:考虑剔除该特征;
  • 短时间价格缺口:使用前向填充,并限制最大连续填充长度;
  • 成交量缺失:默认填充为 0,同时记录填充标记;
  • 长时间连续缺失:不强行恢复,保留缺失或剔除相关区间;
  • 缺失与极端行情同步:按非随机缺失处理,单独做敏感性分析。

这些阈值是数据清洗的起点,不是策略性能的证明。阈值本身也需要在不同市场、不同频率和不同资产类别上复核。

多因子截面:MICE不是自动正确

多重插补法,也称 MICE,适合处理多变量数据中的缺失。它不是一次均值填充,而是通过链式方程迭代预测缺失变量,并生成多套完整数据集。

MICE 的基本逻辑可以拆成四步:

1. 为每个含缺失的变量建立条件模型;

2. 使用其他变量预测当前变量的缺失值;

3. 轮换变量,重复迭代;

4. 生成多套完整数据集,再汇总估计结果。

默认情况下,MICE 通常生成 5 套数据集。实际使用范围可以是 3 到 10 套,具体取决于缺失比例、计算资源和估计稳定性。

为什么要生成多套数据集

单次插补会把一个不确定的缺失值变成确定值。模型后续会把它当成真实观测。方差通常被低估。

多重插补保留了缺失值的不确定性。每套数据集使用不同的预测结果,最终对参数或预测结果进行汇总。这样可以观察插补不确定性对模型输出的影响。

这点对因子研究尤其重要。因子回测不只关心均值,还关心:

  • 因子收益的标准差;
  • 分层组合之间的差异;
  • 信息系数的稳定性;
  • 极端分位数的排序;
  • 因子与行业、规模、波动率的联合暴露。

单次均值填充会压缩方差。MICE 至少能避免把所有缺失值固定在同一个中心点。

MICE在时间序列中的限制

MICE 默认处理的是变量之间的条件关系。金融时间序列还具有时间顺序、滚动依赖和信息可得性约束。

如果用全样本数据拟合插补模型,再把结果用于历史回测,未来截面和未来时期的信息可能进入当前记录。即使 MICE 的统计结果稳定,回测仍然存在前瞻偏差。

正确方式是将插补过程纳入训练窗口:

  • 在时间点 \(t\) 之前拟合插补模型;
  • 只使用 \(t\) 之前可获得的数据;
  • 对 \(t\) 的缺失值执行插补;
  • 向前滚动窗口;
  • 保存每次插补模型的参数和训练范围。

不能先对全量历史数据运行 MICE,再切分训练集和测试集。这样会发生数据泄漏。

MICE的变量选择

插补变量需要具备解释力,也需要满足时间约束。常见候选变量包括:

  • 同一资产的历史收益和波动率;
  • 同期行业或风格因子;
  • 市值、估值、盈利能力等截面变量;
  • 成交量、换手率和流动性指标;
  • 交易状态和上市时间;
  • 可获得的宏观或市场宽度指标。

不应把未来收益、未来价格、未来财务指标直接放入插补方程。即使它们能够提高插补精度,也会让策略回测脱离真实交易环境。

MICE 还可能生成不符合业务约束的值。例如成交量被预测为负数,比例变量超出合理区间,价格关系不满足最高价不低于最低价。插补结果必须做边界修正和逻辑校验。

MICE适用的边界

MICE 更适合多因子截面数据,不适合无条件替代价格路径修复。

价格序列的缺失通常具有明确的时间因果约束。使用多变量预测生成价格,容易把相关变量中的未来信息带回当前时点。除非插补模型严格按滚动窗口构建,并且经过时间切分验证,否则不应把 MICE 作为价格字段的默认方法。

树模型可以接受缺失,不代表数据可以不清洗

部分梯度提升树模型,例如 XGBoost 和 LightGBM,具备原生缺失值处理能力。模型可以在分裂过程中为缺失值学习默认方向。

这解决的是模型输入问题。没有解决数据语义问题。

原生缺失处理的实际含义

树模型遇到缺失值时,可能学习出一条路径:

  • 缺失值向左分支;
  • 非缺失值按照阈值分支;
  • 缺失本身成为一个具有预测力的状态。

如果缺失由数据源故障产生,模型可能学到故障模式,而不是资产规律。训练集中的数据中断与目标收益恰好重合时,缺失指示就会成为隐含标签。

因此,即使模型能接受 NaN,也应保留缺失标记,并检查缺失是否具有非随机结构。

可以同时构造两个字段:

  • 原始变量,保留缺失;
  • 缺失指示变量,缺失为 1,非缺失为 0。

这样可以区分数值信息与缺失状态。是否保留缺失指示,取决于缺失机制和样本外稳定性。

传统模型的输入适配

线性回归、支持向量机、K 近邻等传统模型通常不能直接处理含 NaN 的输入。直接传入缺失值可能导致训练报错,或者在预处理阶段被拒绝。

适配方式包括:

  • 中位数填充;
  • 分组均值填充;
  • MICE 多重插补;
  • 增加缺失指示变量;
  • 删除缺失样本;
  • 使用专门的缺失值编码。

但填充方式要与模型含义匹配。

对线性模型,均值填充后增加缺失指示变量,可以部分区分“真实均值”和“原本缺失”。对 K 近邻,特征尺度和距离度量会被填充值直接影响。对支持向量机,标准化通常需要在填充之后执行,且标准化参数只能由训练集估计。

预处理顺序不能混乱:

1. 按时间切分训练集和测试集;

2. 只用训练集估计填充值、缩放参数和编码规则;

3. 将同一组参数应用到验证集与测试集;

4. 在滚动回测中重新拟合预处理器;

5. 保存每个时间窗口的处理状态。

如果先对全样本做标准化和插补,再切分数据,数据泄漏已经发生。

模型对比表

处理方式是否使用未来数据适用字段主要风险
前向填充不使用,只依赖历史观测短缺口价格、状态变量长缺口导致旧值滞留
后向填充使用缺失时点之后的数据展示数据、非回测分析产生前瞻偏差
线性插值通常使用未来端点非交易决策的平滑数据改变真实价格路径
成交量填 0不使用未来数据成交量、无交易区间需确认确实代表无交易
MICE取决于训练窗口多因子截面数据全样本拟合造成泄漏
树模型原生处理不必先填充部分机器学习特征学到数据故障模式
删除样本不使用未来数据低比例随机缺失改变样本分布

回测清洗流水线:先诊断,后插补

一个可复用的清洗流程应当把缺失诊断、插补和验证分开。不能在读取数据后直接调用 fillna

第一步:统一时间轴与交易日历

先确定数据频率、时区、交易所和交易日历。时间戳必须排序。重复时间戳必须处理。跨市场数据需要统一时间基准。

如果时间轴本身错误,后续所有缺失统计都不可信。

需要区分:

  • 没有交易的时间点;
  • 有交易但数据缺失的时间点;
  • 交易所休市时间;
  • 夜盘与日盘之间的自然间隔;
  • 合约到期、停牌和上市前后的空区间。

不能把不存在的交易时间当作缺失值。交易日历是数据语义的一部分。

第二步:统计单列和联合缺失

单列缺失率只提供第一层信息。还需要记录缺失组合。

例如:

  • 价格缺失,成交量也缺失;
  • 价格存在,成交量缺失;
  • 因子缺失但行情存在;
  • 多个资产在同一时间同时缺失;
  • 同一资产连续缺失但其他资产正常。

联合缺失模式可以帮助定位故障层级。单个字段缺失,可能是字段计算问题。全市场同步缺失,更可能是接口或数据源中断。

第三步:检查缺失与收益分布的关系

把缺失指示变量与未来收益、波动率、成交量变化进行分组比较。不是为了寻找一个显著关系,而是为了发现数据生成机制。

如果缺失样本的未来收益分布与非缺失样本明显不同,需要进一步确认:

  • 缺失是否集中在特定行情状态;
  • 缺失是否来自停牌或交易限制;
  • 缺失是否由数据源截断造成;
  • 缺失指示是否被模型当作预测信号。

不能直接把这种差异解释为策略信号。它也可能只是数据错误的副产品。

第四步:按字段定义插补规则

建立字段级规则,而不是建立一个全局填充函数。

价格字段可以使用受限前向填充。成交量字段通常填充为 0。因子字段根据截面结构选择删除、分组统计量或 MICE。技术指标则在原始字段处理后重新计算。

重新计算比直接填充指标更可靠。比如移动平均、波动率和相对强弱指标都依赖历史窗口。中间价格被插补后,指标应该从修复后的原始价格重新生成。

第五步:保留插补标记

每一次插补都应留下标记。至少包括:

  • 是否发生插补;
  • 使用了哪种方法;
  • 连续缺失长度;
  • 插补发生的时间;
  • 插补前的原始值状态;
  • 是否因为超过阈值而被删除。

不保留标记,后续无法判断模型使用的是原始数据还是人工生成数据。也无法在策略异常时定位数据处理环节。

第六步:做双路径回测

至少运行两套结果:

  • 原始缺失数据经过严格删除;
  • 经过规则化插补后的数据。

比较以下指标:

  • 年化收益;
  • 波动率;
  • 最大回撤;
  • 换手率;
  • 交易次数;
  • 资金曲线的缺口;
  • 信号触发数量;
  • 不同时间窗口的稳定性。

这里不追求某一种处理结果更高。若插补后收益显著提升,首先应怀疑未来信息、零成交误判或样本删除规则,而不是接受结果。

插补带来的收益如果只出现在单一时间窗口,优先按数据泄漏处理,而不是按模型增强处理。

典型错误:看似合理,实际改变了回测因果结构

错误一:全表直接 fillna(method="bfill")

后向填充可以快速消除空值,但把未来价格复制到过去。对历史策略而言,这属于直接的前瞻偏差。

如果策略使用收盘价计算信号,并在下一根 K 线交易,缺失收盘价被后向填充后,未来 K 线的信息会进入当前信号。收益曲线通常会变得异常平滑。

错误二:所有列统一使用均值

价格、成交量、换手率、波动率和分类变量的统计含义不同。统一均值填充没有数据语义。

价格均值会生成不存在的交易路径。成交量均值会制造虚假交易。波动率均值会压缩风险。分类变量的均值甚至没有定义。

错误三:先插补,再切分训练集和测试集

这是最常见的数据泄漏路径之一。

全样本插补器已经看到测试期的数据分布。即使填充公式中没有显式使用未来收益,测试期变量的均值、方差、相关性也可能进入训练期数据。

正确顺序是先按时间切分,再在训练区间拟合插补规则。

错误四:把长缺口当成短缺口处理

前向填充适用于短时缺口。连续缺失跨越较长区间时,旧价格会被复制太久。收益率序列出现大量零值,波动率被压低,交易信号被延迟。

必须设置最大连续填充长度。超过长度后保留缺失,或者删除相关样本。

错误五:用未来收益选择插补方式

如果根据某种插补方法在历史区间产生的收益高低,直接选择全样本最优方法,等于用目标变量优化预处理流程。

插补规则也需要样本外验证。选择标准应包括数据完整性、因果约束和多窗口稳定性,而不是只看净值曲线。

参数优化与模型边界

金融时序数据缺失值插补没有跨市场、跨频率、跨策略的绝对最优方案。可以优化参数,但不能优化因果关系。

可以优化的参数

  • 前向填充允许的最大连续长度;
  • 删除样本的缺失率阈值;
  • 特征剔除的缺失率阈值;
  • MICE 的迭代次数;
  • MICE 的数据集数量;
  • 插补模型的训练窗口;
  • 缺失指示变量是否加入预测模型;
  • 不同资产类别的独立填充规则。

默认多重插补数据集数量通常为 5。可以在 3 到 10 之间做稳定性比较。但增加数据集数量不会修复错误的变量选择,也不会消除未来信息。

不应优化的部分

不能让测试集决定:

  • 是否使用后向填充;
  • 是否使用线性插值;
  • 哪个时间段被删除;
  • 哪些未来变量加入插补模型;
  • 哪个缺失比例阈值能产生最高收益。

这些选择一旦由测试结果驱动,回测就从验证工具变成了拟合工具。

需要保存的审计信息

数据清洗流程应输出可审计日志:

  • 原始记录数量;
  • 各字段缺失数量;
  • 每个字段使用的处理方式;
  • 被删除的资产和时间区间;
  • 前向填充的最大连续长度;
  • MICE 训练窗口与变量集合;
  • 插补前后的分布统计;
  • 测试集是否出现训练期不存在的缺失模式。

日志不是附加功能。它是回测可复现性的组成部分。

结论:先守住时间顺序,再讨论插补精度

金融时序数据缺失值插补的核心,不是寻找最复杂的算法。是保证每个时点只使用当时可获得的信息。

价格短缺口,优先使用受限的前向填充。后向填充和线性插值容易使用未来节点,不应作为量化回测价格序列的默认方案。成交量缺失,通常填充为 0,但前提是该缺失确实表示无交易,而不是数据源中断。多因子截面可以考虑 MICE,但插补模型必须按时间滚动拟合。XGBoost、LightGBM 等树模型能够原生处理部分缺失值,但这不等于可以跳过数据诊断。

最终流程可以压缩为四个动作:

1. 识别缺失机制;

2. 按字段语义制定规则;

3. 将插补过程限制在历史信息集内;

4. 使用多路径回测验证处理结果的稳定性。

如果一套策略只有在后向填充、全样本 MICE 或统一均值填充后才表现良好,问题通常不在预测模型。问题在数据流水线。

参数可以优化。时间顺序不能。

相关阅读: 交易员决策疲劳应对策略:减少日内无效交易的系统化方案全职交易员的社交孤立:享受孤独还是走向心理失衡?.

常见问题

金融时序数据缺失值应该如何处理?
应先判断缺失是完全随机、随机还是非随机,再结合字段语义决定删除、局部插补或保留缺失。还要检查缺失的连续长度、时间分布、资产覆盖范围及其与行情状态的关系。
为什么量化回测不建议对价格数据使用后向填充?
后向填充会把缺失时点之后的价格复制到当前时点,导致未来信息进入历史交易决策。线性插值通常也依赖未来端点,因此不适合作为回测价格序列的默认方法。
价格序列缺失时可以使用前向填充吗?
在价格未发生有效交易、只是时间轴出现短缺口时,前向填充通常可以延续最近一次已知价格状态。缺失持续过长、跨越交易日或遇到合约换月等情况时,应限制填充长度,必要时保留缺失或剔除相关区间。
成交量缺失为什么通常填充为零?
成交量填充为零表示该时间段没有成交,能够保留成交量指标和流动性过滤的真实含义。但如果缺失实际来自数据源中断,就不能直接填零,需要结合价格、交易状态和其他字段进一步判断。
MICE可以直接用于价格序列缺失值插补吗?
MICE更适合多因子截面数据,不应无条件替代价格路径修复。用于回测时,插补模型必须只使用当时及此前可获得的数据,并按时间滚动拟合,否则可能产生数据泄漏。