Black-Litterman starts from implied equilibrium excess returns and updates them with investor views weighted by confidence. A view can specify an absolute return or a spread between assets. The result is a revised vector of expected excess returns that can feed a portfolio optimiser.
Historical average returns can vary sharply with the observation window. Black-Litterman begins with a benchmark allocation and asks which expected excess returns would make that allocation optimal under the chosen
risk model. You then express views in the dimensions where you have information. For instance, saying that equities will outperform bonds by six percentage points is a view on the equity-bond spread. You can be confident about the spread even when the level of each return is uncertain.
The update compares your stated spread with the spread already implied by the benchmark. A small difference produces a small update. A large difference with high confidence produces a larger tilt. Assets outside the view can also move when their expected returns are linked to that view by the prior
covariance.
Write the prior and the view in compatible units
Let wm be the benchmark weights, Σ the asset return covariance, and δ the risk aversion parameter. The unconstrained quadratic objective w⊤π−2δw⊤Σw has first-order condition
π=δΣwm.
Use π as the prior mean for unknown expected excess returns μ. Model μ∼N(π,C) with C=τΣ. Express the views as Q=Pμ+ε, where ε∼N(0,Ω) is independent of the prior. Each row of P defines the portfolio whose return the corresponding view describes. Conditioning the joint Gaussian gives
μBL=π+CP⊤(PCP⊤+Ω)−1(Q−Pπ).
The posterior covariance of the uncertain mean is C−CP⊤(PCP⊤+Ω)−1PC. Under a model where next-period returns have conditional covariance Σ given μ, the predictive covariance is Σ plus that posterior covariance. State which matrix your allocation process uses.
A relative view is a statement about a
linear combination. A row
[1,−1] says “equity return minus bond return,” so the view input
q is a spread and its uncertainty is uncertainty about that spread. One can read the update as a prior estimate plus a scaled surprise
q−Pπ. If the prior already predicts the view, the surprise is zero. Increasing the view-error covariance makes the update smaller, with other inputs fixed. The covariance can still transmit the adjustment to assets that are not named in the view.
Take a 60% equity and 40% bond benchmark,
δ=2.5, equity
variance 0.04, bond variance 0.01 and covariance 0.006. The implied excess returns are 6.6% and 1.9%, a spread of 4.7%. Express a 6.0% spread view with
P=[1,−1],
τ=0.05 and
Ω=[0.002] in squared-return units. The prior variance of the spread is
0.0019, so the posterior spread moves about
0.0019/(0.0019+0.002)=48.7% of the way from 4.7% to 6.0%. The posterior equity and bond returns are about 7.17% and 1.83%.
In the example the prior spread is 4.7% and the view is 6.0%, so the input to the update is a positive surprise of 1.3 percentage points. The updated spread is only part of the way to the view because the view is uncertain. If you increase its uncertainty while holding the prior fixed, the same 1.3-point surprise has less effect on the revised returns. Keep the view scale and prior covariance in compatible units. Treating 6.0 as a decimal return would overwhelm the calculation for a reason unrelated to confidence.
Compute the view update without explicit matrix inversion
import numpy as np
cov = np.array([[0.04, 0.006], [0.006, 0.01]])
prior = 2.5 * (cov @ np.array([0.6, 0.4]))
prior_mean_cov = 0.05 * cov
view_exposure = np.array([[1.0, -1.0]])
view = np.array([0.06])
view_error_cov = np.array([[0.002]])
surprise = view - view_exposure @ prior
view_cov = view_exposure @ prior_mean_cov @ view_exposure.T
update = np.linalg.solve(view_cov + view_error_cov, surprise)
posterior = prior + prior_mean_cov @ view_exposure.T @ update
print(100 * posterior)
References and next steps