4. 因子暴露计算:因子载荷矩阵、标准化处理、暴露度计算

好,咱们进入第四章。因子暴露计算,这名字听着挺唬人,对吧?

说白了,就是搞清楚你的组合里,到底装了多少「动量」、多少「价值」、多少「质量」这些因子。我当年刚入行时,觉得这步就是个数学游戏。直到有一次,我辛辛苦苦跑出来的回测曲线漂亮得不像话,结果一算暴露,好家伙,全押在市值因子上了。那叫一个惨。

所以,这一章咱们把这事彻底掰扯清楚。

4.1 因子载荷矩阵:你的组合「基因图谱」

因子载荷矩阵,你可以把它想象成一张「基因图谱」。

每一行是一只股票,每一列是一个因子。矩阵里的数值,就是这只股票在这个因子上的「基因表达量」。比如,某只股票在「动量因子」上的载荷是1.5,说明它过去涨得比平均水平猛多了。

我个人习惯,把因子载荷矩阵记作 B。它的维度是 (N × K),N是股票数量,K是因子数量。

核心公式:

r_i = α_i + β_i1 * f_1 + β_i2 * f_2 + ... + β_iK * f_K + ε_i

其中,β_ij 就是股票 i 在因子 j 上的载荷。

嗯,这里要注意:载荷不是凭空算出来的。它通常来自两种方式:

  • 回归法:用历史收益率对因子收益率做回归,系数就是载荷。这是最正统的做法。
  • 特征法:直接用股票的特征值,比如PB的倒数、过去12个月的收益率。简单粗暴,但有效。

我在项目中遇到过一个问题:用回归法算载荷,时间窗口选多长?选60天,噪声太大;选252天,又太滞后。后来我折中了一下,用120天滚动窗口,效果还行。你想想看,这其实是个典型的偏差-方差权衡问题。

4.2 标准化处理:让因子「站在同一起跑线」

算完载荷,你是不是想直接拿过来用?别急。

不同因子的量纲差太多了。比如「波动率因子」的数值可能是0.3,而「市值因子」的数值可能是100亿。你直接拿它们去算暴露,市值因子会直接把其他因子「吃掉」。

所以,标准化是必须的。

我常用的标准化方法有三种:

方法 公式 适用场景
Z-score (x - μ) / σ 数据近似正态分布时
分位数标准化 映射到[0,1]或[-1,1] 数据有极端值时
市值加权标准化 以市值为权重做调整 需要消除市值偏差时

我个人最常用的是Z-score。为什么?因为它保留了数据的相对大小关系,而且处理起来简单。

小技巧:标准化时,一定要用「截面」数据做。也就是说,在每个时间点上,对所有股票的某个因子做标准化。千万别用时间序列上的均值和标准差,那会引入未来信息。

我曾经犯过一个低级错误:用全历史数据算均值和标准差,然后做标准化。结果呢?回测时看起来完美,实盘时一塌糊涂。因为历史均值里包含了未来数据,这叫「前视偏差」。嗯,从那以后,我每次做标准化都会反复检查:是不是只用了截止到当前时刻的数据。

4.3 暴露度计算:组合层面的「因子体检报告」

好了,现在你有了标准化的因子载荷矩阵 B,也有了组合的持仓权重向量 w

组合在因子 j 上的暴露度,其实就是持仓权重的加权平均:

组合暴露度公式:

Exposure_j = Σ (w_i * B_ij)

其中,w_i 是股票 i 在组合中的权重,B_ij 是标准化后的因子载荷。

说白了,就是把你组合里每只股票的因子载荷,按权重加起来。结果是一个 K 维向量,每个分量代表组合在该因子上的暴露。

举个例子:

  • 组合在「价值因子」上的暴露是 0.8,说明你偏重价值股。
  • 在「动量因子」上的暴露是 -0.3,说明你偏重反转股。
  • 在「市值因子」上的暴露是 0.1,说明你基本中性。

我一般会把这个暴露度向量画成一张「雷达图」或「条形图」,一眼就能看出组合的因子风格。你想想看,这比看一堆数字直观多了。

避坑指南:计算暴露度时,权重 w_i 必须是「当前」的持仓权重,而不是期初的。因为组合会调仓,权重会变。我曾经用期初权重算暴露,结果发现组合的因子暴露一直在漂移,还以为模型出了问题。后来才发现,是权重没更新。

4.4 核心逻辑:一张图说清楚

为了让你更直观地理解整个流程,我画了一张流程图。它展示了从原始数据到最终暴露度的完整链路。

因子暴露计算核心流程 步骤1:原始数据 股票收益率 + 因子特征值 步骤2:因子载荷矩阵 回归或特征法计算 B 矩阵 步骤3:标准化 Z-score / 分位数 步骤4:组合权重 w 当前持仓权重向量 步骤5:暴露度计算 Exposure = w' * B 步骤6:结果输出 因子暴露向量 反馈:调整权重或因子,重新计算

这张图里,我特意加了一个反馈回路。为什么?因为因子暴露计算不是一次性的。你算完暴露,发现组合在某个因子上偏得太多,就得调整权重,然后重新算。这是一个迭代优化的过程。

4.5 代码示例:Python 实现

光说不练假把式。我给你一段 Python 代码,直接跑就能用。

import numpy as np
import pandas as pd

# 假设我们有 5 只股票,3 个因子
# 因子载荷矩阵 B (5x3)
B = np.array([
    [1.2, 0.8, -0.3],
    [0.9, 1.1, 0.2],
    [1.5, -0.2, 0.7],
    [0.6, 0.4, 1.3],
    [1.1, 0.9, -0.1]
])

# 组合权重 w (5x1)
w = np.array([0.2, 0.3, 0.1, 0.25, 0.15])

# 1. 标准化处理(Z-score)
B_mean = B.mean(axis=0)
B_std = B.std(axis=0)
B_standardized = (B - B_mean) / B_std

# 2. 计算组合暴露度
exposure = w @ B_standardized

# 输出结果
print("标准化后的因子载荷矩阵:")
print(pd.DataFrame(B_standardized, columns=['因子1', '因子2', '因子3']))
print("\n组合因子暴露度:")
print(pd.Series(exposure, index=['因子1', '因子2', '因子3']))

这段代码里,我用了矩阵乘法 @,简洁高效。你想想看,如果用手写循环,不仅慢,还容易出错。在量化里,能用矩阵运算就别用循环,这是铁律。

扩展阅读:如果你用的是 Barra 模型,因子载荷矩阵通常由「行业因子」和「风格因子」两部分组成。行业因子是 0/1 变量,风格因子是标准化后的特征值。计算暴露时,需要分别处理。

好了,这一章的内容就这些。因子暴露计算,说白了就是三步:算载荷、标准化、加权平均。每一步都有坑,但只要你按我上面说的做,基本不会出大问题。

记住:暴露度不是目的,而是手段。它的真正价值,是帮你理解组合的风险来源,然后做出调整。


公众号:蓝海资料掘金营,微信deep3321