black_litterman#
Series: lecture-python-advanced.myst
File:
lectures/black_litterman.mdAudit date: 2026-08-26
Corpus snapshot:
b83d6da399Categories 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 |
|
Math |
3/10 |
|
Code |
7/10 |
|
JAX |
out of scope |
JAX rules target |
Figures |
4/10 |
|
References |
10/10 |
no mechanical violations detected. |
Links |
8.5/10 |
|
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 computessr_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δ. Theblack_littermandocstring 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 literal1at both call sites (402, 410).decolletageis defined twice, at 650 and 704, the second shadowing the first, with 28 near-identical lines differing only inτ * Σ_estbecomingτ * np.eye(N). Spacing: 184 has(np.random.randn(N) + 5) /100, with a double space and no space after the operator; 662-663 writealpha =.4where 716-717 writealpha=.4; 668 and 723 writes=20*3; 656 and 710 leave trailing whitespace. 427 setsax[1].set_title(...)and 437-438 sets the identical title again throughax[1].set(title=...). 1259 names a variableautocorr_h1000fornp.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 hasvector$(\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\cdotwhere 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 forZ_BL- so the two views are indistinguishable; the twoscattercalls at 666-667 take default colours with no labels; there is no legend; and the only identification of the two points is a pair ofax.textannotations 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.
Recommended actions#
Fix the standardisation at 518 (\(\Sigma^{-1/2}\), not \(\Sigma\)) and the sense of Leamer’s program at 581-586, which as displayed maximises an unbounded objective subject to a reversed constraint; the first-order condition at 592 and the solution at 601 are those of the minimisation the prose describes.
Repair the risk-sensitivity operator at 969, which reads \(-\log\theta \int \exp(\cdot)\) for \(-\theta\log\int\exp(\cdot)\), remove or define the \(\zeta\) at 1010, and reconcile 1065-1069 with 1038 - one of the two has twice the entropy penalty, and only 1038 gives the \(w_{\rm rob}\) at 1074.
Correct “minimizer” to “maximizer” at 1071, the doubled bracket and missing \(\frac{\delta}{2}\) at 1025, the missing \(\frac{1}{2\kappa}\) at 1316 and the stray
\cdotat 1317, and the summation index at 1093-1094.Give the two decolletage figures a legend and two distinguishable colours: 662-665 and 716-719 fill both densities with
cmap='viridis'at the same alpha, so the two competing views cannot be told apart, and the points are identified only by bareax.textlabels.Rename
σ_m(308, 634), which holds the variance \(w_m'\Sigma w_m\) that 252 calls \(\sigma^2\) and that 311 immediately takes the square root of, andd_m(314, 635) for the \(\delta_m\) that 191 writes asδ; fix theblack_littermandocstring (390-393), which promises a covariance matrix the function does not return, and drop or use its unusedλargument.Collapse the two
decolletagedefinitions (650, 704) into one function parameterised by the second view’s covariance, and callBL_plot(409) at more than one \(\tau\) so the mixing discussed at 380-386 is visible.Settle the notation and sweep the mechanical load: \(\mu_{BL}\) versus \(\mu_{\bf BL}\) (292, 362, 365),
\text{mse}versus\text{MSE}, and the four operator fonts; then the 36 apostrophe transposes to\top, the 24 bold vectors and matrices ({\bf 1}, {\bf SR}, \mathbf{0}) to plain letters, the 14 unbraced\mathbb E/\mathbb V, the 6\mathcal{N}distribution names, the 5 embeddedset_titlecalls moved intomystnbcaptions withname:fields, the 12plot()calls withoutlw=2, the 7 capitalised axis labels, the two full URLs to this series at 30 and 38, and the escaped underscorer\_fat 1041, which renders literally.