第 7 章 · 02 主观观点融合 本节摘要:有了先验还不够——你总有些「AAPL 要涨 20%」「GOOG 会跑赢 FB」的判断。Black-Litterman 的第二块基石是「贝叶斯融合」:把主观观点(view)通过 P/Q 矩阵编码,通过 Ω 矩阵表达观点的不确定度,用贝叶斯公式把先验和观点加权融合,得到后验收益。本节讲清 类的两大输入——观点(P/Q 或 absoluteviews)、置信度(omega),以及 BL 后验公式 的实现细节。读完本节,你能把任意主观观点融合成稳定的后验收益。 内容来源:原项目源码 、文档 、cookbook ,汉化并套用体系化模板。 学习目标 阅读完本节,你应当能够: 区分 绝对观点 与 相对观点,分别用 和 编码。
本节摘要:有了先验还不够——你总有些「AAPL 要涨 20%」「GOOG 会跑赢 FB」的判断。Black-Litterman 的第二块基石是「贝叶斯融合」:把主观观点(view)通过 P/Q 矩阵编码,通过 Ω 矩阵表达观点的不确定度,用贝叶斯公式把先验和观点加权融合,得到后验收益。本节讲清
BlackLittermanModel类的两大输入——观点(P/Q 或 absolute_views)、置信度(omega),以及 BL 后验公式E(R)=[(τΣ)⁻¹+PᵀΩ⁻¹P]⁻¹[(τΣ)⁻¹Π+PᵀΩ⁻¹Q]的实现细节。读完本节,你能把任意主观观点融合成稳定的后验收益。
内容来源:原项目源码
pypfopt/black_litterman.py、文档docs/BlackLitterman.rst、cookbook4-Black-Litterman-Allocation.ipynb,汉化并套用体系化模板。
阅读完本节,你应当能够:
absolute_views 和 P/Q 编码。BL 模型支持两种观点:
绝对观点对应 P 矩阵里只有一个 1 的行,相对观点对应多个非零项(正负各半)且和为 0 的行。
最简单的输入方式——传一个 {ticker: 收益} 字典,库自动构造 P 和 Q:
viewdict = { "AAPL": 0.20, "BBY": -0.30, "BAC": 0, "SBUX": -0.20, "T": 0.15, } bl = BlackLittermanModel(cov_matrix, pi=market_prior, absolute_views=viewdict)
源码 _parse_views 自动构造 P/Q:每行只有一个 1(在 ticker 对应位置):
def _parse_views(self, absolute_views): views = pd.Series(absolute_views) k = len(views) Q = np.zeros((k, 1)) P = np.zeros((k, self.n_assets)) for i, view_ticker in enumerate(views.keys()): Q[i] = views[view_ticker] P[i, list(self.tickers).index(view_ticker)] = 1 # 该行只有 1 个 1 return Q, P
💡 不必对每个资产都有观点:你只需对关心的几个资产表达看法,其他资产通过协方差自动「连带」。这正是 BL 的优雅之处。
相对观点必须手动写 P。文档里的经典例子:宇宙是 [SBUX, GOOG, FB, AAPL, BAC, JPM, T, GE, MSFT, XOM],四个观点:
import numpy as np Q = np.array([-0.20, 0.05, 0.10, 0.15]).reshape(-1, 1) P = np.array([ [1, 0, 0, 0, 0, 0, 0, 0, 0, 0], # SBUX [0, 0, 0, 0, 0, 0, 0, 0, 1, 0], # MSFT [0, 1, -1, 0, 0, 0, 0, 0, 0, 0], # GOOG - FB [0, 0, 0, 0, 0.5, 0.5, -0.5, -0.5, 0, 0], # (BAC+JPM)/2 - (T+GE)/2 ]) bl = BlackLittermanModel(cov_matrix, pi=market_prior, Q=Q, P=P)
P 矩阵规则:
| 行特征 | 含义 | P 矩阵那行 |
|---|---|---|
| 绝对观点 | 单资产 | 对应位置 1,其他 0 |
| 相对观点 | A 跑赢 B | A 位置 +x,B 位置 -y,行和 = 0 |
⚠️ 行和必须为 0:相对观点的 P 行必须正负抵消,否则会引入「绝对偏向」破坏模型。多资产相对用
+0.5, +0.5, -0.5, -0.5这种均衡写法。
omega 是 K×K 对角矩阵,表示「每个观点的不确定度」(方差越大越不信)。BL 库支持三种来源:
| 来源 | 用法 | 含义 |
|---|---|---|
| default | omega=None(默认) |
Ω = diag(diag(τ·P·Σ·Pᵀ)),与观点组合的方差成比例 |
| idzorek | omega="idzorek", view_confidences=[...] |
用百分比置信度(0~1)推 |
| 自定义 | omega=np.diag([...]) |
直接传 K×K 矩阵 |
源码:
@staticmethod def default_omega(cov_matrix, P, tau): return np.diag(np.diag(tau * P @ cov_matrix @ P.T))
逻辑:观点越涉及高波动资产,自动越不确定。简单稳健,无需额外输入。
允许你用 0~1 的百分比表达「我有多信这个观点」:
confidences = [0.6, 0.4, 0.2, 0.5, 0.7, 0.7, 0.7, 0.5, 0.1, 0.4] bl = BlackLittermanModel( S, pi=market_prior, absolute_views=viewdict, omega="idzorek", view_confidences=confidences )
源码 idzorek_method 的核心:
alpha = (1 - conf) / conf # conf 越低,alpha 越大 omega = tau * alpha * P_view @ cov_matrix @ P_view.T
conf=0 时 omega 设为 1e6(完全不信,等于无观点);conf=1 时 omega=0(完全信,等于强制观点)。
💡 置信度的语义:0.7 表示「我认为这个观点有 70% 的把握」,库会把它换算成 omega 的具体数值。这比直接拍脑袋写方差更直觉。
cookbook 4 给了第三种实用做法——用「1 标准差置信区间」反推:
intervals = [(0, 0.25), (0.1, 0.4), ...] # 每个观点的 68% 置信区间 variances = [((ub - lb) / 2) ** 2 for lb, ub in intervals] omega = np.diag(variances)
BL 公式看着吓人,本质是先验和观点的加权平均:
E(R) = [(τΣ)⁻¹ + PᵀΩ⁻¹P]⁻¹ [(τΣ)⁻¹Π + PᵀΩ⁻¹Q]
(τΣ)⁻¹:先验的「置信度」(τ 越小越信先验)PᵀΩ⁻¹P:观点的「置信度」(Ω 越小越信观点)源码 bl_returns 用线性方程求解避免显式求逆(数值更稳):
def bl_returns(self): if self._tau_sigma_P is None: self._tau_sigma_P = self.tau * self.cov_matrix @ self.P.T if self._A is None: self._A = (self.P @ self._tau_sigma_P) + self.omega b = self.Q - self.P @ self.pi solution = np.linalg.solve(self._A, b) post_rets = self.pi + self._tau_sigma_P @ solution return pd.Series(post_rets.flatten(), index=self.tickers)
💡 τ 的可忽略性:如果你用 default omega 或 idzorek,τ 在矩阵运算中会约掉,最终结果对 τ 不敏感。这就是为什么库默认 τ=0.05 但不强调调参。
BL 也会更新协方差(观点信息让分布更确定):
def bl_cov(self): # ... M = self.tau * self.cov_matrix - self._tau_sigma_P @ M_solution posterior_cov = self.cov_matrix + M return pd.DataFrame(posterior_cov, index=self.tickers, columns=self.tickers)
portfolio_performance 会自动调 bl_cov 算 Sharpe 等指标。日常用法:
ret_bl = bl.bl_returns() # 后验收益 S_bl = bl.bl_cov() # 后验协方差
absolute_views 字典;相对(A 跑赢 B)必须手写 P/Q,P 的相对行必须正负抵消、行和为 0。default(与方差成比例,推荐默认)、idzorek(百分比置信度)、自定义(直接传矩阵或用置信区间反推)。(τΣ)⁻¹ 与 PᵀΩ⁻¹P 是两侧权重。bl_returns() 给后验收益,bl_cov() 给后验协方差,后验收益总是介于先验和观点之间。下一节,我们把这些拼成一条完整流水线——先验 → 观点 → 后验 → 优化,与 Cookbook 4 配套实战。