4、动量因子构建:N日收益率、动量得分、动量衰减加权、动量因子标准化
动量因子,说白了就是看资产最近涨得猛不猛。很多人以为动量就是简单算个收益率,其实没那么简单。我做了这么多年量化,发现动量因子的构建,每一步都有坑。
今天咱们就把动量因子的四个核心步骤拆开揉碎讲清楚。
4.1 N日收益率:最朴素的动量
先看最简单的——N日收益率。公式不复杂:
R_N = (P_t / P_{t-N}) - 1
其中P_t是今天的收盘价,P_{t-N}是N天前的收盘价。
N怎么选?这是个经典问题。我个人习惯用20个交易日,差不多一个自然月。为什么?
- 太短(比如5天):噪声太大,容易被随机波动忽悠
- 太长(比如60天):反应太慢,趋势都快结束了才进场
- 20天:刚好能捕捉中期趋势,又不会太敏感
4.2 动量得分:把收益率变成分数
光有收益率还不够。你想想看,不同ETF的波动率不一样。一个涨了5%的科技ETF,和一个涨了5%的债券ETF,意义完全不同。
所以我们需要动量得分。我常用的方法是:
动量得分 = (R_N - R_mean) / R_std
R_mean是所有ETF的N日收益率均值,R_std是标准差。这其实就是Z-score标准化。
举个例子:
| ETF | 20日收益率 | 动量得分 |
|---|---|---|
| 沪深300ETF | 3.2% | 0.85 |
| 创业板ETF | 5.1% | 1.62 |
| 债券ETF | 0.8% | -0.43 |
你看,创业板ETF收益率最高,得分也最高。债券ETF虽然没亏钱,但跟其他ETF一比,就显得弱了。
4.3 动量衰减加权:让近期数据更重要
嗯,这里要注意。传统的N日收益率,给每一天的权重是一样的。但直觉告诉我们:昨天的涨跌,应该比20天前的涨跌更重要。
所以我用衰减加权。核心思想是:越近的数据,权重越大。
权重_i = exp(-λ * i)
其中i是距离今天的天数,λ是衰减系数。λ越大,衰减越快。
我一般设λ=0.1,这样20天前的权重只有今天的13%左右。代码实现很简单:
import numpy as np
def decay_weighted_return(prices, N=20, lam=0.1):
returns = np.diff(prices) / prices[:-1]
weights = np.exp(-lam * np.arange(N-1, -1, -1))
return np.sum(returns[-N:] * weights) / np.sum(weights)
为什么要衰减?我曾经回测过,不加衰减的动量策略,在震荡市里表现很差。加了衰减后,信号更灵敏,能更快捕捉到趋势变化。
4.4 动量因子标准化:让不同ETF可比
最后一步,标准化。不管前面怎么算,最终得到的动量值,需要映射到统一的尺度上。
我常用的标准化方法有两种:
- Z-score标准化:减去均值,除以标准差。结果在-3到3之间。
- Min-Max标准化:缩放到0到1之间。公式:(x - min) / (max - min)
我个人偏好Z-score。为什么?因为Min-Max对异常值太敏感。有一次我回测时,某个ETF突然涨停,导致所有其他ETF的动量值都被压缩到0.1以下,信号全乱了。
Z-score就好很多,异常值会被截断,不会影响整体分布。
知识体系图
下面这张图,把动量因子构建的完整流程画出来了。你可以看到数据是怎么一步步变成最终信号的。
好了,动量因子的四个步骤讲完了。记住:N日收益率是基础,动量得分让不同ETF可比,衰减加权让近期数据更重要,标准化让因子稳定可靠。每一步都有它的道理,别跳过。