一、多因子模型概述:从CAPM到多因子,因子投资的前世今生
1.1 一切的起点:CAPM 与它的“不完美”
说起多因子模型,咱们得先聊聊它的老前辈——CAPM(资本资产定价模型)。
CAPM 的逻辑其实很简洁:一只股票的预期收益,只跟它对市场波动的敏感度(Beta)有关。说白了,你承担了市场风险,就应该获得市场回报。这个理论在 60 年代提出来的时候,简直是金融界的一股清流。
但我个人在实际项目中很快发现一个问题:CAPM 的解释力太弱了。
举个例子,我曾在某券商做量化策略回测,用 CAPM 去解释 A 股个股的收益率截面差异,R² 经常只有 5%~10%。这意味着什么?市场风险只能解释一小部分收益,剩下 90% 都是“残差”。你想想看,这模型基本等于白搭。
学术界也注意到了这个尴尬。70 年代末,Basu 发现低市盈率股票长期跑赢高市盈率股票;Banz 发现小市值公司比大市值公司收益更高。这些现象,CAPM 一个都解释不了。
1.2 Fama-French 三因子模型:里程碑式的突破
1993 年,Fama 和 French 干了一件大事。他们把 CAPM 的“单因子”扩展成了“三因子”:
- 市场因子(MKT):就是 CAPM 里的 Beta
- 规模因子(SMB):小市值 vs 大市值
- 价值因子(HML):高账面市值比 vs 低账面市值比
这个模型一出来,解释力直接从 10% 跳到了 30%~40%。我记得第一次在 A 股数据上跑三因子回归时,看到 R² 从个位数涨到 30% 多,心里那个爽啊——终于有个能用的模型了。
但这里有个坑,我曾经踩过:三因子模型在美国市场表现很好,但在 A 股市场,规模因子的效果极其不稳定。2017 年之前小盘股确实跑赢大盘股,但 2017 年之后风格切换,大盘蓝筹反而更强。如果你机械地照搬 Fama-French 的因子构造方法,很容易翻车。
1.3 从三因子到多因子:因子投资的“军备竞赛”
三因子模型成功后,学术界和业界就像打开了潘多拉魔盒。大家发现:原来可以找的因子这么多!
2015 年,Fama 和 French 自己又加了两个因子,变成五因子模型:
- 盈利因子(RMW):高盈利公司 vs 低盈利公司
- 投资因子(CMA):保守投资公司 vs 激进投资公司
与此同时,动量因子、低波因子、质量因子、分红因子……各种因子如雨后春笋般冒出来。我粗略统计过,学术论文里正式提出过的因子,少说也有 300 多个。
为什么会这样?说白了,因子投资本质上是在寻找“系统性错误定价”。市场不是完全有效的,总有一些规律可以被利用。你找到一个有效的因子,就等于找到了一台印钞机。
但这里有个大问题:因子太多,真伪难辨。很多因子只是数据挖掘的产物,换个时间段就失效了。我曾经测试过一个“天气因子”——晴天多的月份股票收益更高,结果回测 10 年效果很好,但 2018 年之后完全失效。嗯,这就是典型的过拟合。
1.4 因子投资的核心逻辑:一张图看懂
说了这么多,咱们用一张图来梳理一下因子投资的完整逻辑链条:
这张图展示了因子投资的完整闭环:从发现错误定价,到提取因子,再到构建模型,最后落地应用。而且别忘了——这是一个迭代过程。模型跑一段时间,因子可能失效,你得重新回到起点去寻找新的因子。
1.5 多因子模型的核心价值:风险收益平衡术
说了这么多,多因子模型到底好在哪?我个人认为,它的核心价值在于风险收益的精细化管理。
单因子模型(比如 CAPM)只能告诉你“市场风险有多大”,但多因子模型可以告诉你:
- 你的组合暴露了多少规模风险?
- 价值因子贡献了多少收益?
- 动量因子是不是在拖后腿?
我举个例子。之前有个客户,他的组合收益一直不错,但波动特别大。我用多因子模型一拆解,发现他无意中暴露了很高的动量因子敞口——市场涨的时候猛涨,市场跌的时候猛跌。后来我建议他加入低波因子做对冲,波动率直接降了 30%。
这就是多因子模型的魅力:你不仅能知道赚了多少,还能知道为什么赚、风险在哪。
1.6 一个简单的因子测试代码
最后,给大家看一段我常用的因子测试代码。虽然简单,但很实用:
import pandas as pd
import numpy as np
import statsmodels.api as sm
def factor_regression(returns, factors):
"""
多因子回归:评估因子对收益的解释力
returns: 个股收益率序列
factors: 因子收益率矩阵(每列一个因子)
"""
# 添加截距项
X = sm.add_constant(factors)
model = sm.OLS(returns, X).fit()
# 输出结果
print(f"R²: {model.rsquared:.3f}")
print(f"调整R²: {model.rsquared_adj:.3f}")
print("\n因子系数:")
for name, coef, pval in zip(
['Alpha'] + list(factors.columns),
model.params,
model.pvalues
):
sig = '***' if pval < 0.01 else '**' if pval < 0.05 else '*' if pval < 0.1 else ''
print(f"{name:10s}: {coef:+.4f} (p={pval:.4f}) {sig}")
return model
# 使用示例
# factor_regression(stock_returns, factor_df)
这段代码虽然只有 20 多行,但我在实际项目中用它做过上百次因子测试。记住一个原则:先跑回归,再看显著性,最后才决定要不要用这个因子。千万别跳过这一步,否则很容易被“伪因子”坑了。
好了,第一章的内容就到这里。因子投资的世界很大,咱们后面慢慢聊。