4、因子衰减的实证检验:时间序列回归、Fama-MacBeth回归、面板数据模型、滚动窗口检验
因子衰减,说白了就是因子的预测能力随着时间推移逐渐消失。这玩意儿在量化圈里太常见了——你辛辛苦苦挖出来的因子,过个半年一年就不灵了。怎么科学地检验它?今天我把四种主流方法掰开揉碎讲清楚。
4.1 时间序列回归:最直观的衰减检验
我个人习惯先用时间序列回归做个快速诊断。思路很简单:把因子收益率对时间趋势做回归。
具体来说,我们构建这样一个模型:
FactorReturn_t = α + β × t + ε_t
这里的 t 是时间序号(1,2,3,...)。如果 β 显著为负,说明因子收益率在随时间下降——这就是衰减的信号。
我在项目中遇到过这样的情况:一个动量因子,前两年年化收益15%,第三年直接变成-3%。用时间序列回归一跑,β的t统计量是-2.8,p值0.006。嗯,衰减实锤了。
但要注意,这个方法有个坑——它假设衰减是线性的。你想想看,现实中的衰减哪有这么规整?
4.2 Fama-MacBeth回归:截面维度的衰减检验
时间序列回归看的是整体趋势,但Fama-MacBeth回归能帮我们从截面角度检验衰减。这个方法分两步走:
- 第一步: 每个时间点做一次截面回归,得到因子载荷的时序序列
- 第二步: 对因子载荷序列做时间趋势检验
说白了,就是看因子对收益率的解释力是不是在逐年下降。代码实现大概是这样的:
# 伪代码示例
for t in range(T):
# 截面回归
model = sm.OLS(returns_t, factors_t)
results = model.fit()
gamma[t] = results.params['factor']
# 对gamma序列做趋势检验
trend_model = sm.OLS(gamma, np.arange(T))
trend_results = trend_model.fit()
print(f"衰减系数: {trend_results.params[0]:.4f}")
print(f"t统计量: {trend_results.tvalues[0]:.2f}")
我记得有一次做规模因子的衰减检验,Fama-MacBeth跑出来gamma序列从0.12一路跌到0.03。趋势检验的t值是-3.5,衰减非常显著。但有意思的是,如果用滚动窗口看,衰减并不是匀速的——前三年基本没变,后两年突然加速。
4.3 面板数据模型:固定效应与随机效应
面板数据模型是我最常用的方法。它把时间序列和截面数据揉在一起,能控制个股的个体效应,检验更干净。
基本模型长这样:
R_it = α_i + β_t × Factor_it + γ × Time_Trend + ε_it
关键看 γ 的符号和显著性。如果 γ 显著为负,说明控制了个股差异后,因子收益依然在衰减。
我一般用Hausman检验来决定用固定效应还是随机效应。不过说实话,在因子衰减检验这个场景下,固定效应更稳妥——因为个股的异质性很可能和因子暴露相关。
| 模型类型 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 固定效应 | 个体效应与解释变量相关 | 估计一致,控制个体异质性 | 损失自由度,不估计不随时间变化的变量 |
| 随机效应 | 个体效应与解释变量不相关 | 更有效,可估计时不变变量 | 如果假设不成立,估计不一致 |
| 混合OLS | 无个体效应 | 简单直接 | 忽略个体差异,可能遗漏变量偏误 |
我曾经用面板数据模型检验一个技术因子,固定效应结果显示γ=-0.008(t=-2.1),衰减显著。但换成随机效应后,γ变成-0.005(t=-1.4),不显著了。这说明个股的固定效应确实和因子暴露相关——Hausman检验也证实了这一点(p=0.03)。
4.4 滚动窗口检验:动态捕捉衰减过程
前面几种方法都是假设衰减是单调的。但现实中的衰减往往是非线性的——可能先加速后减速,或者中间有反弹。滚动窗口检验就是为了捕捉这种动态变化。
做法很简单:固定一个窗口长度(比如36个月),每次滚动一个月,在每个窗口内跑一次回归,记录因子收益率的估计值。然后把这些估计值画成时间序列图。
# 滚动窗口检验示例
window = 36
rolling_gamma = []
for i in range(len(data) - window + 1):
window_data = data[i:i+window]
model = sm.OLS(window_data['returns'], window_data['factor'])
results = model.fit()
rolling_gamma.append(results.params[0])
# 画图
plt.plot(range(len(rolling_gamma)), rolling_gamma)
plt.axhline(y=0, color='r', linestyle='--')
plt.title('滚动窗口因子收益率(窗口=36个月)')
plt.show()
我见过最典型的案例是价值因子。2010-2015年,滚动窗口的因子收益率一直在0.05-0.08之间波动,看起来挺稳定。但从2016年开始,收益率一路下滑到0.01附近。有意思的是,2018年又反弹到0.04,然后继续下跌。这种"先跌后弹再跌"的模式,用前面那些全局方法根本看不出来。
4.5 四种方法的对比与选择
说了这么多,到底该用哪种?我整理了一个对比表:
| 方法 | 检验维度 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 时间序列回归 | 时间维度 | 简单直观,快速诊断 | 假设线性衰减,忽略截面差异 | 初步筛查,快速判断 |
| Fama-MacBeth | 截面+时间 | 控制截面风险,两步法稳健 | 对异常时间点敏感 | 学术研究,多因子模型检验 |
| 面板数据模型 | 面板维度 | 控制个体效应,估计更干净 | 模型选择(固定vs随机)有讲究 | 需要控制个股异质性的场景 |
| 滚动窗口检验 | 动态时间维度 | 捕捉非线性衰减,可视化直观 | 窗口选择主观,结果可能不稳定 | 观察衰减的动态变化过程 |
我的建议是:先用时间序列回归快速筛查,如果发现衰减迹象,再用面板数据模型做严谨检验。最后用滚动窗口看看衰减的动态模式——这样既有统计显著性,又有经济直觉。
嗯,以上就是因子衰减实证检验的四种方法。每种方法都有它的适用场景和局限性。关键是要理解它们的逻辑,然后根据你的数据特点和研究目的灵活选择。别指望一种方法解决所有问题——量化投资里没有银弹。