black_litterman#

  • Series: lecture-python-advanced.myst

  • File: lectures/black_litterman.md

  • Audit date: 2026-08-26

  • Corpus snapshot: b83d6da399

  • Categories audited: writing, math, code, figures, references, links, admonitions (JAX out of scope)

  • Overall score: 6.5 / 10

  • Priority: HIGH

Score breakdown#

Category

Score

One-line note

Writing

3/10

qe-writing-001 ×10; qe-writing-005 ×14; qe-writing-003 ×10, +4 more.

Math

3/10

qe-math-002 ×38; qe-math-010 (proposed) ×18; qe-math-011 (proposed) ×16, +2 more.

Code

7/10

qe-code-001 ×10.

JAX

out of scope

JAX rules target lecture-jax.

Figures

4/10

qe-fig-003 ×5; qe-fig-006 ×7; qe-fig-005 ×4, +2 more.

References

10/10

no mechanical violations detected.

Links

8.5/10

qe-link-001 ×2.

Admonitions

10/10

no mechanical violations detected.

Issues#

Critical#

None found.

High severity#

  • [qe-code-001] (reviewer) — Follow PEP8 unless closer to mathematical notation. Count: 10. Lines: 184, 308, 389, 650, 662, 1401. Example: two naming choices actively mislead, and two cells are duplicated. 308 and 634 assign \(w_m' \Sigma w_m\) - which 252 defines as \(\sigma^2\) - to a variable called σ_m, and 311 then computes sr_m = r_m / np.sqrt(σ_m), so the name says standard deviation and the value is a variance; 314 and 635 call \(\delta_m\) d_m, where 191 writes the same parameter δ. The black_litterman docstring at 390-393 says the function “calculates the Black-Litterman mixture mean excess return and covariance matrix”, but it returns only μ_tilde, and its first parameter λ corresponds to nothing in {eq}`mix-views` and is passed as the literal 1 at both call sites (402, 410). decolletage is defined twice, at 650 and 704, the second shadowing the first, with 28 near-identical lines differing only in τ * Σ_est becoming τ * np.eye(N). Spacing: 184 has (np.random.randn(N) + 5)  /100, with a double space and no space after the operator; 662-663 write alpha =.4 where 716-717 write alpha=.4; 668 and 723 write s=20*3; 656 and 710 leave trailing whitespace. 427 sets ax[1].set_title(...) and 437-438 sets the identical title again through ax[1].set(title=...). 1259 names a variable autocorr_h1000 for np.exp(-κ * n_grid * 1e8) and labels it \(h=\infty\). And 1401-1402 puts a backslash continuation inside a string literal, so the rendered figure title contains a 14-space run.

  • [qe-fig-001] — Do not set figure size unless necessary. Count: 7. Lines: 203, 320, 413, 661, 715, 1261, 1397. Example: figsize=.

  • [qe-fig-003] — No matplotlib embedded titles. Count: 5. Lines: 204, 321, 427, 1268, 1401. Example: .set_title.

  • [qe-fig-006] — Lowercase axis labels. Count: 7. Lines: 212, 326, 673, 674, 728, 729, 1403. Example: axis label Assets.

  • [qe-math-002] — Use \top for transpose notation. Count: 38. Lines: 121, 130, 244, 252, 527, 555, 556, 583, 584, 592, …. Example: apostrophe transpose w'.

  • [qe-math-004] — Do not use bold face for matrices or vectors. Count: 24. Lines: 97, 104, 110, 121, 153, 261, 280, 292, 341, 357, …. Example: {\bf.

  • [qe-math-010 (proposed)] — Blackboard \mathbb{P}, \mathbb{E}, \mathbb{V} with braces. Count: 18. Lines: 759, 760, 762, 778, 821, 1025, 1035, 1111, 1117, 1124, …. Example: missing braces: \mathbb E.

  • [qe-math-011 (proposed)] — Distribution names in plain letters, not \mathcal / \mathbb. Count: 16. Lines: 104, 113, 121, 341, 357, 455, 463, 495, 501, 512, …. Example: decorated distribution {\mathcal N}.

  • [qe-writing-001] — Use one sentence per paragraph. Count: 10. Lines: 133, 569, 754, 847, 905, 954, 1127, 1275, 1333, 1414. Example: 2 sentences in one paragraph.

  • [qe-writing-002] (reviewer) — Keep writing clear, concise, and valuable. Count: 5. Lines: 49, 218, 981, 1205, 1326. Example: 48-52 carries two errors in one sentence - “means are more difficult to estimate that covariances” and “Black and Litterman, on the one hand, an robust control theorists, on the other” - and 218 opens a paragraph with “Black and Litterman’s responded to this situation”. 978-985 runs two statements together with no break: “Here the penalty parameter \(\theta \in [\underline \theta, +\infty]\) is a robustness parameter when it is \(+\infty\), there is no scope for the minimizing agent to distort the distribution”. Three inline maths are glued to the following word so the prose runs into the symbol: $\{X_i\}$is ergodic (1103), $\mu$is the unconditional mean (1200), and $\mathcal T(h) \equiv \{nh : n \in \mathbb Z \}$with$h>0$ (1205), which also loses the spaces around “with”; 153 has vector$(\vec r - r_f {\bf 1})$. And the same display is repeated verbatim eleven lines apart at 1326-1328 and 1337-1339. “Euclidiean” at 505.

  • [qe-writing-003] (reviewer) — Maintain logical flow. Count: 10. Lines: 518, 583, 969, 1010, 1025, 1071, 1316. Example: ten places where a step does not follow from the one before it. (i) 518 standardises the Gaussian as \(\bar{Z} \equiv \Sigma(Z-\mu) \sim \mathcal{N}(\mathbf{0}, I)\), which needs \(\Sigma^{-1/2}\) - as written \(\bar Z\) has covariance \(\Sigma^3\) - and it is precisely the square-root transformation that makes \(\bar z \cdot \bar z = (z-\mu)'\Sigma^{-1}(z-\mu)\) in {eq}`ellipse` at 527. (ii) 581-586 states Leamer’s program as \(\max_{\vec r_e}\) of \((\vec r_e - \mu_{BL})'\Sigma^{-1}(\vec r_e - \mu_{BL})\) subject to the other quadratic form being \(\geq \bar d_2\); the prose at 576-579 asks for the opposite (maximise one likelihood subject to the other’s likelihood being at least \(\bar d_2\), i.e. minimise the first form subject to the second being \(\leq \bar d_2\)), and as displayed the objective is unbounded. (iii) 969 gives the second line of the \({\sf T}\) operator as \(-\log \theta \int \exp(-V/\theta)\phi\,d\epsilon\), where the operator is \(-\theta \log \int \exp(-V/\theta)\phi\,d\epsilon\). (iv) 1010 introduces a \(\zeta\) that is defined nowhere and is absent from the same expression at 1038. (v) 1024-1026 has a doubled closing bracket, no transpose on \(w\), and no \(\frac{\delta}{2}\) on the variance term, so it does not equal 1030-1032 as 1028 claims. (vi) 1038 gives \({\sf T}[w(\vec r - r_f {\bf 1})] = w'\mu - \frac{1}{2\theta}w'\Sigma w\) but 1065-1069 restates the same criterion as \(w'(\mu - \theta^{-1}\Sigma w)\), twice the penalty; only the first is consistent with \(w_{\rm rob} = (\delta+\gamma)^{-1}\Sigma^{-1}\mu\) at 1074. (vii) 1071 calls that \(w_{\rm rob}\) the “minimizer” of the criterion 1056-1057 says is maximised. (viii) 1316 drops the \(\frac{1}{2\kappa}\) from \(\gamma(0)\) that both 1294 and the bound at 1317-1318 carry, and 1317 leaves a stray \cdot where the factor \(i\) was. (ix) 1093-1094 defines \(S_N\) with \(\sum_{t=1}^{N}(X_i - \bar X_N)^2\), summing over \(t\) and indexing by \(i\). (x) 950-951 says relative entropy “is the expected value of the likelihood ratio \(m\)” where 941 and 947 both show it is the expected value of \(\log m\); 760-761 similarly writes \(\mathbb E \beta_{OLS}\) without the hat that 762 has.

  • [qe-writing-005] (reviewer) — Use bold for definitions, italic for emphasis. Count: 14. Lines: 96, 164, 232, 573, 751, 973. Example: definitions are split between the two conventions and bold also carries emphasis. Bold definitions: robust portfolio choice (45), mean-variance portfolio choice model (51), mean-variance portfolio choice problem (124), Sharpe-ratio (264), market’s views (335), likelihood ratio (918), entropy / Entropy (935, 938), spherical symmetry (545). Italic definitions, for terms of exactly the same standing: excess returns (96-97), iso-likelihood in effect at 533-534, curve decolletage (573), information contract curve (575, 595), mean squared error (MSE) (751-752), Tikhonov regularization (790), ridge regression (814), risk-sensitivity (991), frequency and lags (1218-1219), relative MSE (1128). And four uses of bold are plain emphasis, which the rule reserves for italic: plausible (164), extreme long and short positions (167), actual (232), adversary (973). 938 also sets a bold word alone as a de facto heading, “Entropy is defined as”.

  • [qe-writing-008] — Remove excessive whitespace between words. Count: 7. Lines: 38, 42, 66, 116, 837. Example: 2 spaces.

Medium severity#

  • [qe-fig-005] — Descriptive figure names for cross-referencing. Count: 4. Lines: 172, 303, 1249, 1369. Example: code-cell figure without mystnb figure metadata.

  • [qe-fig-008] — Use lw=2 for line charts. Count: 2. Lines: 670, 725. Example: plot() without lw=.

  • [qe-link-001] — Use markdown style links for lectures in same lecture series. Count: 2. Lines: 30, 38. Example: full URL to own series (python-advanced.quantecon.org).

  • [qe-math-009] (reviewer) — Choose simplicity in mathematical notation. Count: 3. Lines: 292, 759, 1124. Example: the same three objects each have two spellings. The market-implied mean is \(\mu_{BL}\) at 231, 341, 370, 381, 477, 495, 555 and 601 but \(\mu_{\bf BL}\) at 292, 362 and 365 - a bold subscript on a two-letter label. The mean squared error function is \text{mse} at 759, 777 and 820 and \text{MSE} at 1124, 1132, 1167, 1173 and 1184. And operators are set in four different fonts across the lecture: {\sf T} (900-1060), {\rm ent} (941, 947), {\rm var} (1025), {\rm rob} (1074), \text{corr} and \text{cov} (1229, 1235, 1292), and {\bf SR}_m (261, 280) - the last putting a scalar in bold. Settling on \mathrm{} for all of them, and on one spelling of each label, costs nothing and removes a reader’s doubt about whether \(\mu_{\bf BL}\) and \(\mu_{BL}\) are the same object.

  • [qe-writing-004] — Avoid unnecessary capitalization in narrative text. Count: 3. Lines: 30. Example: mid-sentence ‘Asset’.

  • [qe-writing-007] (reviewer) — Use visual elements to enhance understanding. Count: 3. Lines: 409, 612, 1080. Example: the two figures at the conceptual centre of the lecture cannot be read. The curve-decolletage panels (649-680, 703-735) exist to show two iso-likelihood ellipses and the contract curve between them, but both densities are filled with the same colormap - ax.contourf(X, Y, Z_hat, cmap='viridis', alpha=.4) immediately followed by the same call for Z_BL - so the two views are indistinguishable; the two scatter calls at 666-667 take default colours with no labels; there is no legend; and the only identification of the two points is a pair of ax.text annotations at 675-676. Second, BL_plot(τ) at 409-443 is written as a function of the mixing parameter and then called exactly once, with \(\tau = 1\) (401, 443), so the dependence on \(\tau\) that 380-386 discusses - “this portfolio \(\tilde w\) will deviate from the portfolio \(w_{BL}\) in amounts that depend on the mixing parameter \(\tau\)” - is never shown, though the machinery to show it is already a one-line loop. Third, the robust-control half of the lecture (886-1082) has no figure at all, and it ends on an assertion that is exactly a plot: 1080-1082 says an increase in \(\gamma\) “shrinks the portfolio weights toward zero in the same way that an increase in risk aversion does”, which \(w_{\rm rob} = (\delta+\gamma)^{-1}\Sigma^{-1}\mu\) makes a two-line computation on the data already in memory.

Low severity#

None found.

Strengths#

  • The lecture makes a promise in the overview and keeps it in the appendix: 54-56 says “at the end of this lecture, we shall use some rates of convergence results and some simulations to verify how means are more difficult to estimate than variances”, and 1084-1418 does exactly that - closed-form MSEs for the IID case (1160-1185), the discretised Ornstein-Uhlenbeck process that puts dependence in (1196-1216), the analytic inflation factor for the mean estimator (1312-1339), an honest admission that the variance estimator’s MSE is harder to derive (1341), and a simulation that supplies it (1348-1405).

  • Both modifications are introduced as answers to one stated embarrassment - that mean-variance weights imply extreme long-short positions (71-79) - and the lecture shows the embarrassment before fixing it: the figure at 172-216 plots the mean-variance weights against the market portfolio with dashed lines at \(\pm 1\), so the reader sees weights outside that band.

  • The Black-Litterman construction is presented as a reverse engineering and the direction of the inference is made explicit: 229-237 backs \(\mu_{BL}\) out of the observed market portfolio, 283-297 backs \(\delta_m\) out of an estimated Sharpe ratio, and 299-301 names the resulting pair \((\delta_m, \mu_m)\) as the model’s starting point - a customer who is told to hold the market.

  • The same recommendation is then given three independent readings, each self-contained: as a Bayesian posterior (446-488), as a point on Leamer’s information contract curve where two likelihoods cannot both be improved (490-610), and as Tikhonov regularisation shrinking \(\hat\mu\) toward \(\mu_{BL}\) (737-884), with the algebra at 839-870 showing the two formulas coincide.

  • The robust-control alternative is built from primitives rather than asserted: the likelihood ratio and its two defining properties (918-925), the distorted density (931-933), relative entropy (935-952), then the \({\sf T}\) operator (961-976), and finally the observation that carries the whole comparison - for an affine value function the worst case distorts the mean but not the covariance (1000-1005), which is exactly the licence Black and Litterman take.

  • The parallel between the two approaches is stated in a form the reader can check: 1074-1082 shows the robust portfolio is \((\delta + \gamma)^{-1}\Sigma^{-1}\mu\), so robustness enters exactly where risk aversion does, which is the sharpest possible statement of the relationship the overview promised at 66-79.

  • The autocorrelation figure at 1249-1271 is chosen to make one point and makes it twice: four decay curves for \(h = 1, 2, 5\) and an effectively infinite \(h\) show both that dependence dies out in \(n\) for fixed \(h\) and that the IID case is the high-\(h\) limit - the two bullets stated just above it at 1245-1247.