2. 因子模型构建:单因子模型、多因子模型、因子暴露与因子收益率的计算
因子模型是量化组合风险归因与收益分解的核心工具。它将资产的收益率分解为系统性因子贡献与特质性残差两部分,从而将高维的资产协方差矩阵降维到低维的因子协方差矩阵,极大简化了风险建模与组合优化的复杂度。
2.1 单因子模型:CAPM 与市场模型
单因子模型假设资产收益率仅受一个共同因子驱动,最经典的实现是资本资产定价模型(CAPM)与市场模型(Market Model)。
| 模型 | 公式 | 核心假设 | 因子含义 |
|---|---|---|---|
| CAPM | \(R_i - R_f = \beta_i (R_m - R_f) + \epsilon_i\) | 市场组合有效、投资者同质预期 | 市场超额收益 |
| 市场模型 | \(R_i = \alpha_i + \beta_i R_m + \epsilon_i\) | 仅需线性回归假设 | 市场收益率(含截距) |
实践要点: 市场模型不要求 \(R_f\) 已知,直接对原始收益率做 OLS 回归,更便于工程实现。但 CAPM 在理论上要求 \(\alpha_i = 0\),若回归发现显著非零的 \(\alpha\),则意味着存在定价异象或模型设定偏误。
2.2 多因子模型:从 Fama-French 到 Barra 体系
单因子模型无法解释大量横截面收益差异,多因子模型应运而生。常见体系包括:
- Fama-French 三因子模型: 市场因子 (MKT)、规模因子 (SMB)、价值因子 (HML)。
- Carhart 四因子模型: 在三因子基础上加入动量因子 (MOM)。
- Barra 风险模型: 包含国家因子、行业因子、风格因子(如市值、波动率、成长、杠杆等),通常使用 10~50 个因子。
- 统计因子模型: 通过 PCA、ICA 等无监督方法从收益率协方差矩阵中提取主成分作为因子。
工程选择建议: 在组合风险归因场景中,Barra 风格因子模型因其因子经济含义明确、行业暴露可解释性强,成为业界主流。统计因子模型虽拟合优度高,但因子缺乏经济含义,不利于向投资者解释风险来源。
2.3 因子暴露的计算
因子暴露(Factor Exposure / Factor Loading)衡量资产对每个因子的敏感度。根据因子类型不同,计算方法分为两类:
2.3.1 基于回归的暴露估计
对于经济因子模型,通常使用时间序列回归估计因子暴露:
# Python: 使用滚动窗口 OLS 估计因子暴露
import pandas as pd
import statsmodels.api as sm
def estimate_factor_exposure(returns, factor_returns, window=252):
"""
returns: 个股日收益率 Series
factor_returns: 因子收益率 DataFrame (每列一个因子)
window: 滚动窗口长度
"""
exposures = []
for i in range(window, len(returns)):
y = returns.iloc[i-window:i]
X = factor_returns.iloc[i-window:i]
X = sm.add_constant(X) # 加入截距项 alpha
model = sm.OLS(y, X).fit()
exposures.append(model.params[1:]) # 排除截距
return pd.DataFrame(exposures, index=returns.index[window:], columns=factor_returns.columns)
2.3.2 基于截面特征的暴露赋值
对于 Barra 风格因子,暴露通常由资产自身的特征值直接计算:
| 因子名称 | 暴露计算方法 | 数据来源 |
|---|---|---|
| 市值因子 (Size) | \(\text{ln(总市值)}\) 经 Z-score 标准化 | 日频市值数据 |
| 波动率因子 (Volatility) | 过去 60 日收益率年化波动率的秩标准化 | 日频收益率 |
| 价值因子 (Value) | \(\text{ln(B/P)}\) 经行业中性化处理 | 财报账面价值 |
| 动量因子 (Momentum) | 过去 12 个月累计收益率(剔除最近 1 个月) | 月频收益率 |
| 行业因子 | 哑变量编码:属于该行业为 1,否则为 0 | 行业分类标准 |
工程陷阱: 截面标准化时需注意异常值处理。市值因子常呈现右偏分布,直接 Z-score 会导致极端值主导回归结果。建议先取对数,再使用中位数绝对偏差(MAD)替代标准差做稳健标准化。
2.4 因子收益率的计算
因子收益率(Factor Return)是因子在截面上的溢价,即每单位暴露所获得的超额收益。计算方法取决于模型设定:
2.4.1 时间序列回归法(两步法)
- 第一步: 对每只股票做时间序列回归,估计因子暴露 \(\beta_{i,k}\)。
- 第二步: 在每个截面时点 \(t\),以股票收益率 \(R_{i,t}\) 为因变量,以第一步估计的暴露 \(\beta_{i,k}\) 为自变量,做截面回归,回归系数即为因子收益率 \(f_{k,t}\)。
# Python: 截面回归估计因子收益率
def estimate_factor_returns(returns_cross_section, exposures):
"""
returns_cross_section: 截面收益率 Series (index=股票)
exposures: DataFrame (index=股票, columns=因子)
"""
X = sm.add_constant(exposures)
model = sm.OLS(returns_cross_section, X).fit()
return model.params # 包含截距和所有因子收益率
2.4.2 组合排序法(Fama-French 经典方法)
通过构建多空组合直接计算因子收益率,无需回归:
- SMB (Small Minus Big): 小市值股票组合收益率减去大市值股票组合收益率。
- HML (High Minus Low): 高账面市值比组合收益率减去低账面市值比组合收益率。
- MOM (Momentum): 过去收益最高组合减去过去收益最低组合。
2.5 因子模型的风险归因公式
一旦获得因子暴露矩阵 \(B\) 和因子协方差矩阵 \(\Sigma_f\),组合风险可分解为:
| 风险成分 | 公式 | 含义 |
|---|---|---|
| 因子风险 | \(\sigma^2_{factor} = w^T B \Sigma_f B^T w\) | 由因子波动引起的组合风险 |
| 特质风险 | \(\sigma^2_{specific} = w^T \Delta w\) | 由个股残差波动引起的组合风险 |
| 总风险 | \(\sigma^2_{total} = \sigma^2_{factor} + \sigma^2_{specific}\) | 组合总方差 |
| 因子边际贡献 | \(MCR_k = \frac{w^T B_k \Sigma_f B^T w}{\sigma_{total}}\) | 第 k 个因子对总风险的边际贡献 |
实践要点: 因子协方差矩阵 \(\Sigma_f\) 的估计通常使用指数加权移动平均(EWMA)或收缩估计(Shrinkage),以平衡估计偏差与方差。特质风险矩阵 \(\Delta\) 通常假设为对角矩阵,即残差之间不相关。
2.6 模型验证与诊断
构建因子模型后,需进行以下诊断以确保模型质量:
- 因子显著性检验: 截面回归中因子收益率的 t 统计量是否显著(|t| > 2)。
- 残差自相关检验: 个股残差序列的 Durbin-Watson 统计量是否接近 2。
- 因子多重共线性: 因子暴露矩阵的条件数(Condition Number)是否小于 30,若过大需考虑因子正交化。
- R² 分布: 模型对个股收益率的解释力度,横截面 R² 中位数应 > 30%。
- 因子收益率序列平稳性: ADF 检验确保因子收益率序列平稳,避免伪回归。
工程实践: 在生产环境中,因子模型通常每日重新估计一次暴露,但因子收益率可保持周频或月频更新以降低噪声。建议使用
pandas.DataFrame.rolling 实现滚动回归,并利用 numba 或 joblib 并行加速多只股票的暴露估计。