第一章:因子构建与标准化
各位同学好,我是老张。今天咱们聊聊因子构建与标准化。说实话,这是整个宏观因子交易系统里最基础、也最容易踩坑的环节。我见过太多人因子算对了,但标准化没做好,结果回测曲线漂亮得不行,实盘一跑就崩。嗯,咱们今天就把这块彻底讲透。
1.1 因子计算逻辑
先说说因子是什么。说白了,因子就是能解释资产收益的某种特征。比如GDP增速、CPI变化、利率曲线斜率,这些都是宏观因子。但光有原始数据不行,你得把它变成可交易的信号。
我个人习惯把因子计算分成三步:
- 数据清洗:去掉缺失值、处理重复数据
- 差分/对数处理:让数据平稳
- 方向判断:确定因子是正向还是反向影响
举个例子,假设我们要构建一个“通胀动量因子”:
# 伪代码示例
def calculate_inflation_momentum(cpi_series, lookback=12):
# 计算12个月滚动变化
momentum = cpi_series.pct_change(periods=lookback)
# 去趋势处理
momentum = momentum - momentum.rolling(60).mean()
return momentum
这里有个坑:滚动窗口的选择。我记得刚开始做的时候,直接用全样本均值去中心化,结果回测时因子值一直在漂移。后来才明白,必须用滚动窗口,不然就是未来函数。
1.2 Z-score标准化
因子算出来了,但不同因子的量纲不一样。比如GDP增速可能是2.5%,而利率变化可能是0.1%。直接比较没意义,必须标准化。
Z-score是最常用的方法:
Z = (X - μ) / σ
其中μ是均值,σ是标准差
但这里有个细节:用哪个窗口的均值和标准差?
我建议用滚动窗口。比如用过去252个交易日(约1年)的均值和标准差。为什么?因为市场环境在变,5年前的均值对今天没意义。
def zscore_rolling(series, window=252):
rolling_mean = series.rolling(window).mean()
rolling_std = series.rolling(window).std()
zscore = (series - rolling_mean) / rolling_std
return zscore
小技巧:如果数据量不够,可以先用expanding窗口初始化,再切换到rolling。我一般前60个交易日用expanding,之后用rolling。
1.3 滚动窗口处理
滚动窗口是标准化里的核心。你想想看,如果不用滚动窗口,直接用全样本均值,那每个时间点的因子值都包含了未来的信息。这在回测里是致命的。
常见的窗口选择:
| 窗口长度 | 适用场景 | 我的经验 |
|---|---|---|
| 20天(1个月) | 高频因子、短期动量 | 噪声太大,慎用 |
| 60天(3个月) | 中期反转因子 | 比较均衡,我常用 |
| 252天(1年) | 宏观因子、趋势跟踪 | 稳定,但反应慢 |
| 504天(2年) | 长期均值回归 | 适合债券因子 |
我曾经犯过一个错误:用20天窗口做利率因子的标准化。结果因子值上蹿下跳,交易信号频繁反转,手续费都亏光了。后来改成60天窗口,信号稳定多了。
1.4 异常值处理
异常值是个大问题。宏观数据经常有突发事件,比如2008年雷曼倒闭、2020年疫情。这些极端值会把Z-score拉偏,导致大部分时间因子值都在0附近,失去区分度。
我常用的方法有三种:
- MAD法(中位数绝对偏差):比标准差更稳健
- 分位数截断:比如把超过99%分位数的值截断
- Winsorize:把极端值替换为边界值
注意:不要直接删除异常值!删除会导致数据不连续,影响滚动窗口计算。我一般用Winsorize,把上下1%的极端值替换为边界值。
def winsorize_series(series, limits=[0.01, 0.99]):
lower = series.quantile(limits[0])
upper = series.quantile(limits[1])
return series.clip(lower, upper)
这里有个实战经验:异常值处理要在标准化之前做。先截断极端值,再算Z-score,这样标准化后的因子值不会因为几个极端点而失真。
知识体系总览
下面这张图是我自己画的,把因子构建与标准化的核心逻辑串起来了:
这张图把整个流程串起来了。从原始数据开始,经过因子计算、异常值处理、滚动窗口标准化,最后输出标准化的因子信号。每一步都有坑,每一步都要小心。
核心要点总结:
- 因子计算要避免未来函数,滚动窗口是关键
- Z-score标准化必须用滚动窗口,不能用全样本
- 异常值处理要在标准化之前做,推荐Winsorize
- 窗口长度选择要结合因子特性,没有万能参数
好了,这一章就到这里。因子构建和标准化是基本功,看似简单,但细节决定成败。我见过太多人在这上面栽跟头,希望你们能少走弯路。