2. 风险因子体系:系统性风险因子、行业因子与风格因子
风险因子体系是组合风险归因的基石。一个完备的因子体系需要覆盖市场整体波动、行业结构性差异以及个股风格特征三个层次。本章将系统性风险因子(市场、规模、价值、动量等)、行业因子和风格因子进行结构化拆解,并给出数据构建与模型训练中的关键处理要点。
核心原则:因子之间应尽量正交,避免多重共线性;因子收益需具备经济含义与统计显著性;因子载荷需随时间稳定更新。
2.1 系统性风险因子
系统性风险因子解释资产收益中由宏观经济或市场整体波动驱动的部分。以下为最常用的五大系统性因子:
| 因子名称 | 经济含义 | 典型代理变量 | 数据频率 |
|---|---|---|---|
| 市场因子 (MKT) | 整体市场超额收益 | 全市场指数收益率 - 无风险利率 | 日/周/月 |
| 规模因子 (SMB) | 小盘股 vs 大盘股收益差 | 小市值组合收益 - 大市值组合收益 | 月 |
| 价值因子 (HML) | 高账面市值比 vs 低账面市值比收益差 | 高 B/P 组合收益 - 低 B/P 组合收益 | 月 |
| 动量因子 (MOM) | 过去赢家 vs 过去输家收益差 | 过去 12 个月收益最高 30% - 最低 30% | 月 |
| 波动率因子 (VOL) | 低波动 vs 高波动股票收益差 | 过去 60 日波动率最低 20% - 最高 20% | 月 |
数据构建提示:构建因子组合时,需做市值加权或等权处理,并剔除微盘股(市值低于全市场 1% 分位)以避免极端值干扰。因子收益率序列需做平稳性检验(ADF 检验),若存在单位根需差分处理。
2.2 行业因子
行业因子捕捉同一行业内股票共同暴露于特定产业周期、政策或供需冲击的风险。行业因子的构建通常采用虚拟变量回归法或行业组合收益法。
- 虚拟变量回归法:将个股收益对行业哑变量(属于该行业=1,否则=0)做横截面回归,回归系数即为行业因子收益。需注意哑变量陷阱,通常去掉一个基准行业或施加约束(行业因子收益之和为0)。
- 行业组合收益法:直接计算每个行业市值加权组合的收益率,再减去市场因子收益得到纯行业因子收益。该方法更直观,但需确保行业分类标准统一(如 GICS、申万一级)。
行业因子数量通常为 10~30 个,过多会导致因子间高度相关。建议在模型训练前做行业因子间的相关性聚类,合并高度相关的行业(如“银行”与“非银金融”)。
# 行业因子收益计算示例(Python 伪代码)
import pandas as pd
import numpy as np
# 假设 returns: 个股收益率矩阵 (T x N)
# industry: 行业标签列表 (N,)
# market_cap: 市值序列 (N,)
def compute_industry_factors(returns, industry, market_cap):
unique_industries = np.unique(industry)
industry_factors = pd.DataFrame(index=returns.index)
for ind in unique_industries:
mask = (industry == ind)
weights = market_cap[mask] / market_cap[mask].sum()
ind_ret = returns.loc[:, mask].dot(weights)
industry_factors[ind] = ind_ret
# 去市场因子:减去等权市场收益
market_ret = returns.dot(market_cap / market_cap.sum())
industry_factors = industry_factors.subtract(market_ret, axis=0)
return industry_factors
2.3 风格因子
风格因子描述个股在特定财务或交易特征上的暴露,通常由个股特征值经标准化后得到。常见的风格因子包括:
| 风格因子 | 计算方式 | 典型暴露范围 | 处理要点 |
|---|---|---|---|
| 成长因子 | 过去 3 年 EPS 增长率 Z-score | [-3, 3] | 剔除负增长极端值,缩尾处理 |
| 杠杆因子 | 总负债 / 总资产,再取秩标准化 | [0, 1] | 金融行业需单独处理或剔除 |
| 流动性因子 | 过去 20 日日均换手率对数 | [-5, 5] | 与市值因子高度相关,需正交化 |
| 盈利因子 | ROE(净资产收益率) | [-20%, 40%] | 使用过去 12 个月滚动 ROE |
| 残差波动因子 | 个股收益对市场回归后的残差波动率 | [0, 10%] | 需先做市场回归,再计算残差标准差 |
常见陷阱:风格因子之间以及与系统性因子之间往往存在天然相关性。例如,小市值股票通常流动性更高、成长性更强。在模型训练前,必须对因子做正交化处理(如 Gram-Schmidt 正交化或回归残差法),否则会导致因子收益估计偏误。
2.4 因子体系结构总览
下图展示了完整的风险因子体系层级关系,以及各因子在组合风险归因中的角色:
2.5 因子数据构建流程
构建风险因子数据需遵循以下标准化流程,确保数据质量与模型稳定性:
- 原始数据清洗:剔除 ST、*ST、退市整理期股票;处理缺失值(前向填充或行业均值填充);对极端值做缩尾处理(1% 和 99% 分位)。
- 因子计算:按上述表格中的代理变量计算每个因子的原始值。注意系统性因子需先构建多空组合,行业因子需做市值加权,风格因子需做 Z-score 标准化。
- 因子正交化:使用 Gram-Schmidt 方法或回归残差法,依次将风格因子对系统性因子和行业因子做回归,取残差作为正交化后的因子暴露。正交化顺序通常为:市场 → 行业 → 风格。
- 因子收益估计:在横截面回归中,将个股收益对因子暴露做回归,估计每期因子收益。回归需使用加权最小二乘法(WLS),权重为市值平方根。
- 因子协方差矩阵估计:使用指数加权移动平均(EWMA)或 DCC-GARCH 模型估计因子收益的协方差矩阵,半衰期通常设为 60 个交易日。
# 因子正交化示例(Python 伪代码)
import statsmodels.api as sm
def orthogonalize_factors(factor_exposure, base_factors):
"""
factor_exposure: 待正交化的因子暴露 (T x N)
base_factors: 基础因子暴露矩阵 (T x K)
返回正交化后的因子暴露
"""
T, N = factor_exposure.shape
orthogonalized = np.zeros_like(factor_exposure)
for i in range(N):
y = factor_exposure[:, i]
X = sm.add_constant(base_factors)
model = sm.OLS(y, X).fit()
orthogonalized[:, i] = model.resid
return orthogonalized
模型训练关键参数:因子收益估计的回归频率建议为月度(避免日度噪声);因子协方差矩阵的 EWMA 半衰期建议在 30~90 天之间,可通过交叉验证选择最优半衰期;行业因子数量建议控制在 15~20 个,风格因子数量建议 5~8 个。
2.6 因子有效性检验
在将因子纳入风险模型前,需进行以下三项检验:
| 检验类型 | 统计量 | 阈值 | 处理方式 |
|---|---|---|---|
| 因子收益显著性 | t 统计量(H0: 因子收益=0) | |t| > 2.0 | 不显著则考虑剔除或合并 |
| 因子暴露稳定性 | 自相关系数(滞后 1 期) | ρ > 0.7 | 暴露不稳定则缩短更新窗口 |
| 因子间相关性 | Pearson 相关系数 | |r| < 0.6 | 高度相关则合并或正交化 |
通过上述检验的因子体系,即可用于后续的组合风险归因模型训练。下一阶段将基于此因子体系构建风险因子载荷矩阵与因子收益协方差矩阵,为风险分解与边际贡献计算奠定基础。