第1章:因子收益率计算——从暴露度到残差的完整拆解

大家好,我是老张。今天咱们聊聊多因子归因里最基础、也最容易被忽视的一环——因子收益率的计算。

说实话,我见过不少团队,模型跑得飞起,但一问到因子收益率怎么算的,支支吾吾说不清楚。嗯,这其实是个大坑。你想想看,归因分析要是地基没打牢,后面所有结论都可能跑偏。

1.1 因子暴露度:你的股票在因子上的“敏感系数”

先讲因子暴露度。说白了,就是某只股票在某个因子上的“得分”。比如市值因子,小盘股暴露度高,大盘股暴露度低。

我个人习惯用标准化后的Z-score来表示暴露度。为什么?因为不同因子的量纲不一样,市盈率是几十倍,换手率是百分之几,不标准化没法直接比较。

举个例子,假设我们有5只股票,计算它们在“动量因子”上的暴露度:

import pandas as pd
import numpy as np

# 原始数据:过去20日收益率
returns_20d = [0.05, -0.02, 0.12, -0.08, 0.03]
stock_names = ['A', 'B', 'C', 'D', 'E']

# 标准化为Z-score
mean_ret = np.mean(returns_20d)
std_ret = np.std(returns_20d)
exposure = [(r - mean_ret) / std_ret for r in returns_20d]

# 结果展示
for name, exp in zip(stock_names, exposure):
    print(f"{name}: {exp:.3f}")

输出结果:

A: 0.218
B: -0.654
C: 1.309
D: -1.309
E: 0.436

你看,股票C的动量暴露度最高(1.309),说明它最近涨得最猛。股票D最低(-1.309),跌得最惨。

我的经验: 标准化时记得用滚动窗口,别用全样本。我在项目中遇到过用全样本标准化,结果回测时引入了未来信息,导致策略看起来无敌,实盘一塌糊涂。

1.2 因子收益率:横截面回归的核心输出

因子收益率怎么算?最经典的方法是Fama-MacBeth两步法中的第一步——横截面回归。

具体来说,在每个时间点t,我们用所有股票的收益率对因子暴露度做回归:

R_i = α + β_1 * X_i1 + β_2 * X_i2 + ... + ε_i

其中,β就是因子收益率,代表该因子在当期带来的超额收益。

我建议用加权最小二乘法(WLS),权重用市值的平方根。为什么?因为小市值股票波动大,容易带偏回归结果。这是我踩过坑之后才学乖的。

import statsmodels.api as sm

# 假设我们有100只股票,3个因子
# returns: 100x1 的收益率向量
# exposures: 100x3 的暴露度矩阵(已标准化)
# weights: 100x1 的权重向量(市值平方根)

# 添加截距项
X = sm.add_constant(exposures)

# 加权最小二乘回归
model = sm.WLS(returns, X, weights=weights)
results = model.fit()

# 因子收益率就是回归系数
factor_returns = results.params[1:]  # 去掉截距项
print("因子收益率:", factor_returns)
关键点: 因子收益率不是预测值,而是“事后”解释值。它告诉我们:在已经发生的这个时间点,每个因子平均带来了多少收益。

1.3 残差收益率:被因子“遗漏”的部分

残差收益率,就是实际收益率减去因子能解释的部分。公式很简单:

ε_i = R_i - (α + β_1 * X_i1 + β_2 * X_i2 + ...)

这个残差很重要。它代表了个股的特质收益——那些因子抓不住的东西。

我曾经遇到过一个案例:某只股票因子暴露度很低,但收益率很高。一开始以为是数据错了,后来发现是公司发布了超预期的业绩预告。这就是典型的残差收益——因子模型解释不了的部分。

# 计算残差收益率
predicted_returns = results.predict(X)
residuals = returns - predicted_returns

# 查看残差最大的几只股票
top_residual = pd.DataFrame({
    'stock': stock_names,
    'actual_return': returns,
    'predicted_return': predicted_returns,
    'residual': residuals
}).sort_values('residual', ascending=False)

print(top_residual.head())
注意: 残差收益率不是噪声!它可能隐藏着alpha信号。很多量化团队专门做“残差策略”——买入残差为正的股票,卖出残差为负的股票。但要注意,残差也可能只是运气。

1.4 三者关系:一张图说清楚

下面我用一张SVG图来展示因子暴露度、因子收益率和残差收益率之间的关系:

因子归因核心逻辑图 因子暴露度 (标准化Z-score) 因子收益率 (回归系数β) 残差收益率 (特质收益ε) 输入 解释 实际收益率 因子解释部分 特质部分 R_i = α + Σ(β_k × X_ik) + ε_i 实际收益 = 截距 + 因子解释部分 + 残差 因子暴露度 × 因子收益率 = 因子贡献收益

1.5 实战中的避坑指南

最后,分享几个我踩过的坑:

  • 多重共线性: 因子之间相关性太高,回归系数会不稳定。我一般用VIF(方差膨胀因子)检测,超过5就剔除或合并因子。
  • 异常值处理: 极端暴露度会严重扭曲回归结果。我习惯用MAD(中位数绝对偏差)方法做缩尾处理,比3σ更稳健。
  • 时间序列自相关: 因子收益率在时间上可能有自相关。我建议用Newey-West标准误调整t统计量,否则显著性检验会偏大。
一个小技巧: 计算完因子收益率后,我习惯画一张热力图,看看因子收益率之间的相关性。如果两个因子收益率长期高度相关(比如超过0.7),那它们很可能在解释同一件事,考虑合并。

好了,因子收益率计算的核心内容就这些。记住:暴露度是输入,因子收益率是过程输出,残差是最终检验。三者缺一不可。


专注资料整理