M14 绩效评估与归因¶
层级:L3 组合管理 | 优先级:★★ | 预计学时:10 小时 对应原书:GK 第 17 章;因子 7.6–7.7;黑箱第 12 章 前置知识:M09 的信息比率;M11 的方差拆分;M13 的扣费。 读书笔记:GK 第 17 章的业绩 状态:reviewed 数据截至:2026-08|最近复核:2026-10-22
学习目标¶
- 手算 Brinson–Fachler 的配置、选择和交互,并核对三项之和等于主动收益。
- 分清 Fachler 与 Hood 在单个行业上的差别,以及现金没有被写成一组时合计对不上的原因。
- 用四个月的构造回归看年化 α 1.20% 怎样对应 t = 0.192。
- 用 t = IR √Y 计算信息比率 0.60 在 t = 2 和 t = 1.96 下各要多少年。
- 把扣费、持仓和事前暴露写进月复盘,而不是事后把超额叫做某种风格。
本章知识拓扑图¶
flowchart TB
RET["组合收益与基准收益"] --> BR["Brinson 三项"]
HOLD["行业权重"] --> BR
FAC["因子收益"] --> REG["时间序列回归"]
RET --> REG
REG --> ALPHA["截距与 t 值"]
ALPHA --> YEARS["t = IR × √年数"]
HOLD --> RISK["M11 的方差份额"]
COST["M13 的拖累"] --> RET
归因回答的是这段收益落在哪一列上。它不把一个构造出来的 1.20% 变成技能,也不把没有持仓的产品写成已经测过的风格暴露。
🟢 入门层:主动收益先要有同一张基准¶
1. 基准和组合用同一组资产¶
主动的 3.00 个点拆成三笔:押对股票这条赛道 1.60 个点,赛道里把股票挑到 12% 而基准股票只有 10% 的选择 0.80 个点,超配又恰逢挑中的交互 0.60 个点。 1.60 + 0.80 + 0.60 = 3.00,等于组合 0.098 减基准 0.068。 两组权重都要落在同一组资产上。现金没进分组时,这个加法会离开主动收益。 只做多账户的现金是常态。月记里先写明基准是哪一张,再拆这三笔。
两组都满仓。基准:股票 60%、收益 10%,债券 40%、收益 2%。组合:股票 80%、收益 12%,债券 20%、收益 1%。
R_b = 0.60 × 0.10 + 0.40 × 0.02 = 0.068 Rₚ = 0.80 × 0.12 + 0.20 × 0.01 = 0.098
主动收益是 0.030。Brinson 与 Fachler (1985, JPM 11(3)) 把其中的配置写成行业超额,而不是行业本身的收益:
配置 = Σⱼ(w_(p,j) − w_(b,j))(R_(b,j) − R_b) 选择 = Σⱼ w_(b,j)(R_(p,j) − R_(b,j)) 交互 = Σⱼ(w_(p,j) − w_(b,j))(R_(p,j) − R_(b,j))
| 项目 | 计算 | 结果 |
|---|---|---|
| 配置 | 0.20 × (0.10 − 0.068) + (−0.20) × (0.02 − 0.068) | 0.0160 |
| 选择 | 0.60 × 0.02 + 0.40 × (−0.01) | 0.0080 |
| 交互 | 0.20 × 0.02 + (−0.20) × (−0.01) | 0.0060 |
| 合计 | 0.0160 + 0.0080 + 0.0060 | 0.0300 |
股票超配的 0.20 只因为股票比基准总收益高 3.2 个百分点而得到 0.64 个百分点;低配债券又因为债券比基准低 4.8 个百分点而得到 0.96 个百分点。配置合计 1.60 个百分点。Brinson、Hood 与 Beebower (1986, FAJ 42(4)) 的配置用 R_(b,j) 本身。两组权重都加总到 1 时,两种配置的合计相同,都是 0.0160。行业层面上不同:股票一列,Hood 是 0.20 × 0.10 = 0.020,Fachler 是 0.0064。把「股票涨了」记成配置贡献,用的是 Hood 的行业列。
2. 现金没进分组时,Fachler 的合计会离开主动收益¶
组合只把 40% 放在股票、20% 放在债券,收益仍是 12% 和 1%,其余 40% 没有被写成一组。按这两组点积,组合收益是 0.050,基准仍是 0.068,主动收益是 −0.0180。Fachler 三项合计只有 0.0092。差额
−0.0180 − 0.0092 = −0.0272 = 0.068 × (−0.40)
是基准收益乘上少投的那 0.40。Hood 的三项合计仍等于 −0.0180,因为它没有减去这个基准。个人账户经常留现金。分组里若没有现金,Fachler 的三根柱子不能拿来对账。把现金写成收益为 0 的一组,主动权重才会重新加总为 0。
月记里写「这个月跑赢了」,先要有一张和持仓同一组资产的基准。60/40、恒生指数和你的 15 只股票不是自动的同一张表。 现金没有进分组时,少投的那 40% 会让归因合计离开真实的主动收益。只做多账户的现金是常态,不能假装满仓。 赛道押对、赛道里挑对、以及两件叠在一起,是三笔不同的账。两期复利之后还有交叉项,直接把月度三项相加对不上净值。
🟡 进阶层:因子截距和需要多少年¶
3. 四个月恢复不出技能¶
构造一个组合:月超额等于 0.001,加上 1 倍市场、0.5 倍 HML,再加上一段已经去掉了常数项和这两个因子的噪声。四个月的最小二乘把系数收回来:月截距 0.001000,年化算术 0.001 × 12 = 0.0120,斜率 1.0000 和 0.5000。自由度是 4 − 3 = 1,截距的 t 值是 0.192。自由度为 1 时,双侧 5% 的 t 临界值约 12.71。0.192 落在它下面。年化 1.20% 在这里是写进数据的常数,不是某条策略的业绩。statsmodels 不在当前环境里;这个回归只用矩阵。
时间序列回归把整个样本里的暴露看成一条直线。持仓每个月都在变时,截距混进了暴露的变化。持仓归因用的是当期权重乘当期因子收益,那需要持仓和暴露,本章的四个月例子没有持仓。M07 里,1963-07 至 2026-08,HML 对市场、SMB、RMW 和 CMA 的月截距是 −0.000222,t = −0.28,CMA 的斜率约 1.00。那条价值收益的大部分落在投资因子上,截距不是一个可以单独领取的 α。
风险占比沿用 M11:那组三只股票的教学账上,市场占方差 57.69%。选股组合若大部分方差来自市场列,收益来源就是市场,不是行业内的选择。M11 的 57.69% 是给定暴露算出来的,不是一条实盘策略的测量。
4. 年数由信息比率决定¶
残差按月独立时,
t = IR × √Y
| 信息比率 | t = 2 的年数 | t = 1.96 的年数 |
|---|---|---|
| 0.25 | 64.000 | 61.466 |
| 0.50 | 16.000 | 15.366 |
| 0.60 | 11.111 | 10.671 |
| 0.75 | 7.111 | 6.830 |
| 1.00 | 4.000 | 3.842 |
信息比率 0.60、t = 2 时,年数是 (2/0.60)² = 11.111。换成 1.96 是 10.671。Newey–West 不改变截距,但会改变 t,从而改变这张表。M07 的 HML 截距 t 值是普通最小二乘,不是这张表的输入。夏普和信息比率也不是同一个比:M01 的夏普对的是超额收益的波动,这里的信息比率对的是相对因子或基准的残差。
Sharpe (1992, JPM 18(2)) 的风格分析还要求系数非负且和为 1。上面的斜率 1 与 0.5 已经加总到 1.5,无约束回归允许这种杠杆。把它截成非负再归一,得到 ⅔ 和 ⅓,那不是约束二次规划的解。
另用四个月的教学收益,组合恰好等于 1 倍第一种风格加 0.5 倍第二种风格,没有噪声。无约束、不带截距的斜率就是 1 和 0.5,残差平方和是 0。加上非负与和为 1 之后,最小化残差平方和的权重是 0.814815 和 0.185185,残差平方和是 0.00008241。把 1 和 0.5 归一成 ⅔ 与 ⅓,残差平方和是 0.00014167,比约束解更大。约束解不是「先回归,再把负数改成 0,再让它们加总为 1」。只做多账户若要一个风格分解,要用这次二次规划的权重,而不是无约束斜率。这四个月不是第 3 节那条带截距、t = 0.192 的回归。
import math
import numpy as np
def brinson_fachler(wp, wb, rp, rb, cash_return: float = 0.0):
"""现金组显式进入权重。权重和不到 1 时,差额记成收益为 cash_return 的一组。"""
wp = np.asarray(wp, dtype=float)
wb = np.asarray(wb, dtype=float)
rp = np.asarray(rp, dtype=float)
rb = np.asarray(rb, dtype=float)
wp = np.append(wp, 1.0 - wp.sum())
wb = np.append(wb, 1.0 - wb.sum())
rp = np.append(rp, cash_return)
rb = np.append(rb, cash_return)
port = float(wp @ rp)
bench = float(wb @ rb)
active_w = wp - wb
allocation = float(active_w @ (rb - bench))
selection = float(wb @ (rp - rb))
interaction = float(active_w @ (rp - rb))
return allocation, selection, interaction, port - bench
def carino_link(port: np.ndarray, bench: np.ndarray) -> np.ndarray:
"""各期系数是对数收益差除以简单收益差,再除以全期的同一个比。"""
def gap(left: float, right: float) -> float:
return math.log((1.0 + left) / (1.0 + right)) / (left - right)
total_p = float(np.prod(1.0 + port) - 1.0)
total_b = float(np.prod(1.0 + bench) - 1.0)
scale = gap(total_p, total_b)
return np.array([
gap(float(p), float(b)) / scale * (float(p) - float(b))
for p, b in zip(port, bench)
])
def style_on_simplex(style_a: np.ndarray, style_b: np.ndarray, target: np.ndarray) -> tuple[float, float]:
# 和为 1 的线段上求最小残差。先回归再归一会落到另一点。
diff = style_a - style_b
beta = float((target - style_b) @ diff / (diff @ diff))
beta = min(1.0, max(0.0, beta))
return beta, 1.0 - beta
5. 两期的三项加总,不等于两期复利后的主动收益¶
两期主动收益简单相加是 0.035,复利之后的主动收益是 0.036090。多出来的 0.001090 是两期收益的交叉项。 Carino 用对数收益除以简单收益的差做平滑系数,把各期的配置、选择、交互缩放到能加回这个复利差。 直接把两期的三项相加,对不上净值。 全期平滑系数 0.903092 就是用来把各期缩放到能加回 0.036090 的那一个数。
第 1 节是第一期:组合 0.098,基准 0.068,主动收益 0.030,三项 0.0160、0.0080、0.0060。第二期另给一组满仓权重。基准股票 60%、债券 40%,组合改成股票 50%、债券 50%。股票收益 0,债券收益 0.05。基准收益 0.60 × 0 + 0.40 × 0.05 = 0.020,组合收益 0.50 × 0.05 = 0.025,主动收益 0.005。两组资产在组内没有第二种收益,选择和交互都是 0。Fachler 配置是
(−0.10) × (0 − 0.020) + (0.10) × (0.05 − 0.020) = 0.0050
两期主动收益简单相加是 0.030 + 0.005 = 0.035。复利之后
1.098 × 1.025 − 1 = 0.125450, 1.068 × 1.020 − 1 = 0.089360
主动收益是 0.125450 − 0.089360 = 0.036090。多出来的 0.001090 是 0.098 × 0.025 − 0.068 × 0.020,也就是两期收益的交叉项。把两期的配置、选择、交互直接相加,得到 0.035,对不上 0.036090。
Carino 的平滑系数用对数收益除以简单收益的差。全期系数是 0.903092。第一期是 0.923420,第二期是 0.977997。用全期系数去除各期系数,再乘各期主动收益:
0.923420/0.903092 × 0.030 = 0.030675 0.977997/0.903092 × 0.005 = 0.005415
两项相加是 0.036090。连接系数改变的是各期贡献的刻度,不改变每一期内部配置、选择、交互的比例。第一期连上之后仍是 0.0160、0.0080、0.0060 各自乘 0.030675/0.030。本章没有把这个比例再拆回三列,因为第二期的选择和交互本来就是 0。
6. 波动率对权重是一次齐次,所以风险贡献加总等于波动¶
Euler 定理说:一次齐次函数等于每个自变量乘上它对这个函数的偏导,再求和。组合波动对权重是一次齐次的。把全部权重乘以 2,波动也乘以 2。因此
σₚ = Σᵢ wᵢ ∂σₚ / (∂ wᵢ)
偏导是 (Σ w)ᵢ / σₚ。M11 那组两只股票、各持一半、波动 30% 和 20%、相关 0.5,风险贡献是 0.1376 和 0.0803,加总 0.2179,就是这组输入下的组合波动。份额 63.16% 和 36.84% 加总为 1,那是再除了一次波动。Euler 分解给出的是前一个加总。它需要持仓和协方差。只有收益、没有持仓时,做的是上一节的风格回归,不是这一节的风险贡献。
7. 扣费以后的技能检验¶
Kosowski、Timmermann、Wermers 与 White (2006, JF 61(6)) 用自助法比较基金 α 和「没有技能」的分布。Barras、Scaillet 与 Wermers (2010, JF 65(1)) 用虚假发现率估计扣费后仍可被判为有正 α 的比例,并报告这一比例在样本末期约为 0.6%。Carhart (1997, JF 52(1)) 把业绩持续性的一大部分联系到动量暴露和费用。M09 里,Frazzini、Kabiller 与 Pedersen (2018) 的伯克希尔样本是 1976-10 至 2017-03:超额 18.6%,波动 23.5%,夏普 0.79,市场调整后的信息比率 0.64,平均杠杆约 1.7。控制 BAB 和 QMJ 之后,α 不再显著。论文没有给出一个可以抄进本章的新 α 百分比。杠杆上限 1.0 也复制不了 1.7。
metrics.py 的夏普是日超额减去 r_f/252,再乘 √252。本章的信息比率用月残差和 √Y。两个数不能放进同一张「技能」表里而不写频率。
🔴 深入层:没有持仓就不要指定风格¶
8. 复盘表先写基准和费用¶
journal/templates/monthly.md 的策略归因要有基准月收益、主动收益、是否已扣费、主要暴露。主动收益和基准用同一个月。扣费前的数不和扣费后的数放在一格。没有持仓时,主要暴露留空,而不是用事后的涨跌去填。
黑箱第 12 章用来核对的是流程:收益来源有没有写在 M00 的对手表里,尝试次数有没有记在 M08,费用有没有按 M13 的 2τ c 扣除,风控是不是 M04 里事先写好的那条。实盘成交和信号表不一致时,回归截距解释的是另一条策略。
真实案例¶
满仓时主动收益 0.030、Fachler 三项 0.0160、0.0080、0.0060,以及四个月回归的 t = 0.192,仍是正文的手算。下面用实验室已经印出的日历年收益,对同一年的 French 月频连乘做回归。样本是 2015–2025 共 11 个完整日历年。French 文件用到 202608,2026 年不足 12 个月,不进这张回归。策略年收益先除掉同年国库券的连乘,截距才是超额。标准误是经典 OLS,自由度 11 − 5 = 6。
案例 1:经典 12-1 的截距,t 只有 1.04¶
momentum_plus_lab/outputs/yearly_returns.csv 的「S1 经典 12-1」,对 Mkt-RF、SMB、HML、Mom 四个全年连乘:
| 项 | 系数 | t |
|---|---|---|
| 截距 | 0.0489 | 1.04 |
| Mkt-RF | 1.377 | 4.75 |
| SMB | 0.730 | 1.16 |
| HML | 0.045 | 0.25 |
| Mom | 0.774 | 2.44 |
R² = 0.831。2022 年这列 Mkt-RF 的连乘是 −20.99%,和 M07 的五因子文件相同。S1 那年的总收益是 −8.46%。正的 Mom 系数对上了 2022 年 Mom 的 +20.20%,但截距的 t = 1.04,自由度 6 的 5% 临界值大约是 2.45。年化 4.89 个百分点的常数,在这 11 年里说明不了技能。Mom 的斜率 0.774 是对一条多空因子的暴露。只做多的账户拿得到多头腿,拿不到空头腿的那一半。
案例 2:等权基准的市场斜率接近 1,价值列很薄¶
同一窗口的「2015 成分等权」:
| 项 | 系数 | t |
|---|---|---|
| 截距 | 0.0590 | 2.68 |
| Mkt-RF | 1.017 | 7.51 |
| SMB | −0.466 | −1.58 |
| HML | 0.171 | 2.00 |
| Mom | −0.202 | −1.36 |
R² = 0.959。市场斜率接近 1,收益的大部分跟着 Mkt-RF 走。HML 的 t = 2.00,临界值大约 2.45。截距 t = 2.68 高于这个临界值,对应的是这 47 只股票的等权相对四个因子列还剩下的常数。它不是 Brinson 表里的配置项,也没有扣掉换手。等权的年化单边换手在 performance_summary.csv 里是 0.23 倍。S1 的信息比率相对 SPY 是 0.84,等权是 1.44。信息比率用的是相对 SPY 的残差,和上面这张四因子截距不是同一个数。
案例 3:没有月度持仓,就不要把斜率填进风格权重¶
这张回归用的是一年一个点的连乘,不是 Sharpe (1992) 那种系数非负且和为 1 的持仓回归。S1 的四条斜率加起来大约是 2.93,等权大约是 0.52。两种都不是可以下单的权重。M12 的 Iter2 把回撤从 43.92% 收到 30.12%,换手升到 3.90 倍。那个差额要进费用列,不能记进截距。Kosowski 等人的自助法和 Barras 等人扣费后约 0.6% 的正 α 比例,是他们的基金样本。这里的 t 值只属于这 11 个日历年。
方法论来源¶
| 概念 / 模型 | 核心文献或规范出处 |
|---|---|
| Brinson–Fachler | Brinson & Fachler (1985), JPM 11(3) |
| Brinson–Hood | Brinson, Hood & Beebower (1986), FAJ 42(4) |
| 多期连接 | Carino 的对数平滑系数。两期主动收益相加对不上复利差 |
| 风格回归 | Sharpe (1992), JPM 18(2),系数非负且和为 1 |
| 基金技能 | Kosowski, Timmermann, Wermers & White (2006), JF 61(6);Barras, Scaillet & Wermers (2010), JF 65(1) |
| 持续性与费用 | Carhart (1997), JF 52(1) |
| 风险贡献 | 波动对权重一次齐次,Euler 分解。M11 的 0.1376 与 0.0803 加总为 0.2179 |
| 图 | figures/M14/plot_attribution.py |
| 日历年因子回归 | Labs/momentum_plus_lab/outputs/yearly_returns.csv 对缓存的 French 月频连乘,2015–2025 |
💡 思考回顾与巩固¶
核心认知纠偏¶
| 误区 | 反例 | 用法 |
|---|---|---|
| 三项归因怎么加都等于主动收益 | 现金不在组内时,Fachler 合计 0.0092,主动收益 −0.0180 | 现金写成一组 |
| Fachler 和 Hood 的配置永远不同 | 权重都满仓时,合计都是 0.0160 | 差别在股票那一列:0.0064 对 0.020 |
| 年化 α 1.20% 就是有技能 | 四个月、自由度 1、t = 0.192 | 对照临界值约 12.71 |
| 信息比率 0.60 大约 7 年就能证明 | t = 2 要 11.111 年;t = 1.96 要 10.671 年 | 用 (t/IR)² |
| 回归斜率可以当作只做多的风格权重 | 1 与 0.5 加总是 1.5 | Sharpe 约束是另一次优化 |
| HML 的收益就是 α | M07 的截距 t = −0.28,斜率主要在 CMA | 截距和因子列分开 |
| 指增回撤说明已经测得小市值 β | M00 只有指数约三成和媒体超额的两位数 | 没有持仓不填暴露 |
| 日频夏普和月频信息比率可以比大小 | 一个用 √252,一个用 √Y | 先写频率 |
| 扣费前的 α 是基金技能 | Barras 等人的 0.6% 是扣费后的样本末期估计 | 费用放进同一张表 |
| 自助法打乱收益就能得到本章的 t | 四个月的 t 来自普通最小二乘 | 不把未做的 10,000 次写成结果 |
费曼自测¶
- 为什么股票配置在 Fachler 里是 0.64 个百分点,在 Hood 里是 2.00 个百分点,合计却一样?
- 0.0272 这个差额从哪两个数乘出来?
- 月截距 0.001 年化成 1.20% 之后,为什么 t 仍然是 0.192?
- 信息比率 0.75 为什么不是「大约 7 年」就够?
自测要点
1. 主动权重加总为 0。Fachler 比 Hood 的每一列都少了 `(wₚ − w_b) R_b`。这些少掉的项加总是 `−R_b × 0 = 0`。股票列从 0.020 变成 0.0064,债券列从 −0.004 变成 0.0096,合计仍是 0.0160。 2. 基准收益 0.068 乘少投的 0.40,得 0.0272。它等于主动收益 −0.0180 减去 Fachler 合计 0.0092 的绝对值。现金被写成一组之后,这一项会进配置,三项重新加总到主动收益。 3. 年化只把月截距乘 12。t 值用的是月残差和自由度 1 的标准误,不随「乘 12」变大。0.192 对 12.71,四个月的常数说明不了技能。 4. (2/0.75)² = 7.111。表里的 7 是四舍五入。若用 1.96,年数是 6.830。残差若有自相关,Newey–West 的 t 会改,年数表不再适用。四维习题¶
A. 概念题¶
- 写出 Fachler 的三项,并说明它们在什么时候加总等于主动收益。
- 时间序列因子回归和持仓归因各要什么数据?
- t = IR √Y 里的信息比率对应哪一个残差?
- 月复盘里的「主要暴露」在没有持仓时为什么留空?
B. 计算题¶
- 用第 1 节的权重和收益,重算基准、组合、三项和股票列的两种配置。
- 用第 2 节的部分仓位,说明 Fachler 合计与主动收益相差 0.0272。
- 信息比率 0.60。t = 2 和 t = 1.96 各要多少年?信息比率 0.25 和 1.00 在 t = 2 下呢?
- 四个月回归的月截距是 0.001,斜率是 1 和 0.5,t = 0.192。年化截距是多少?自由度是多少?
C. 编程实战题¶
- 运行
figures/M14/plot_attribution.py,核对主动收益 0.0300、三项 0.0160、0.0080、0.0060,以及 t = 0.192。 - 把组合权重改成 0.40 和 0.20,确认 Fachler 合计变成 0.0092、主动收益变成 −0.0180。
- 在月复盘表里填一行:基准用第 1 节的 0.068,组合用 0.098,主动收益 0.030,已扣费填「否」,主要暴露填「股票超配 0.20」。不要把 0.030 写成 α。
D. 个人实战思考题¶
- 你的账户经常留 20% 以上的现金。月度 Brinson 表若只有股票和债券两组,你会对哪一个合计数?
- 一条策略的回归斜率稳定在市场 1 附近、截距的 t 值低于 2。继续跑它和改为持有基准,差别落在费用和哪一项暴露上?
- 实验记录里的归因至少要附哪四个输入,才不会把构造出来的 1.20% 写成历史业绩?
完整参考答案与解析
**A1.** 配置、选择、交互的定义见第 1 节。两组权重都加总到 1,而且用的是同一组行业时,三项之和等于组合收益减基准收益。现金没有进分组、组合权重和变成 0.60 时,Fachler 合计不再等于主动收益。 **A2.** 时间序列回归要组合的超额收益和因子收益,暴露被估成整个样本的一条直线。持仓归因要每个月的权重、暴露和因子收益。四个月的例子只有收益,没有持仓,所以只有截距和两条斜率。 **A3.** 它对应相对基准或因子模型的残差,而且要求月份独立。日频夏普用的是另一套波动和 √252。Newey–West 改变 t 时,这张年数表不再直接使用。 **A4.** 没有持仓就不知道超额来自哪一列。M00 的中证 2000 下跌约三成,媒体超额大约是两位数,样本彼此不同。这些数不能填进「主要暴露」。 **B5.** 基准 0.068,组合 0.098,主动收益 0.030。配置 0.0160,选择 0.0080,交互 0.0060。股票列的 Fachler 配置是 0.0064,Hood 是 0.0200。两种配置的合计都是 0.0160。 **B6.** 组合点积 0.050,主动收益 −0.0180。Fachler 合计 0.0092。差额 −0.0272,等于 0.068 × (−0.40)。 **B7.** 0.60:11.111 年与 10.671 年。0.25:64.000 年。1.00:4.000 年。都在 t = 2 的那一列,除了 0.60 同时给了 1.96。 **B8.** 年化截距 0.001 × 12 = 0.0120。自变量含常数项和两个因子,自由度 4 − 3 = 1。t = 0.192。临界值约 12.71。 **C9–C11.** 左图和年数仍由 `figures/M14/plot_attribution.py` 打印。下面复算现金组、Carino 连接和约束风格权重。import numpy as np
alloc, selection, interaction, active = brinson_fachler(
[0.80, 0.20], [0.60, 0.40], [0.12, 0.01], [0.10, 0.02],
)
assert abs(alloc - 0.0160) < 1e-12
linked = carino_link(np.array([0.098, 0.025]), np.array([0.068, 0.020]))
assert abs(float(linked.sum()) - 0.036090) < 1e-6
style_a = np.array([0.02, -0.01, 0.03, 0.00])
style_b = np.array([0.01, 0.02, -0.01, 0.01])
beta, other = style_on_simplex(style_a, style_b, style_a + 0.5 * style_b)
assert abs(beta - 22 / 27) < 1e-6
📌 章节知识总结¶
一句话核心洞察¶
- 满仓例子的主动收益是 3.00 个百分点,Fachler 三项是 1.60、0.80 和 0.60。股票列上,Fachler 是 0.64 个百分点,Hood 是 2.00 个百分点。
- 40% 现金不在分组里时,Fachler 合计 0.92 个百分点,主动收益是 −1.80 个百分点,差额 2.72 个百分点。
- 四个月构造回归的年化截距是 1.20%,t = 0.192,自由度 1。这不是历史业绩。
- 信息比率 0.60 要 11.111 年才到 t = 2,10.671 年到 t = 1.96。
- 没有持仓,就不填风格暴露。M07 的 HML 截距 t = −0.28,说明因子收益本身还要再归因。
公式与样本¶
| 对象 | 表达式或数值 | 前提 |
|---|---|---|
| Fachler 配置 | Σ(wₚ − w_b)(R_(b,j) − R_b) |
满仓时合计 0.0160 |
| 两期复利主动收益 | 0.036090 | 简单相加是 0.035;交叉项 0.001090 |
| Carino 连接 | 0.030675 与 0.005415 | 系数 0.903092、0.923420、0.977997 |
| 约束风格权重 | 0.814815 与 0.185185 | 残差平方和 0.00008241;归一成 ⅔、⅓ 是 0.00014167 |
| Euler | 0.1376 + 0.0803 = 0.2179 | 沿用 M11 的两股票波动 |
| 选择与交互 | 0.0080 与 0.0060 | 同上,合计主动收益 0.0300 |
| 股票列 | Fachler 0.0064,Hood 0.0200 | 主动权重 0.20 |
| 缺现金 | Fachler 合计 0.0092,主动 −0.0180 | 差额 0.068 × 0.40 |
| 构造回归 | 月截距 0.001,斜率 1 与 0.5,t = 0.192 | 四个月,自由度 1 |
| 年数 | (t/IR)² | 残差独立;0.60 与 t = 2 为 11.111 |
| HML 截距 | 月 −0.000222,t = −0.28 | M07,1963-07 至 2026-08 |
| 市场方差份额 | 57.69% | M11 的教学账,不是实盘 |
| 伯克希尔 | 信息比率 0.64,杠杆约 1.7 | M09 所引论文,α 在 BAB 与 QMJ 之后不显著 |
跨模块¶
| 结论 | 交给 | 位置 |
|---|---|---|
| 主动收益不是截距 | 信息比率 | M09 |
| 方差份额 | 风险来自哪一列 | M11 |
| 扣费 | 净额 | M13 |
| HML 与 CMA | 因子再归因 | M07 |
| 2024 年初约三成 | 指数事实,不是风格系数 | M00 案例 3 |
| 月复盘字段 | 基准、主动、扣费、暴露 | ../../../journal/templates/monthly.md |
| 日频夏普 | 不与月频 t 混用 | ../../../src/quant/backtest/metrics.py |
学习指引¶
- 精读:GK 第 17 章怎样把一段业绩放回基准和残差。因子 7.6 的收益归因和 7.7 的风险贡献,对应本章的三项和 M11 的方差份额。
- 对照:三项、差额和年数以脚本为准。Barras 等人的约 0.6%、Kosowski 等人的自助法,都没有在这里重算。
- 项目:月复盘先写基准和是否扣费。没有持仓就让暴露空着。
- 下一步:M15 把这些复盘数字和实盘委托、成交放在同一条运营链上。
自检清单¶
- 能把满仓例子算成基准 0.068、组合 0.098、三项 0.0160、0.0080、0.0060
- 能说明股票列的 0.0064 和 0.0200 合计仍都是 0.0160
- 能把缺现金时的差额写成 0.068 × 0.40
- 能说出四个月回归的 t = 0.192、年化截距 1.20%、自由度 1
- 能算出信息比率 0.60 在 t = 2 时要 11.111 年
- 能指出没有持仓时不填写风格暴露
