某上海公募的沪深300指增基金:基金经理周一早盘想加 3% 宁德时代,通过减 3% 招商银行融资。90 秒之内,风控要回答三个问题——加完之后(1)对沪深300的事前跟踪误差是不是还在 4% 预算之内?(2)哪个因子吃掉了最多的跟踪误差预算?(3)哪几只股票贡献了最多的组合风险?这堂课讲的就是这套事前组合风险归因(ex-ante portfolio risk attribution)算法,以及它如何在 L1 给出的 之上做交易前合规检查。Grinold-Kahn(1999)《Active Portfolio Management》第 17 章是规范参考。
L2 拿 L1 的 、、、 当成给定输入;L2 自己不构造协方差,只用归因代数读取风险。
术语对齐表
本课新增的核心术语,与 data/glossaries/quant-glossary.yaml 标准译名一致:跟踪误差(tracking error, TE)、因子模型(factor model)、因子暴露(factor loading)、Barra 模型(Barra model)、协方差矩阵(covariance matrix)、夏普比率(Sharpe ratio,主动收益的「同款」就是 IR)、贝塔(beta,系统性风险暴露的最简单代表)、风险平价(risk parity,与 PCTR 同质的「按风险等量分配」理念)。后续所有讨论用这些标准译名。
事前组合风险的因子-特异分解
下面是 Inline-code listing 中按固定顺序的五条:
total_variance: sigma_p^2 = w^T * Sigma * w
factor_variance: w^T * B * Sigma_F * B^T * w = b_p^T * Sigma_F * b_p with b_p = B^T * w (portfolio factor exposures)
specific_variance: w^T * D * w = sum_i w_i^2 * D_ii
total_decomposition: sigma_p^2 = factor_variance + specific_variance
empirical_split: factor ~70-90% for typical active equity fund; ~95% for cap-weighted index; ~50% for concentrated stock-picker book
规则:most equity portfolios are factor-risk dominated; specific risk grows in importance for concentrated books。
给定 L1 的 Barra 协方差 与组合权重 ( 维,加和为 1),事前(ex-ante)组合方差是
第一项是因子风险——由组合对 个公共因子暴露贡献的方差;第二项是特异风险——由资产特有残差贡献的方差。两者的比例是任何机构风险报告的第一行头条数:沪深300完全复制(全市值加权)组合的因子比例约 95%(指数权重本身就承袭了跨股共动结构);典型 100–200 只股票的主动权益基金落在 70–90%;集中 10–20 只的选股师组合可能降到 50%(多个独立特异押注的多元化抵消了大量特异风险,残余的因子暴露反而成主要贡献)。
组合层因子暴露与每因子风险归因
定义组合层因子暴露 ( 维)。这是 L2 最核心的一个产出: 是组合在因子 上的暴露,单位是横截面标准差(因为风格因子已被 z-score)。例如 表示组合相对市场偏向小市值 0.3 sigma; 表示偏向高动量 0.5 sigma。
因子风险项展开得很干净:
每因子对因子方差的贡献可拆为对角项 (其它因子归零时的边际贡献)加上交叉项 (与其它因子暴露的协同)。每因子百分比贡献是
加和等于 100%。这就是风险归因报告中「因子归因」那一行的产出方式。
MCTR / CCTR / PCTR:资产层归因
下面是 Inline-code listing 中按固定顺序的五条:
marginal_contribution: MCTR_i = (Sigma * w)_i / sigma_p
component_contribution: CCTR_i = w_i * MCTR_i
percent_contribution: PCTR_i = CCTR_i / sigma_p
euler_identity: sum_i CCTR_i = sigma_p; sum_i PCTR_i = 1.0
actionable_insight: rank assets by PCTR; top-PCTR positions are the actionable risk levers — often NOT the same as top-weight positions
规则:PCTR sums to 1 across assets and identifies the actionable risk-reduction levers。
每只资产 的边际风险贡献(marginal contribution to risk, MCTR)是偏导
回答的是「如果把 增加一个 ,总风险变化多少?」。成分风险贡献(component contribution to risk, CCTR)是 ;按 Euler 齐次函数定理,。百分比风险贡献(percent contribution to risk, PCTR)是 ,加和为 1。
PCTR 是资产层归因的核心输出:按 PCTR 排序就指出了风险贡献前五的资产,而这往往不是权重前五。一只 5% 权重、与大盘高度相关的茅指数白马股可能贡献 12% 风险(PCTR = 0.12);一只 10% 权重、与大盘相关性低的多元化品种可能只贡献 4% 风险(PCTR = 0.04)。基金经理调风险时盯的就是 PCTR——「把 PCTR 排第一的位置减半,跟踪误差能下来多少?」
事前跟踪误差
下面是 Inline-code listing 中按固定顺序的七条:
active_weights: w_a = w - w_B
tracking_error: TE = sqrt(w_a^T * Sigma * w_a)
active_factor_exposure: b_a = B^T * w_a
factor_TE: sqrt(b_a^T * Sigma_F * b_a)
specific_TE: sqrt(sum_i w_a_i^2 * D_ii)
decomposition_identity: TE^2 = factor_TE^2 + specific_TE^2
information_ratio: IR = alpha / TE = expected_active_return / tracking_error
规则:long-only funds typically have factor_TE > specific_TE; market-neutral funds typically have specific_TE > factor_TE。
主动组合(active portfolio)是 , 是基准权重(典型基准:沪深300指增产品基准就是沪深300 ETF 510300 持仓;中证500 / 中证1000 同理)。跟踪误差是主动收益 的标准差:
主动基金按跟踪误差预算运作:产品合同典型规定「相对基准预期跟踪误差 3%–5%」作为风险护栏;风控系统每笔交易前算事前 TE 检查是否在预算内。TE 按 L1 的因子-特异分解同款拆解:
其中 是主动因子暴露——风险报告里「相对基准在哪些因子上偏了多少」的核心读数。因子跟踪误差 和特异跟踪误差 都非负,总 TE 是二者平方和的平方根(交叉项按 与 的正交性恰好为零)。
经验签名:长期跟基准的多头基金通常 factor_TE > specific_TE(主动权重被「不许做空」约束,大头分散到多只跟基准结构相近的票);市场中性多空基金通常 specific_TE >> factor_TE(整套机制就是把因子暴露中性化,赚特异 alpha)。
信息比率与主动管理基本法则
信息比率(information ratio, IR)是主动收益的夏普比率:
CN 公募沪深300指增头部产品净 IR 约 0.6–1.0(费后);量化 500 指增因为残余 alpha 更多通常 IR 更高(头部能到 1.2+);最强的私募中性产品 IR 可以稳定 2.0+。主动管理基本法则(Grinold 1989 JPM):
其中 IC 是信息系数(每笔押注的预测 alpha 与实现收益的相关系数,4.2.3 L1 全推),BR 是广度(每年独立押注的数量)。结论:IC 翻倍 -> IR 翻倍;广度从 50 只扩到 200 只(假设独立)-> IR 乘 。对风险预算分配的含义:4% 跟踪误差预算最好分摊到尽量多的独立押注上;把 TE 集中在 1–2 个押注上,即使 IC 相同也是统计学上的浪费。这就是为什么国内量化指增普遍跑 200–500 只票而非 30 只——不是基本面研究能力不够,是 IR-广度的法则把分散写在了数学上。
实践工作流:交易前合规
Step 1: 基金经理提议交易 delta_w(权重变化)
Step 2: 风控系统计算新组合 w_new = w + delta_w
Step 3: 用 L1 的 Sigma_BARRA + L2 归因算 sigma_p_new、TE_new、因子-特异分解、b_a_new、PCTR 前五、因子 TE 贡献前五
Step 4: 风控经理对照预算,过则放行;超则要求缩规模或重构
Step 5: 实盘成交后系统记录新归因作为下一笔交易前检查的基线
每个交易日、每只受监管主动权益基金都在跑这套流。下面给出可直接套用的两个函数。
实现:risk_attribution
import numpy as np
def risk_attribution(
weights: np.ndarray,
benchmark_weights: np.ndarray,
Sigma_BARRA: np.ndarray,
B: np.ndarray,
Sigma_F: np.ndarray,
D: np.ndarray,
) -> dict:
# 总风险与因子-特异分解
sigma_p = float(np.sqrt(weights @ Sigma_BARRA @ weights))
b_p = B.T @ weights
factor_var = float(weights @ B @ Sigma_F @ B.T @ weights)
specific_var = float(weights @ np.diag(D) @ weights)
factor_var_pct = factor_var / (factor_var + specific_var)
specific_var_pct = specific_var / (factor_var + specific_var)
# 资产层 MCTR / CCTR / PCTR
mctr = Sigma_BARRA @ weights / sigma_p
cctr = weights * mctr
pctr = cctr / sigma_p
# 主动组合与跟踪误差
w_a = weights - benchmark_weights
TE = float(np.sqrt(w_a @ Sigma_BARRA @ w_a))
b_a = B.T @ w_a
factor_TE = float(np.sqrt(b_a @ Sigma_F @ b_a))
specific_TE = float(np.sqrt(w_a @ np.diag(D) @ w_a))
return {
"sigma_p": sigma_p,
"factor_var_pct": factor_var_pct,
"specific_var_pct": specific_var_pct,
"b_p": b_p,
"MCTR": mctr,
"CCTR": cctr,
"PCTR": pctr,
"TE": TE,
"factor_TE": factor_TE,
"specific_TE": specific_TE,
"b_a": b_a,
}
签名(参数名 weights / benchmark_weights / Sigma_BARRA / B / Sigma_F / D、返回字典键)与 US 版逐字节一致。
实现:pre_trade_check
下面这段 Fenced Python 代码块封装了交易前合规检查:把当前权重、拟交易增量、基准、L1 协方差全部送进去,一次性返回拟成交后的总跟踪误差、是否在预算内、PCTR 排第一的资产索引、贡献最多 TE 的因子索引。这是风控经理收到基金经理交易请求后真正调用的函数——它把 L2 的归因代数封成单一接口,90 秒之内给出 yes/no 决策外加可执行的归因报告。每家受监管主动权益基金都在跑这套同样形态的接口,只是变量命名不同。
import numpy as np
def pre_trade_check(
current_weights: np.ndarray,
delta_weights: np.ndarray,
benchmark_weights: np.ndarray,
Sigma_BARRA: np.ndarray,
B: np.ndarray,
Sigma_F: np.ndarray,
D: np.ndarray,
te_budget: float = 0.04,
) -> dict:
# 拟成交后的组合
new_weights = current_weights + delta_weights
current_attr = risk_attribution(current_weights, benchmark_weights, Sigma_BARRA, B, Sigma_F, D)
new_attr = risk_attribution(new_weights, benchmark_weights, Sigma_BARRA, B, Sigma_F, D)
passes_budget = new_attr["TE"] < te_budget
te_change = new_attr["TE"] - current_attr["TE"]
top_pctr_asset_index = int(np.argmax(new_attr["PCTR"]))
# 每因子 TE 贡献
b_a = new_attr["b_a"]
factor_te_sq = b_a @ Sigma_F @ b_a
if factor_te_sq > 0:
b_a_pcd = b_a * (Sigma_F @ b_a) / factor_te_sq
else:
b_a_pcd = np.zeros_like(b_a)
top_factor_te_contributor_index = int(np.argmax(np.abs(b_a_pcd)))
return {
"passes_budget": passes_budget,
"current_TE": current_attr["TE"],
"new_TE": new_attr["TE"],
"te_change": te_change,
"top_pctr_asset_index": top_pctr_asset_index,
"top_factor_te_contributor_index": top_factor_te_contributor_index,
"current_attr": current_attr,
"new_attr": new_attr,
}
签名(参数名、默认 te_budget=0.04、返回字典键)与 US 版逐字节一致。
可视化:PCTR 条形图
Formula Explorer
x^2把 PCTR 按降序条形图画出来,再叠加权重直方图。健康签名:前五 PCTR 加和 30%–50%(分散组合);如果前五 PCTR 加和超过 70%,说明组合过分集中,基金经理需要分散或减仓最高 PCTR 头寸。
练习
Exercise
你是 50 只大盘主动权益基金的风险官 (cn: 50 沪深300板块龙头, V_0 = 100,000,000 RMB),对沪深300 ETF 510300 跟踪误差预算 4%。给定 (i) 当前权重 current_weights, (ii) 基准权重 benchmark_weights, (iii) L1 的 Barra 协方差 Sigma_BARRA、B、Sigma_F、D, (iv) 拟交易 delta_weights(+3% 加最大市值科技股,-3% 减最大市值金融股融资):(a) 调 current_attr = risk_attribution(current_weights, benchmark_weights, Sigma_BARRA, B, Sigma_F, D),报告 sigma_p、TE、factor_var_pct、specific_var_pct;验证因子比例落在典型 70%–90% 区间。(b) 调 pre_trade_check(current_weights, delta_weights, benchmark_weights, Sigma_BARRA, B, Sigma_F, D, te_budget=0.04);报告 passes_budget、current_TE、new_TE、te_change。(c) 报告新组合下 b_a 绝对值前三(相对基准最偏的三个因子)。(d) 按 PCTR 排序,报告新组合前五资产名 + PCTR 值;评论最高 PCTR 资产是否也是权重最大的资产(通常不是——最高 PCTR 通常是中等权重的高相关科技茅指数)。(e) 计算每因子 TE 贡献 pct_factor_k = b_a_k * (Sigma_F @ b_a)_k / (b_a^T @ Sigma_F @ b_a);报告绝对值前三的因子;指认吃掉最多预算的那一个因子。(f) 验证如果新组合超过 4% 预算,把交易缩 50%(delta_weights * 0.5)能否拉回预算内;否则一句话推荐应该减哪一项因子暴露。
提示
w_a = w - w_B 加和应严格等于 0(都是 1 - 1);如果加和不为 0,说明基准或当前权重未归一化。提示
实战注脚:CN 主动权益基金的归因报告
国内公募指数增强(沪深300指增 / 中证500指增 / 中证1000指增)产品每天发的归因报告基本就是 L2 的产出加上一段择时叙事。中信、中金、兴业证券的卖方风险研究每年也会发布行业级 PCTR 排行——某季度新能源板块在主动基金中的 PCTR 占比、消费板块的因子 TE 贡献等——是基金经理调仓的参考。L2 的算法本身十年没变,变的是用什么 Sigma_BARRA 来算:从早年自建小因子模型,到 Barra CNE6 商业授权,再到近年 因子投资(石川 等)开源复刻 + 自建增强因子的混合栈。这一层的工程量在风控团队的日常 80% 用在数据管线、20% 用在新增因子的归因展示——L2 的数学是稳定的,工程是活的。私募方面,千象 / 幻方 / 鸣石等头部量化的 沪深300指增 / 中证500指增 产品都跑这套同型归因,但用的因子库更深(可能 100+ 因子)、 估计更频繁(可能日更而非月更)、合规人对 PCTR 阈值要求更严(top-1 PCTR 不超过总风险 5%)。掌握 L2 的算法就掌握了和这些团队对话的共同语言。
桥接到 L3
L1 给协方差,L2 给方差归因(MCTR / CCTR / PCTR / TE / b_a / IR),L3 上分位数风险——把目光从「典型一天波动多少」(variance-based)切到「最坏的一天能亏多少」(tail-risk)。在险价值(VaR)是损失分布的分位数;条件在险价值(CVaR / 期望损失)是超过 VaR 的平均损失,在 Artzner 等(1999)的一致性公理下比 VaR 更稳。L3 用 L1 的 算参数法 VaR、用历史 P&L 算历史法 VaR、用 + 蒙特卡洛模拟多元 t 分布算 MC VaR;然后讲为什么 2023 起的 FRTB 用 97.5% ES 替代 99% VaR 作为监管资本头条数。