这行代码可以修复一段价格序列。也可以直接制造前瞻偏差。区别不在语法,而在执行时点、缺失机制和字段语义。
量化回测中的缺失值不是普通表格里的空单元格。价格缺失、成交量缺失、因子缺失、交易日缺失,分别对应不同的数据生成过程。统一填充,等于把不同的随机变量强行归入同一个分布。结果通常不稳定。
金融时序数据缺失值插补的目标,不是让数据表看起来完整。目标是让回测使用的信息集合与真实交易时点一致。任何使用未来数据完成当前修复的操作,都会改变策略的统计性质。
缺失值先分类,再决定是否插补
金融时序中的缺失机制通常分为三类:
1. 完全随机缺失,即缺失与当前变量、其他变量及时间状态都无关。英文称为完全随机缺失,简称 MCAR。
2. 随机缺失,即缺失概率与其他已观测变量有关,但在控制这些变量后,与缺失值本身无关。英文称为随机缺失,简称 MAR。
3. 非随机缺失,即缺失概率直接依赖未观测值或其隐含状态。英文称为非随机缺失,简称 MNAR。
这三个分类不是统计学装饰。它们决定了删除、前向填充、模型插补是否会改变样本分布。
完全随机缺失:可以考虑删除
如果一列因子随机丢失少量记录,缺失比例低于 5%,且缺失位置没有明显的时间聚集,删除对应样本通常比强行插补更干净。
删除法的前提有三个:
- 缺失比例低;
- 缺失位置没有集中在开盘、收盘或极端波动区间;
- 被删除样本不会改变标签分布和交易信号分布。
例如,一个日频横截面因子只有少量随机缺失。直接删除对应股票当天的因子记录,可能只减少少量样本。此时用均值填充,反而会压缩截面方差,改变因子的排序结果。
截面排序策略尤其敏感。假设某个因子原本服从近似正态分布,缺失值全部填充为截面均值。均值附近的股票数量会被人为增加。因子排名的尾部结构被削弱。多空组合的分位数边界也会移动。
这不是数据完整性问题。是分布问题。
随机缺失:需要建模变量之间的关系
如果成交量缺失与交易状态、证券类别、交易所或其他已观测字段有关,但并不直接依赖缺失的成交量本身,可以使用多变量插补。
这类场景通常出现在:
- 多因子数据中部分指标缺失;
- 基本面数据更新日期不一致;
- 不同数据供应商的字段覆盖范围不同;
- 日频价格、成交量、波动率和行业因子存在局部缺口。
这里不能只看单列缺失率。还要看缺失与其他变量的相关结构。
如果某个因子只在小盘股中缺失,整体缺失率可能不高,但缺失不是随机分布。直接删除会改变股票池结构。填充为均值则会把小盘股推向截面中心。两种处理都会影响组合暴露。
非随机缺失:插补本身可能改变研究结论
非随机缺失更难处理。
例如,极端行情下数据源中断。缺失发生在波动率突然升高、价格跳跃或成交量急剧放大的时段。缺失概率与市场状态直接相关。此时缺失不是噪声,而是状态变量的一部分。
如果把这些缺失记录按普通日处理,得到的回测收益可能被平滑。最大回撤、波动率和换手率都会被低估。
对非随机缺失,第一步通常不是插补,而是定位缺失的产生原因:
- 数据源是否在特定时段中断;
- 某个交易所是否存在独立缺口;
- 缺失是否集中在涨跌停、停牌或开闭市附近;
- 缺失前后是否出现时间戳跳跃;
- 缺失是否只发生在某些合约、品种或证券状态下。
没有原因模型时,插补只能生成一个形式完整的数据集。不能证明它接近真实路径。
回测数据的完整,不等于信息集合的真实。填满空值只是表面修复,防止未来信息进入当前时点才是核心约束。
价格序列:前向填充是默认方案,不是万能方案
价格数据通常以时间索引排列。缺失值出现在某个时间点时,最容易犯的错误是直接使用后面的观测值反推当前价格。
后向填充为什么会产生前瞻偏差
假设时间序列如下:
| 时间 | 收盘价 |
|---|---|
| 09:30 | 100 |
| 09:31 | 缺失 |
| 09:32 | 102 |
如果在 09:31 使用后向填充,得到的价格是 102。这个值在 09:31 的交易决策中不可获得。它来自 09:32。
回测程序不会因为代码运行在历史数据上,就自动遵守时间约束。bfill 只按照数组顺序填值。它不知道策略在 09:31 是否已经完成下单。
线性插值也有相同问题。09:31 的插值结果通常依赖 09:30 和 09:32 两个端点。后一个端点属于未来信息。样条插值使用的邻域更大,未来数据范围可能更长。平滑程度提高,因果性消失。
因此,价格序列的 bfill 与 linear 不能作为无条件默认值。它们适合离线可视化、数据探索或明确不参与历史决策的展示数据。不适合作为标准回测输入。
前向填充的因果性
前向填充使用最近一次已经观测到的价格:
| 时间 | 原始收盘价 | 前向填充后 |
|---|---|---|
| 09:30 | 100 | 100 |
| 09:31 | 缺失 | 100 |
| 09:32 | 102 | 102 |
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 或统一均值填充后才表现良好,问题通常不在预测模型。问题在数据流水线。
参数可以优化。时间顺序不能。
相关阅读: 交易员决策疲劳应对策略:减少日内无效交易的系统化方案 、 全职交易员的社交孤立:享受孤独还是走向心理失衡?.
