4. 因子计算与实现:以动量因子为例,演示因子值的计算过程
聊到因子计算,很多人第一反应就是「拿公式一套,出结果」。嗯,理论上是这样。但我在实际项目中踩过不少坑,发现细节才是魔鬼。今天我们就拿动量因子开刀,一步步把计算过程掰开揉碎了讲。
4.1 动量因子的核心逻辑
动量因子,说白了就是「过去涨得好的,未来可能继续涨」。这个逻辑听着简单,但实现起来有讲究。
我个人习惯把动量因子分成两类:
- 时间序列动量:看个股自身过去一段时间的收益率
- 截面动量:看个股在所有股票中的相对排名
回测中常用的是截面动量,因为它能消除市场整体趋势的影响。你想想看,如果大盘涨了20%,个股涨了15%,这算动量强还是弱?截面动量会告诉你——弱,因为跑输了大盘。
4.2 计算步骤拆解
我们以最常见的12个月动量因子为例,也就是用过去12个月的收益率(剔除最近1个月)来构建因子。为什么要剔除最近1个月?因为短期反转效应会干扰动量信号。我在项目中遇到过,如果不做这个处理,因子表现会大打折扣。
步骤一:数据准备
你需要以下数据:
- 个股的日度或月度收盘价(复权后)
- 时间范围:至少13个月的历史数据
- 股票池:全A股或特定指数成分股
步骤二:计算月度收益率
先把日度数据转换成月度数据。我一般用月末收盘价来计算:
# 伪代码示例
monthly_return = (close_price_t / close_price_t-1) - 1
这里有个细节:如果某个月份停牌怎么办?我的做法是跳过该月,用上一个有效月份的数据。但要注意,连续停牌超过3个月的股票,建议直接剔除。
步骤三:计算累积收益率
动量因子需要的是过去12个月的累积收益率(剔除最近1个月):
# 计算过去12个月累积收益率(剔除最近1个月)
momentum_factor = (1 + monthly_return_t-2) *
(1 + monthly_return_t-3) *
... *
(1 + monthly_return_t-13) - 1
为什么是t-2到t-13?因为我们要跳过t-1(最近一个月)。这个窗口期设置,是我在多次回测中试出来的最优解。
步骤四:截面标准化
得到原始动量值后,还需要做截面标准化。常用的方法有两种:
| 方法 | 公式 | 适用场景 |
|---|---|---|
| Z-score | (x - mean) / std | 因子值呈正态分布时 |
| 排名百分位 | rank(x) / N | 因子值有极端值时 |
我个人更推荐排名百分位法。为什么?因为动量因子经常会出现极端值——比如某只股票因为重组连续涨停,动量值会高得离谱。用Z-score会被这些极端值带偏,而排名法就稳健得多。
4.3 完整代码实现
下面是一个完整的Python实现,我用的是pandas和numpy:
import pandas as pd
import numpy as np
def calculate_momentum_factor(price_df, lookback=12, skip=1):
"""
计算截面动量因子
参数:
price_df: DataFrame, 索引为日期, 列为股票代码, 值为复权收盘价
lookback: int, 回溯期数(月)
skip: int, 跳过的最近期数(月)
返回:
DataFrame, 动量因子值(已标准化)
"""
# 计算月度收益率
monthly_ret = price_df.pct_change()
# 计算累积收益率(跳过最近skip个月)
momentum = (1 + monthly_ret.shift(skip)).rolling(window=lookback).apply(
lambda x: np.prod(x) - 1, raw=True
)
# 截面排名标准化
momentum_rank = momentum.rank(axis=1, pct=True)
# 处理缺失值
momentum_rank = momentum_rank.replace([np.inf, -np.inf], np.nan)
return momentum_rank
# 使用示例
# price_data = pd.read_csv('monthly_prices.csv', index_col=0, parse_dates=True)
# momentum_factor = calculate_momentum_factor(price_data)
np.prod 函数计算累积乘积,比循环快10倍以上。处理全A股4000多只股票时,这个优化能省下不少时间。
4.4 常见坑点与避坑指南
这部分是我最想分享的。纸上谈兵谁都会,但实战中遇到的问题才真正考验功力。
- 幸存者偏差:回测时只用了当前存活的股票,忽略了退市的股票。结果就是因子表现被高估。我曾经因为这个原因,把一个策略的夏普比率从1.5吹到了2.0,实盘直接打脸。
- 前视偏差:计算因子时不小心用了未来的数据。比如用t月的收盘价计算t月的因子,这就是典型的前视偏差。记住,因子值必须在t月结束后才能计算。
- 极端值处理:动量因子天然存在尖峰厚尾特征。我建议在标准化之前先做MAD(中位数绝对偏差)去极值,效果比3-sigma好。
核心要点:因子计算不是简单的数学公式套用。数据清洗、窗口期选择、标准化方法,每一个环节都影响最终结果。我的经验是——先跑通,再优化,最后才谈得上「精确」。
4.5 知识体系总览
下面这张图总结了动量因子计算的完整流程,你可以把它当作一个检查清单:
这张图把整个流程串起来了。你从数据准备开始,一步步走到最终因子值。每个环节都有对应的处理方法和注意事项。我个人建议把这张图打印出来贴在工位上,写代码的时候对照着看,能少走很多弯路。
最后说一句:因子计算没有银弹。同样的动量因子,在不同市场、不同时间窗口下表现可能天差地别。我的做法是——先理解逻辑,再动手实现,最后用数据验证。每一步都走扎实了,结果自然不会差。
公众号:蓝海资料掘金营,微信deep3321