4. 策略收益序列处理
在量化策略相关性与分散化配置中,很多结论并不是被模型“算错”的,而是被输入数据“带偏”的。两条策略收益序列如果时间戳不一致、频率不同、缺失值处理方式不同,或者极端值未加处理,相关系数、协方差矩阵和权重优化结果都会发生显著漂移。因此,收益序列处理不是预处理附属步骤,而是配置结论可靠性的第一道防线。
一、核心原理:相关性建立在“可比收益”之上
相关性衡量的是两个变量在同一样本空间中的共同变动程度。对于策略收益序列,这意味着三件事必须同时成立:第一,两个序列的收益定义一致,例如都使用对数收益或都使用简单收益;第二,时间区间一致,不能一个用日频、一个用周频直接计算;第三,缺失与异常的处理规则一致,否则相当于人为制造了不同步的波动结构。
从数据链路看,处理流程可以概括为:原始净值或价格 → 收益计算 → 时间对齐 → 频率统一 → 缺失与异常处理 → 平稳性检验 → 进入相关性或优化模型。任何一步跳过,都会把误差传递到配置权重中。
二、方法流程:从原始序列到可比收益矩阵
第一步是收益计算。若使用净值序列,建议优先采用对数收益,因为它在时间上可加,便于频率转换。第二步是时间对齐,核心是统一交易日历。A股、港股、、期货和加密资产的交易日不同,直接按自然日合并会产生大量伪缺失。第三步是频率转换,常见做法是将日频收益按区间复利汇总为周频或月频。
import pandas as pd
import numpy as np
# 假设 df 为多策略日频净值,索引为交易日
returns = np.log(df / df.shift(1)).dropna(how='all')
# 统一到共同交易日历
common_index = returns.dropna(how='any').index
returns_aligned = returns.loc[common_index]
# 日频转周频:按周末复利汇总
weekly = returns_aligned.resample('W-FRI').sum()
# 缺失值:仅对短缺口线性插值,长缺口保留并标记
returns_filled = returns_aligned.interpolate(method='linear', limit=3)
missing_flag = returns_aligned.isna() & returns_filled.notna()
第四步是异常值处理。收益序列中的极端值可能来自真实行情,也可能来自数据错误。建议先识别再处理:用滚动中位数和MAD构造稳健Z分数,超过阈值的点先核查,确认错误后再截尾或Winsorize,而不是直接删除。第五步是平稳性检验。多数策略收益序列本身近似平稳,但若使用累计收益或价差序列,则需先差分或转为收益。
三、案例场景:两条策略为何“看起来不相关”
假设策略A为A股日频多头,策略B为周频多空。若直接按自然日外连接,B在A股交易日大量缺失,填充后波动被平滑,计算出的相关系数会明显偏低。正确做法是:先将B的周频收益按周内交易日映射,或统一降频到周频;再在共同周频区间计算相关。另一个常见场景是某策略在停牌期净值不变,收益为0,若未剔除停牌区间,会人为降低波动并扭曲相关性。
| 处理环节 | 常见做法 | 风险 | 建议 |
|---|---|---|---|
| 收益计算 | 简单收益或对数收益 | 混用导致频率转换偏差 | 全流程统一收益定义 |
| 时间对齐 | 自然日外连接 | 伪缺失、伪同步 | 使用共同交易日历 |
| 频率转换 | 直接重采样求和 | 忽略复利与区间边界 | 对数收益求和或净值重算 |
| 缺失值 | 前向填充或均值填充 | 制造虚假低波动 | 短缺口插值,长缺口标记 |
| 异常值 | 直接删除 | 丢失真实极端行情 | 先核查,再截尾或Winsor |
| 平稳性 | 默认收益平稳 | 价差序列伪回归 | ADF/KPSS配合观察 |
四、误区与复盘:不要用“干净”掩盖“失真”
最常见的误区是“把缺失填满就等于处理好了”。前向填充会让收益序列出现长串0,波动率被低估,相关性被高估或低估,取决于另一条序列的同期表现。另一个误区是“异常值一律删除”。真实极端行情往往是策略尾部风险的核心来源,删除后回测更漂亮,但配置结论更脆弱。
复盘时建议保留三套数据版本:原始对齐版、清洗后主版本、异常值标记版。任何相关性结论都应能在三套版本上复现方向。如果方向频繁反转,说明结论对预处理过于敏感,不应直接用于权重优化。
最后,平稳性检验不是形式主义。对收益序列,ADF拒绝单位根通常是好消息;对价差或累计收益,若未通过检验,应转为差分序列或使用协整方法。只有完成清洗、对齐、频率转换、异常值处理和平稳性检验,收益矩阵才具备进入相关性与分散化配置模型的基本资格。