Fama-French 三因子 / 五因子模型
直觉
模块 1.6 的 CAPM 只用一个市场因子解释收益。但实证发现,小盘股、价值股等也有系统性溢价,单靠市场解释不充分。Fama-French 用多个因子做回归,能解释掉更多收益波动,剩下的 才是「真正无法解释的超额」。
因子模型
资产超额收益对多个因子回归:
- MKT:市场超额收益(CAPM 的那个);
- SMB:Small Minus Big,小盘相对大盘的溢价;
- HML:High Minus Low,高账面市值比(价值)相对成长的溢价;
- 五因子再补 RMW(盈利)、CMA(投资)。
「人话」解释:为什么要多因子?
如果一只股票的收益其实来自「它是小盘股」(SMB 暴露),用单因子 CAPM 回归,这部分会被算进 ,让你误以为「找到了超额能力」。 加入 SMB 后,这部分被「解释掉」, 缩小、 上升——这才是更诚实的归因。 所以因子越全,剩下的 越「干净」(也通常越小)。
可运行案例:单因子 vs 三因子 vs 五因子
构造一个只对 MKT/SMB/HML 有暴露的资产,分别用 1/3/5 因子回归,对比 与 ——单因子会因遗漏 SMB/HML 而虚高 。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
ff = pd.read_csv('/data/ff_factors_monthly.csv', parse_dates=['date']).set_index('date')
MKT, SMB, HML, RMW, CMA = (ff[c].values for c in ['MKT','SMB','HML','RMW','CMA'])
rng = np.random.default_rng(7)
# 真实敞口: MKT=1.2, SMB=0.5, HML=0.3; 月 alpha=0.2%; 无 RMW/CMA 暴露
asset = 0.002 + 1.2*MKT + 0.5*SMB + 0.3*HML + rng.normal(0, 0.02, len(ff))
def ols(y, X):
X1 = np.column_stack([np.ones(len(y)), X])
b, *_ = np.linalg.lstsq(X1, y, rcond=None)
resid = y - X1 @ b
r2 = 1 - resid.var(ddof=0) / y.var(ddof=0)
return b, r2
b1, r2_1 = ols(asset, MKT)
b3, r2_3 = ols(asset, np.column_stack([MKT, SMB, HML]))
b5, r2_5 = ols(asset, np.column_stack([MKT, SMB, HML, RMW, CMA]))
print("真值: alpha(月)=0.002 β(MKT,SMB,HML)=(1.2,0.5,0.3)")
print(f"\n单因子(MKT) alpha={b1[0]*12:+.3%}/年 β_MKT={b1[1]:.2f} R²={r2_1:.3f}")
print(f"三因子(3F) alpha={b3[0]*12:+.3%}/年 β=({b3[1]:.2f},{b3[2]:.2f},{b3[3]:.2f}) R²={r2_3:.3f}")
print(f"五因子(5F) alpha={b5[0]*12:+.3%}/年 β_MKT={b5[1]:.2f} R²={r2_5:.3f}")
print("\n→ 单因子遗漏 SMB/HML, alpha 虚高; 三因子还原真值、alpha≈0、R² 最高。")
models = ['单因子', '三因子', '五因子']
plt.figure(figsize=(7, 3.4))
plt.subplot(1, 2, 1); plt.bar(models, [r2_1, r2_3, r2_5], color='#2563eb'); plt.title('R² (越高越好)')
plt.subplot(1, 2, 2); plt.bar(models, [b1[0]*12, b3[0]*12, b5[0]*12], color='crimson'); plt.title('alpha/年 (越接近0越好)')
plt.tight_layout(); plt.show()
小结
- Fama-French 用 MKT/SMB/HML(三因子)或加 RMW/CMA(五因子)解释收益;
- 因子越全,被「解释掉」的收益越多,剩余 越干净;
- 单因子回归常高估 ——多因子是更诚实的绩效归因。