3、因子动量与反转:因子收益率的自相关性、因子动量策略、因子反转策略
好,咱们进入第三章。这一章聊的东西,我个人觉得特别有意思——因子动量和反转。
你想想看,很多人在做因子投资时,总以为因子收益是随机的、不可预测的。但实际跑过数据的人都知道,因子收益其实有很强的「惯性」或者「回摆」效应。说白了,就是因子自己也会涨多了跌、跌多了涨。
我在项目中遇到过好几次这样的情况:辛辛苦苦挖出一个因子,回测表现很好,结果实盘一跑,连续三个月负收益。后来一查,不是因子失效了,而是因子本身正处于「反转期」。嗯,这就是我们今天要解决的问题。
3.1 因子收益率的自相关性
先讲基础概念。因子收益率的自相关性,说白了就是「今天的因子收益和昨天的因子收益有没有关系」。
数学上,我们用自相关系数来衡量:
ρ(k) = Cov(r_t, r_{t-k}) / Var(r_t)
其中 r_t 是因子在第 t 期的收益率,k 是滞后阶数。
我个人习惯用 Ljung-Box Q 检验来判断自相关性是否显著。代码很简单:
import statsmodels.api as sm
from statsmodels.stats.diagnostic import acorr_ljungbox
# factor_returns 是因子日收益率序列
result = acorr_ljungbox(factor_returns, lags=[5, 10, 20], return_df=True)
print(result)
如果 p 值小于 0.05,说明存在显著的自相关。这时候,因子动量或反转策略就有了用武之地。
关键点:自相关性为正,说明因子有动量效应;自相关性为负,说明因子有反转效应。但要注意,不同时间尺度下,结果可能完全不同。
我曾经犯过一个错误:用日度数据算自相关,发现是负的,就以为因子适合做反转。结果换到周度数据一看,自相关变成正的了。所以,多尺度验证是必须的。
3.2 因子动量策略
因子动量策略,就是「追涨杀跌」——买入近期表现好的因子,卖出近期表现差的因子。
具体做法分三步:
- 计算因子近期收益率:通常用过去 12 个月(扣除最近 1 个月)的累计收益。
- 排序分组:把所有因子按近期收益率从高到低排序,分成 5 组或 10 组。
- 做多最强组,做空最弱组:构建多空组合,持有 1 个月后调仓。
代码实现如下:
def factor_momentum_strategy(factor_returns_df, lookback=12, hold=1):
"""
factor_returns_df: DataFrame, 行为时间, 列为因子
lookback: 回溯期(月)
hold: 持有期(月)
"""
# 计算过去 lookback 个月的累计收益
momentum_score = factor_returns_df.rolling(lookback).sum()
# 每月末排序
ranks = momentum_score.rank(axis=1, ascending=True)
# 做多 top 20%, 做空 bottom 20%
long = ranks >= ranks.quantile(0.8, axis=1)
short = ranks <= ranks.quantile(0.2, axis=1)
# 计算多空收益
long_ret = (factor_returns_df.shift(-hold) * long).mean(axis=1)
short_ret = (factor_returns_df.shift(-hold) * short).mean(axis=1)
return long_ret - short_ret
避坑指南:我曾经用全样本回测因子动量,效果特别好。但后来发现,这是因为样本内包含了因子「强者恒强」的时期。换成滚动回测后,收益直接腰斩。所以,一定要做滚动验证。
因子动量策略的底层逻辑是什么?其实和股票动量一样——信息传导需要时间。一个因子之所以能持续跑赢,可能是因为市场对因子所捕捉的异象认知不足,或者资金流入有惯性。
3.3 因子反转策略
因子反转策略,就是「低买高卖」——买入近期表现差的因子,卖出近期表现好的因子。
为什么因子会反转?我总结了几点:
- 拥挤交易:太多人用同一个因子,导致因子溢价被抹平。
- 资金流冲击:大资金进出造成短期价格偏离。
- 风险补偿变化:因子承载的风险溢价随时间波动。
反转策略的实现和动量策略几乎一样,只是方向相反:
def factor_reversal_strategy(factor_returns_df, lookback=1, hold=1):
"""
短期反转策略,lookback 通常设为 1 天或 5 天
"""
# 计算过去 lookback 期的累计收益
reversal_score = factor_returns_df.rolling(lookback).sum()
# 排序
ranks = reversal_score.rank(axis=1, ascending=True)
# 做多最弱组,做空最强组
long = ranks <= ranks.quantile(0.2, axis=1)
short = ranks >= ranks.quantile(0.8, axis=1)
long_ret = (factor_returns_df.shift(-hold) * long).mean(axis=1)
short_ret = (factor_returns_df.shift(-hold) * short).mean(axis=1)
return long_ret - short_ret
注意:因子反转策略的交易频率通常很高,手续费和滑点会吃掉大部分收益。我建议在回测时至少扣除 0.1% 的单边交易成本,否则结果会过于乐观。
我个人经验是,因子反转策略在以下场景效果更好:
- 市场波动率较高时
- 因子拥挤度处于历史高位时
- 宏观经济数据发布前后
3.4 知识体系结构图
下面这张图,把因子动量与反转的核心逻辑串起来了:
3.5 实战中的注意事项
最后,分享几个我在实战中踩过的坑:
| 问题 | 表现 | 解决方案 |
|---|---|---|
| 参数过拟合 | 回测完美,实盘拉胯 | 使用滚动窗口验证,避免全样本优化 |
| 交易成本忽略 | 策略收益虚高 | 至少扣除 0.1% 单边成本,高频策略扣更多 |
| 因子选择偏差 | 只选表现好的因子做回测 | 使用全因子池,避免幸存者偏差 |
| 忽视市场状态 | 动量在震荡市失效 | 结合市场波动率或趋势状态做条件策略 |
我的建议:刚开始做因子动量/反转策略时,别追求复杂模型。先用简单的滚动窗口排序法跑一年数据,看看因子收益的自相关结构是否稳定。稳定了,再上机器学习。不稳定,再好的模型也白搭。
嗯,这一章就到这里。因子动量和反转,说白了就是「顺势」和「逆势」的博弈。没有绝对的好坏,关键看你用在什么市场环境下。
公众号:蓝海资料掘金营,微信deep3321