<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[VertoxQuant]]></title><description><![CDATA[Applied quantitative research on trading, risk, and systematic strategy design.]]></description><link>https://www.vertoxquant.com</link><image><url>https://substackcdn.com/image/fetch/$s_!ufaQ!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb77b39-424b-4665-b2a7-7db519ff9e11_128x128.png</url><title>VertoxQuant</title><link>https://www.vertoxquant.com</link></image><generator>Substack</generator><lastBuildDate>Mon, 15 Jun 2026 04:39:16 GMT</lastBuildDate><atom:link href="https://www.vertoxquant.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Vertox]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[vertox@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[vertox@substack.com]]></itunes:email><itunes:name><![CDATA[Vertox]]></itunes:name></itunes:owner><itunes:author><![CDATA[Vertox]]></itunes:author><googleplay:owner><![CDATA[vertox@substack.com]]></googleplay:owner><googleplay:email><![CDATA[vertox@substack.com]]></googleplay:email><googleplay:author><![CDATA[Vertox]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Fast Option Pricing using Fourier Transform]]></title><description><![CDATA[When Monte-Carlo is too slow]]></description><link>https://www.vertoxquant.com/p/fast-option-pricing-using-fourier</link><guid isPermaLink="false">https://www.vertoxquant.com/p/fast-option-pricing-using-fourier</guid><dc:creator><![CDATA[Vertox]]></dc:creator><pubDate>Tue, 09 Jun 2026 22:27:48 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!1H6m!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4db5601f-c43b-4d49-9c77-24bb132dc734_1189x390.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Monte-Carlo Simulation is the most straightforward way to price an option, and if you don&#8217;t care about speed, it&#8217;s a solid choice.</p><p>The moment you care about speed, like when quoting live, or when calibrating a pricing model where you need to reprice options thousands of times, Monte Carlo quickly becomes unusable.</p><p>This article presents three Fourier-based methods that solve this problem, reducing pricing from seconds to microseconds. We&#8217;ll use the Heston model as our running example throughout, and achieve a speedup of 30,000x against Monte Carlo!</p><div><hr></div><p>I write about quantitative trading the way it&#8217;s actually practised:<br><br>Robust models and portfolios, combining signals and strategies, understanding the assumptions behind your models.</p><p>Topics I write about include portfolio construction, market making, risk management, research methodology, and more.</p><p>If this way of thinking resonates, you&#8217;ll probably like what I publish.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.vertoxquant.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">VertoxQuant is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h3><strong>What you&#8217;ll learn</strong></h3><ul><li><p>Why Monte Carlo breaks down for live pricing and model calibration, and what makes it fundamentally unsuitable for production options trading.</p></li><li><p>How the Fourier Transform and FFT work and why they matter for options pricing.</p></li><li><p>What the characteristic function is and how it enables us to price options even when the risk-neutral density of the model has no known closed-form analytical solution.</p></li><li><p>How Carr-Madan transforms option pricing into an FFT problem.</p></li><li><p>How Lewis reformulates the same problem via contour integration, eliminating the dampening parameter that makes Carr-Madan brittle.</p></li><li><p>How the COS method takes a completely different approach, approximating the density via a cosine series, and why it converges exponentially fast.</p></li><li><p>Python implementations for all methods, together with speed comparisons.</p></li></ul><p>This article is free to read, so I would appreciate it if you shared it with someone who would also like it!</p><div><hr></div><h1>The Characteristic Function</h1><p>To price options using Fourier methods, we need one thing from our model: the characteristic function of log S_T where S_T is the price at expiry.</p><p>For a random variable X, the characteristic function is defined as:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\phi(u) = \\mathbb{E}[e^{iuX}]&quot;,&quot;id&quot;:&quot;NRZRNDHLYL&quot;}" data-component-name="LatexBlockToDOM"></div><p>For log S_T we write:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\phi_T(u) = \\mathbb{E}^\\mathbb{Q}[e^{iu \\log S_T}],&quot;,&quot;id&quot;:&quot;WHXRFBHFWZ&quot;}" data-component-name="LatexBlockToDOM"></div><p>where Q is the risk-neutral measure.</p><p>Just like the probability density function, it completely characterises the distribution of X. But while the density q(x) often has no closed-form expression, the characteristic function often does and is much easier to find.</p><p>In fact, the characteristic function and the density are a Fourier transform pair. Given the characteristic function, you can recover the density via the inverse Fourier transform:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;q(x) = \\frac{1}{2\\pi}\\int_{-\\infty}^\\infty e^{-iux}\\phi_T(u)du&quot;,&quot;id&quot;:&quot;TXSKEDBQVZ&quot;}" data-component-name="LatexBlockToDOM"></div><p>This is the core idea behind all Fourier pricing methods. You don&#8217;t need to know the distribution of log S_T explicitly; you just need the characteristic function.</p><h3>Why does the characteristic function always exist?</h3><p>For any model where log S_T is a well-defined random variable, the characteristic function is guaranteed to exist for all real u, since</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;|e^{iu\\log S_T}|=1,&quot;,&quot;id&quot;:&quot;OVHFZELRCR&quot;}" data-component-name="LatexBlockToDOM"></div><p>and thus the expectation is always finite.</p><h3>Pricing in Fourier Space</h3><p>In theory, you could now go ahead and compute the distribution from the characteristic function numerically, and then integrate against the payoff to get the fair value of the option. In practice, Fourier pricing methods skip this step entirely and price directly in Fourier space, which is both faster and more numerically stable.</p><h3>Two Examples</h3><p>For Black-Scholes, log S_T is Gaussian, so the characteristic function is that of a Gaussian random variable, with appropriate mean and standard deviation plugged in:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\phi_T^{\\text{BS}}(u) = \\exp(iu(\\log S_0 + (r-\\frac{\\sigma^2}{2})T) - \\frac{u^2 \\sigma^2 T}{2})&quot;,&quot;id&quot;:&quot;BUAIBETWKQ&quot;}" data-component-name="LatexBlockToDOM"></div><p>For Heston, log S_T has no nice closed-form density expression. But the characteristic function is still available in closed form:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\phi_T^\\text{Heston}(u) = \\exp(iu \\log S_0 + A(T, u) + B(T,u) v_0)&quot;,&quot;id&quot;:&quot;BQMCKPYUJF&quot;}" data-component-name="LatexBlockToDOM"></div><p>where:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\begin{align}\nA(T,u) &amp;= iurT + \\frac{\\kappa \\theta}{\\xi^2}[(\\rho\\xi iu-\\kappa - d)T - 2 \\log \\frac{1-ge^{-dT}}{1-g}] \\\\\nB(T,u) &amp;= \\frac{(\\rho\\xi iu - \\kappa - d)(1-e^{-dT})}{\\xi^2(1-ge^{-dT})}\n\\end{align}&quot;,&quot;id&quot;:&quot;YJHWDCYDMU&quot;}" data-component-name="LatexBlockToDOM"></div><p>with</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\begin{align}\nd &amp;= \\sqrt{(\\rho\\xi i u - \\kappa)^2 + \\xi^2(iu+u^2)} \\\\\ng &amp;= \\frac{\\rho \\xi i u - \\kappa - d}{\\rho \\xi i u - \\kappa + d}\n\\end{align}&quot;,&quot;id&quot;:&quot;DNKVAHASQY&quot;}" data-component-name="LatexBlockToDOM"></div><p>These are derived by applying It&#244;&#8217;s lemma to log S_t, exploiting the affine structure of the Heston dynamics, and solving the resulting Riccati ODEs in closed form.</p><p>How to properly derive this will be the subject of future articles.</p><div><hr></div><h1>Fourier Transform and FFT</h1><p>Before deriving any pricing formulas, we need to understand the Fourier Transform and the Fast Fourier Transform algorithm.</p><h3>The Fourier Transform</h3><p>For a real square integrable function f(x), the Fourier transform is:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\hat{f}(\\xi) = \\int_{-\\infty}^\\infty e^{i\\xi x}f(x)dx&quot;,&quot;id&quot;:&quot;UTWYBTBMIG&quot;}" data-component-name="LatexBlockToDOM"></div><p>This function lives in frequency space; It tells you how much of each frequency xi is present in f. You recover f from hat{f} via the inverse Fourier transform:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;f(x) = \\frac{1}{2\\pi}\\int_{-\\infty}^\\infty e^{-i\\xi x}\\hat{f}(\\xi)dx.&quot;,&quot;id&quot;:&quot;POKSGHEIEV&quot;}" data-component-name="LatexBlockToDOM"></div><p>Two real functions f and g that are both square integrable have a well-defined inner product. Parseval&#8217;s theorem says this inner product can also be computed in Fourier space:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\int_{-\\infty}^\\infty f(x)\\overline{g(x)}dx = \\frac{1}{2\\pi}\\int_{-\\infty}^\\infty \\hat{f}(\\xi)\\overline{\\hat{g}(\\xi)}d\\xi&quot;,&quot;id&quot;:&quot;CZJPYDZBMJ&quot;}" data-component-name="LatexBlockToDOM"></div><p>This will be used later on in the Lewis method.</p><h3>The Discrete Fourier Transform</h3><p>In practice, you work with a finite grid of N points rather than a continuous function. The Discrete Fourier Transform (DFT) of a sequence x_0, x_1, &#8230;, x_{N-1} is:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;X_k = \\sum_{j=0}^{N-1} x_j e^{-i2\\pi\\frac{k}{N}j}.&quot;,&quot;id&quot;:&quot;GKNREUVCLO&quot;}" data-component-name="LatexBlockToDOM"></div><p>Each output X_k is the inner product of the input sequence against a complex exponential at frequency k. Computing all N outputs naively requires evaluating N terms for each of the N outputs, a total of N^2 multiplications.</p><h3>The Fast Fourier Transform</h3><p>For N a power of 2, the Fast Fourier Transform, introduced by Cooley and Tukey, reduces the cost from O(N^2) to O(N log N) by exploiting the fact that the DFT of a sequence of length N can be written as the sum of two DFTs of length N/2.<br>Applying this decomposition recursively, splitting each half into its own two halves, reduces the total number of multiplications to O(N log N). For N = 4096, this is roughly a 340x speedup over the naive approach!</p><p>More formally, the DFT of a sequence of length N can be written as the sum of the DFT over the even-indexed elements and the DFT over the odd-indexed elements:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\begin{align}\nX_k &amp;= \\sum_{j=0}^{N/2-1} x_{2j}e^{-\\frac{2\\pi i}{N}(2j)k} + \\sum_{j=0}^{N/2-1} x_{2j+1}e^{-\\frac{2\\pi i}{N}(2j+1)k}\\\\\n&amp;= E_k + e^{-\\frac{2\\pi i}{N}k} O_k\n\\end{align}&quot;,&quot;id&quot;:&quot;MRVUJQPJJB&quot;}" data-component-name="LatexBlockToDOM"></div><p>where E_k and O_k are the DFTs of the even and odd subsequences.</p><div><hr></div><h1>Carr-Madan</h1><p>The Carr-Madan method (1999) is one of the most popular option pricing methods using the Fast Fourier Transform. </p><p>Let s = log S_T and k = log K. The risk-neutral density of s is q_T(s), with characteristic function</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\phi_T(u) = \\int_{-\\infty}^\\infty e^{ius}q_T(s)ds.&quot;,&quot;id&quot;:&quot;RVDNZUDIKR&quot;}" data-component-name="LatexBlockToDOM"></div><p>The call price as a function of log strike is:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;C_T(k) = e^{-rT} \\int_k^\\infty (e^s - e^k)q_T(s)ds&quot;,&quot;id&quot;:&quot;KWUCVIYOOK&quot;}" data-component-name="LatexBlockToDOM"></div><p>We want to Fourier transform C_T(k). The problem is that C_T(k) is not square-integrable, since as k&#8594; -infinity, C_T(k) &#8594; S_0 rather than decaying to zero. So its Fourier Transform doesn&#8217;t exist in the classical sense.</p><p>The fix is to multiply by an exponential dampening factor. Define the modified call price:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;c_T(k) = e^{\\alpha k }C_T(k), \\quad \\alpha > 0.&quot;,&quot;id&quot;:&quot;OREAOUDLEE&quot;}" data-component-name="LatexBlockToDOM"></div><p>For suitable alpha, c_T(k) is square integrable, since the e^{alpha k) term decays fast enough as k &#8594; -infty to kill the blow-up. Therefore, this has a well-defined Fourier transform:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\Psi_T(v) = \\int_{-\\infty}^\\infty e^{ivk}c_T(k)dk&quot;,&quot;id&quot;:&quot;PGNXSSEZNB&quot;}" data-component-name="LatexBlockToDOM"></div><p>Our goal now is to write an analytical expression of Psi_T in terms of phi_T, and then obtain call prices numerically using the inverse transform.</p><h3>Deriving Psi_T</h3><p>Substitute the definitions of c_T(k) and C_T(k):</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\Psi_T(v) = \\int_{-\\infty}^\\infty e^{ivk}e^{\\alpha k} \\int_k^\\infty e^{-rT}(e^s - e^k)q_T(s)dsdk&quot;,&quot;id&quot;:&quot;KNOJJFVAMM&quot;}" data-component-name="LatexBlockToDOM"></div><p>The region of integration is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\{(k,s):k\\in(-\\infty,\\infty), s\\in(k,\\infty)\\},&quot;,&quot;id&quot;:&quot;QDTKICICLW&quot;}" data-component-name="LatexBlockToDOM"></div><p>which is equivalent to:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\{(k,s): s\\in(-\\infty,\\infty), k\\in(-\\infty,s)\\}.&quot;,&quot;id&quot;:&quot;XZOIDFRDRJ&quot;}" data-component-name="LatexBlockToDOM"></div><p>The integrand is non-negative, so we can apply Tonelli&#8217;s theorem and swap the order of integration:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\Psi_T(v) = \\int_{-\\infty}^\\infty e^{-rT}q_T(s)\\int_{-\\infty}^s e^{\\alpha k}(e^s-e^k)e^{ivk}dkds&quot;,&quot;id&quot;:&quot;ISHVPXYWFS&quot;}" data-component-name="LatexBlockToDOM"></div><p>Expand the inner integrand:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;e^{\\alpha k}(e^s - e^k)e^{ivk} = e^s e^{(a+iv)k} - e^{(1+\\alpha+iv)k}&quot;,&quot;id&quot;:&quot;HGQYHUQOPA&quot;}" data-component-name="LatexBlockToDOM"></div><p>For the first term:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;e^s \\int_{-\\infty}^{s} e^{(\\alpha+iv)k}\\,dk\n= e^s \\left[ \\frac{e^{(\\alpha+iv)k}}{\\alpha+iv} \\right]_{-\\infty}^{s}\n= \\frac{e^{(\\alpha+1+iv)s}}{\\alpha+iv}&quot;,&quot;id&quot;:&quot;HQWOKDWCGU&quot;}" data-component-name="LatexBlockToDOM"></div><p>For the second term:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\int_{-\\infty}^{s} e^{(1+\\alpha+iv)k}\\,dk\n=\n\\left[\n\\frac{e^{(1+\\alpha+iv)k}}{1+\\alpha+iv}\n\\right]_{-\\infty}^{s}\n=\n\\frac{e^{(1+\\alpha+iv)s}}{1+\\alpha+iv}\n\\&quot;,&quot;id&quot;:&quot;KQHGVVZBMS&quot;}" data-component-name="LatexBlockToDOM"></div><p>Substituting back:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\Psi_T(v)\n=\ne^{-rT}\n\\int_{-\\infty}^{\\infty}\nq_T(s)\n\\left(\n\\frac{e^{(\\alpha+1+iv)s}}{\\alpha+iv}\n-\n\\frac{e^{(\\alpha+1+iv)s}}{\\alpha+1+iv}\n\\right)\nds&quot;,&quot;id&quot;:&quot;EJAQULMPLR&quot;}" data-component-name="LatexBlockToDOM"></div><p>Factor out </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;e^{(\\alpha+1+iv)s}&quot;,&quot;id&quot;:&quot;WQCNKASDMR&quot;}" data-component-name="LatexBlockToDOM"></div><p>and recognise that since</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;e^{(\\alpha+1+iv)s} = e^{i(v-(\\alpha+1)i)s},&quot;,&quot;id&quot;:&quot;JCITOQMOGO&quot;}" data-component-name="LatexBlockToDOM"></div><p>we have:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\int_{-\\infty}^{\\infty}\nq_T(s)e^{(\\alpha+1+iv)s}\\,ds\n=\n\\phi_T\\!\\bigl(v-(\\alpha+1)i\\bigr)&quot;,&quot;id&quot;:&quot;LXOBHBZZDJ&quot;}" data-component-name="LatexBlockToDOM"></div><p>So:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\Psi_T(v)\n=\ne^{-rT}\n\\phi_T\\!\\bigl(v-(\\alpha+1)i\\bigr)\n\\left(\n\\frac{1}{\\alpha+iv}\n-\n\\frac{1}{\\alpha+1+iv}\n\\right)&quot;,&quot;id&quot;:&quot;IHAYFWWHPH&quot;}" data-component-name="LatexBlockToDOM"></div><p>After simplifying, we finally get:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\Psi_T(v)\n=\n\\frac{\ne^{-rT}\\phi_T\\!\\bigl(v-(\\alpha+1)i\\bigr)\n}{\n\\alpha^2+\\alpha-v^2+i(2\\alpha+1)v\n}&quot;,&quot;id&quot;:&quot;KLHUNDEGUS&quot;}" data-component-name="LatexBlockToDOM"></div><p>This is expressed entirely in terms of phi_T, the characteristic function of log S_T under our model of choice, which we said earlier we often have a closed-form solution for, so this whole thing is closed-form!</p><h3>Recovery Formula</h3><p>Since Psi_T is the Fourier transform of the dampened call price, standard Fourier inversion gives:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;c_T(k) = \\frac{1}{2\\pi}\\int_{-\\infty}^\\infty e^{-ivk}\\Psi_T(v)dv&quot;,&quot;id&quot;:&quot;ROBKRWKSMX&quot;}" data-component-name="LatexBlockToDOM"></div><p>Dividing both sides by e^{alpha k}:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;C_T(k) = \\frac{e^{-\\alpha k}}{2\\pi} \\int_{-\\infty}^\\infty e^{-ivk}\\Psi_T(v)dv&quot;,&quot;id&quot;:&quot;JBHQINAYDB&quot;}" data-component-name="LatexBlockToDOM"></div><p>Since C_T(k) is real, we have</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\Psi_T(-v) = \\overline{\\Psi_T(v)},&quot;,&quot;id&quot;:&quot;CWCQVZHXMU&quot;}" data-component-name="LatexBlockToDOM"></div><p>so the integrand over (-infty, 0) is the complex conjugate of the integrand over (0,infty), and their sum is twice the real part:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;C_T(k) = \\frac{e^{-\\alpha k}}{\\pi} \\int_0^\\infty \\Re[e^{-ivk} \\Psi_T(v)]dv&quot;,&quot;id&quot;:&quot;NFHKCCALWA&quot;}" data-component-name="LatexBlockToDOM"></div><h3>Choice of alpha</h3><p>Two conditions constrain alpha. First, for Psi_T(0) to be finite, we need</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\phi_T(-(\\alpha + 1)i) = \\mathbb{E}^\\mathbb{Q}[S_T^{\\alpha + 1}]< \\infty.&quot;,&quot;id&quot;:&quot;ABXVPEFLIV&quot;}" data-component-name="LatexBlockToDOM"></div><p>Another condition is alpha not being equal to 0, to avoid a singularity in the denominator at v = 0. For Black-Scholes and Heston, all positive moments exist, so alpha is unconstrained. Carr and Madan suggest using one quarter of the upper bound implied by the moment condition, and find alpha = 1.5 works well in practice.</p><h3>Truncation bound</h3><p>The recovery integral runs from 0 to infinity. We need to verify it converges and can be safely truncated at some finite value a. For that, let&#8217;s first look at the numerator of |Psi_T(v)|.</p><p>It&#8217;s easy to see that</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;|\\phi_T(v-(\\alpha + 1)i)| \\leq \\mathbb{E}^\\mathbb{Q}[S_T^{\\alpha+1}],&quot;,&quot;id&quot;:&quot;NSJWEXFBZI&quot;}" data-component-name="LatexBlockToDOM"></div><p>which is independent of v. </p><p>The denominator of Psi_T(v) grows like v^4 for large v, so:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;|\\Psi_T(v)|^2 \\leq \\frac{\\mathbb{E}[S_T^{\\alpha+1}]}{(\\alpha^2+\\alpha-v^2)^2+(2\\alpha+1)^2v^2} \\leq \\frac{A}{v^4}&quot;,&quot;id&quot;:&quot;FCYSNOBXTY&quot;}" data-component-name="LatexBlockToDOM"></div><p>for some constant A. Therefore</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;|\\Psi_T(v)| \\leq \\frac{\\sqrt{A}}{v^2}&quot;,&quot;id&quot;:&quot;UPQNPZZCAF&quot;}" data-component-name="LatexBlockToDOM"></div><p>and the tail integral from any truncation point a satisfies:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\int_a^\\infty|\\Psi_T(v)|dv \\leq \\frac{\\sqrt{A}}{a}&quot;,&quot;id&quot;:&quot;ADPTSEQJDM&quot;}" data-component-name="LatexBlockToDOM"></div><p>Thus, the truncation error is bounded by:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;|C_T(k) - \\tilde{C}_T(k)| \\leq \\frac{e^{-\\alpha k}}{\\pi}  \\frac{\\sqrt{A}}{a}&quot;,&quot;id&quot;:&quot;LBXBYZITCJ&quot;}" data-component-name="LatexBlockToDOM"></div><p>To achieve a target error epsilon, choose:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;a > \\frac{e^{-\\alpha k} \\sqrt{A}}{\\pi \\epsilon}&quot;,&quot;id&quot;:&quot;NMBVUQDQIF&quot;}" data-component-name="LatexBlockToDOM"></div><h3>FFT discretization</h3><p>Discretize the recovery integral with N points at spacing eta, setting</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;v_j = \\eta(j-1) \\quad \\text{for} \\ j=1,...,N&quot;,&quot;id&quot;:&quot;KYRCIAGAMN&quot;}" data-component-name="LatexBlockToDOM"></div><p>Applying the trapezoid rule:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;C_T(k) \\approx \\frac{e^{-\\alpha k}}{\\pi} \\sum_{j=1}^N e^{-iv_jk}\\Psi_T(v_j)\\eta&quot;,&quot;id&quot;:&quot;BFPFDQYHZN&quot;}" data-component-name="LatexBlockToDOM"></div><p>The effective upper limit of integration is a = N*eta. We want to evaluate this at a grid of N log-strikes</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;k_u = -b + \\lambda(u-1) \\quad \\text{for} \\ u=1,..,N,&quot;,&quot;id&quot;:&quot;GTGJTCNQMM&quot;}" data-component-name="LatexBlockToDOM"></div><p>which gives us log strike levels ranging from -b to b, centred around ATM by setting </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;b = \\frac{1}{2}N \\lambda.&quot;,&quot;id&quot;:&quot;QFOYWNAYFF&quot;}" data-component-name="LatexBlockToDOM"></div><p>Substituting v_j and k_u:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;e^{-iv_jk_u} = e^{ibv_j}e^{-i\\eta\\lambda(j-1)(u-1)}&quot;,&quot;id&quot;:&quot;LYUTYFVUNZ&quot;}" data-component-name="LatexBlockToDOM"></div><p>For the sum to match the DFT structure</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;e^{-i\\frac{2\\pi}{N}(j-1)(u-1)}&quot;,&quot;id&quot;:&quot;ELUALEGWCK&quot;}" data-component-name="LatexBlockToDOM"></div><p>we need</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\lambda\\eta = \\frac{2\\pi}{N}.&quot;,&quot;id&quot;:&quot;LVKFWEQOUE&quot;}" data-component-name="LatexBlockToDOM"></div><p>This is the grid coupling constraint; Fine integration grid (eta small) forces coarse strike spacing (lambda large) and vice versa. The sum becomes:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;C_T(k_u) \\approx \\frac{e^{-\\alpha k_u}}{\\pi} \\sum_{j=1}^N e^{-i\\frac{2\\pi}{N}(j-1)(u-1)}e^{ibv_j}\\Psi_T(v_j)\\eta&quot;,&quot;id&quot;:&quot;IYFYBKYWPY&quot;}" data-component-name="LatexBlockToDOM"></div><p>which is exactly the DFT of the sequence</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;e^{ibv_j}\\Psi_t(v_j)\\eta.&quot;,&quot;id&quot;:&quot;CQLGOVTYBY&quot;}" data-component-name="LatexBlockToDOM"></div><p>A single FFT call evaluates this for all N strikes simultaneously.</p><p>So you build the input vector</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;x_j = e^{ibv_j}\\Psi_T(v_j)\\eta&quot;,&quot;id&quot;:&quot;DTOBQMUDAS&quot;}" data-component-name="LatexBlockToDOM"></div><p>once and then call the FFT algorithm. Then multiply the u-th output by</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\frac{e^{-\\alpha k_u}}{\\pi}&quot;,&quot;id&quot;:&quot;BBLOPFSCMQ&quot;}" data-component-name="LatexBlockToDOM"></div><p>to get the final call prices for each strike.</p><h3>Simpson&#8217;s rule</h3><p>The trapezoid rule has errors O(eta^2). To get accurate integration with larger eta, which, via the grid coupling constraint, means finer strike spacing, we replace the uniform weight eta with Simpson&#8217;s rule weights:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;w_j = \\frac{\\eta}{3}[3+(-1)^j + \\delta_{j-1}]&quot;,&quot;id&quot;:&quot;QISRMAXNIT&quot;}" data-component-name="LatexBlockToDOM"></div><p>where delta_{j-1} is the Kronecker delta, equal to 1 only at j=1. The error improves from O(eta^2) to O(eta^4), and the FFT structure is preserved since replacing eta with w_j just multiplies each term by a scalar before applying the FFT. </p><p>The final formula is:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;C_T(k_u) \\approx \\frac{e^{-\\alpha k_u}}{\\pi} \\sum_{j=1}^N e^{-i\\frac{2\\pi}{N}(j-1)(u-1)}e^{ibv_j}\\Psi_T(v_j)w_j&quot;,&quot;id&quot;:&quot;WFJZUPAPJI&quot;}" data-component-name="LatexBlockToDOM"></div><h3>The weakness of Carr-Madan</h3><p>The grid coupling constraint is the fundamental limitation; you cannot independently choose integration accuracy and strike grid density. Additionally, alpha requires model-specific tuning. Both issues are addressed by the methods that follow.</p><h3>Python Implementation</h3><p>We will be working with Heston in this article. Let&#8217;s first implement Monte Carlo pricing using Euler-Maruyama as a ground truth and for speed comparison:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;a66992d3-e5ef-4985-b813-befeef818b05&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">import numpy as np
from scipy.stats import norm
import time
import matplotlib.pyplot as plt
from scipy.integrate import quad</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;c5d4d1d7-40cb-42f0-a021-1b34a9b301a1&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">def heston_mc(S0, K, r, q, T, kappa, theta, eta, rho, v0,
              n_steps=200, n_paths=1_000_000, seed=42):
    rng = np.random.default_rng(seed)
    dt  = T / n_steps
    S   = np.full(n_paths, float(S0))
    v   = np.full(n_paths, float(v0))

    for _ in range(n_steps):
        Z1    = rng.standard_normal(n_paths)
        Z2    = rho * Z1 + np.sqrt(1 - rho**2) * rng.standard_normal(n_paths)
        v_pos = np.maximum(v, 0)
        S    *= np.exp((r - q - 0.5 * v_pos) * dt + np.sqrt(v_pos * dt) * Z1)
        v    += kappa * (theta - v_pos) * dt + eta * np.sqrt(v_pos * dt) * Z2

    return np.exp(-r * T) * np.mean(np.maximum(S - K, 0))</code></pre></div><p>Next, we implement the Heston Characteristic Function:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;a4c5f2a6-2c36-4c5e-bde2-1f82221b8af8&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">def heston_cf(omega, S0, r, q, T, kappa, theta, eta, rho, v0):
    x  = np.log(S0)
    xi = kappa - 1j * rho * eta * omega
    d  = np.sqrt(xi**2 + eta**2 * (omega**2 + 1j * omega))
    g  = (xi - d) / (xi + d)

    C = ((r - q) * 1j * omega * T
         + (kappa * theta / eta**2) * (
             (xi - d) * T - 2 * np.log((1 - g * np.exp(-d * T)) / (1 - g))
         ))
    D = ((xi - d) / eta**2) * (1 - np.exp(-d * T)) / (1 - g * np.exp(-d * T))

    return np.exp(C + D * v0 + 1j * omega * x)</code></pre></div><p>and finally, the FFT implementation of Carr-Madan using Simpson weights:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;cb192ef7-db7c-4705-b8d0-4097d8086561&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">def carr_madan_fft(S0, r, q, T, kappa, theta, eta, rho, v0,
                   alpha=1.5, N=4096, eta_grid=0.25):
    lam = 2 * np.pi / (N * eta_grid)
    b   = 0.5 * N * lam

    j   = np.arange(1, N + 1)
    v_j = eta_grid * (j - 1)

    cf  = lambda omega: heston_cf(omega, S0, r, q, T, kappa, theta, eta, rho, v0)

    psi = (np.exp(-r * T) * cf(v_j - (alpha + 1) * 1j)
           / (alpha**2 + alpha - v_j**2 + 1j * (2 * alpha + 1) * v_j))

    w   = (eta_grid / 3) * (3 + (-1)**j - (j == 1).astype(float))
    k_u = -b + lam * (np.arange(1, N + 1) - 1)

    x       = np.fft.fft(np.exp(1j * b * v_j) * psi * w)
    calls   = (np.exp(-alpha * k_u) / np.pi) * np.real(x)
    strikes = np.exp(k_u)

    return strikes, calls</code></pre></div><p>Let&#8217;s compare MC to Carr-Mada:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;195d5e69-4af9-4be8-89a2-e302adc71f73&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># &#9472;&#9472; parameters &#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;

params = dict(S0=100, r=0.05, q=0, T=1.0,
              kappa=2.0, theta=0.04, eta=0.3, rho=-0.7, v0=0.04)

strikes_to_price = np.arange(60, 141, 5, dtype=float)

# &#9472;&#9472; MC ground truth &#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;

t0 = time.perf_counter()
mc_prices = np.array([heston_mc(**params, K=K) for K in strikes_to_price])
mc_time   = time.perf_counter() - t0

# &#9472;&#9472; Carr-Madan &#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;

t0 = time.perf_counter()
cm_strikes, cm_calls = carr_madan_fft(**params)
cm_time = time.perf_counter() - t0
cm_prices = np.interp(strikes_to_price, cm_strikes, cm_calls)

# &#9472;&#9472; print results &#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;

print(f"{'Strike':&gt;8} {'MC':&gt;10} {'Carr-Madan':&gt;12} {'Error':&gt;10}")
print("-" * 44)
for K, mc, cm in zip(strikes_to_price, mc_prices, cm_prices):
    print(f"{K:&gt;8.0f} {mc:&gt;10.4f} {cm:&gt;12.4f} {abs(mc-cm):&gt;10.4f}")

print(f"\nMC time:          {mc_time:.2f}s  ({len(strikes_to_price)} strikes, 100k paths each)")
print(f"Carr-Madan time:  {cm_time*1000:.2f}ms (all strikes simultaneously)")

# &#9472;&#9472; plot &#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))

ax1.plot(strikes_to_price, mc_prices, 'o', label='Monte Carlo', color='steelblue')
ax1.plot(strikes_to_price, cm_prices, '-', label='Carr-Madan', color='tomato', linewidth=2)
ax1.set_xlabel('Strike')
ax1.set_ylabel('Call Price')
ax1.set_title('Heston Call Prices')
ax1.legend()
ax1.grid(True, alpha=0.3)

ax2.bar(['Monte Carlo\n(100k paths, 17 strikes)', 'Carr-Madan FFT\n(all strikes)'],
        [mc_time, cm_time],
        color=['steelblue', 'tomato'])
ax2.set_ylabel('Time (seconds)')
ax2.set_title('Computation Time')
ax2.grid(True, alpha=0.3, axis='y')

plt.tight_layout()
plt.show()</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;5a9f0d3e-1532-4113-a0e6-9c1c66619ff0&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">  Strike         MC   Carr-Madan      Error
--------------------------------------------
      60    43.0926      43.0487     0.0439
      65    38.4447      38.4019     0.0428
      70    33.8703      33.8281     0.0423
      75    29.4033      29.3614     0.0420
      80    25.0861      25.0447     0.0415
      85    20.9701      20.9298     0.0403
      90    17.1172      17.0758     0.0415
      95    13.5838      13.5438     0.0401
     100    10.4286      10.3950     0.0336
     105     7.7081       7.6798     0.0283
     110     5.4500       5.4306     0.0194
     115     3.6676       3.6572     0.0104
     120     2.3451       2.3334     0.0117
     125     1.4146       1.4061     0.0085
     130     0.8051       0.8002     0.0049
     135     0.4343       0.4309     0.0034
     140     0.2238       0.2206     0.0031

MC time:          6.46s  (17 strikes, 100k paths each)
Carr-Madan time:  1.05ms (all strikes simultaneously)</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZkZV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feeb4f2b6-52d3-4260-baf8-05767e585855_1189x390.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZkZV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feeb4f2b6-52d3-4260-baf8-05767e585855_1189x390.png 424w, https://substackcdn.com/image/fetch/$s_!ZkZV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feeb4f2b6-52d3-4260-baf8-05767e585855_1189x390.png 848w, https://substackcdn.com/image/fetch/$s_!ZkZV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feeb4f2b6-52d3-4260-baf8-05767e585855_1189x390.png 1272w, https://substackcdn.com/image/fetch/$s_!ZkZV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feeb4f2b6-52d3-4260-baf8-05767e585855_1189x390.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZkZV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feeb4f2b6-52d3-4260-baf8-05767e585855_1189x390.png" width="1189" height="390" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/eeb4f2b6-52d3-4260-baf8-05767e585855_1189x390.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:390,&quot;width&quot;:1189,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:45447,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/200941555?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feeb4f2b6-52d3-4260-baf8-05767e585855_1189x390.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ZkZV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feeb4f2b6-52d3-4260-baf8-05767e585855_1189x390.png 424w, https://substackcdn.com/image/fetch/$s_!ZkZV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feeb4f2b6-52d3-4260-baf8-05767e585855_1189x390.png 848w, https://substackcdn.com/image/fetch/$s_!ZkZV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feeb4f2b6-52d3-4260-baf8-05767e585855_1189x390.png 1272w, https://substackcdn.com/image/fetch/$s_!ZkZV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feeb4f2b6-52d3-4260-baf8-05767e585855_1189x390.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The results speak for themselves! Even at 100k paths, which isn&#8217;t all that much, and gives somewhat inaccurate results, running MC takes around 6.5 seconds, while Carr-Madan only takes a millisecond. But we can do even better!</p><div><hr></div><h1>Lewis</h1><p>Lewis (2001) reformulates option pricing as a complex contour integral. The result is a cleaner formula than Carr-Mada; no dampening parameter alpha to tune, and the strip condition is easily satisfied for essentially all models used in practice.</p><h3>The core idea</h3><p>The option price is a discounted expectation under Q (We are restating this since the paper has slightly different notation):</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;V(S_0) = e^{-rT}\\int_{-\\infty}^\\infty w(x) q_T(x)dx&quot;,&quot;id&quot;:&quot;OCTCTJPVDQ&quot;}" data-component-name="LatexBlockToDOM"></div><p>where x = log S_T, w(x) is the payoff function, and q_T(x) is the risk-neutral density of log S_T. This is an inner product of w and q_T. Parseval&#8217;s theorem says inner products are preserved under Fourier transformation:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\int_{-\\infty}^\\infty w(x)\\overline{q_T(x)}dx = \\frac{1}{2\\pi}\\int_{-\\infty}^\\infty \\hat{w}(\\xi)\\overline{\\hat{q_T}(\\xi)}d\\xi&quot;,&quot;id&quot;:&quot;MGSDTRIGSP&quot;}" data-component-name="LatexBlockToDOM"></div><p>Since q_T(x) is real, we have</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\overline{\\hat{q}_T(\\xi)} = \\hat{q}_T(-\\xi)=\\phi_T(-\\xi)&quot;,&quot;id&quot;:&quot;OXYMBWVFNT&quot;}" data-component-name="LatexBlockToDOM"></div><p>So:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;V(S_0) = \\frac{e^{-rT}}{2\\pi}\\int_{-\\infty}^\\infty \\hat{w}(\\xi) \\phi_T(-\\xi)d\\xi&quot;,&quot;id&quot;:&quot;GHCWDMTPKJ&quot;}" data-component-name="LatexBlockToDOM"></div><h3>The problem</h3><p>That formula looks clean, but there&#8217;s a catch. For a call, the payoff is </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;w(x) = (e^x - K)^+,&quot;,&quot;id&quot;:&quot;HBFBTMAQEC&quot;}" data-component-name="LatexBlockToDOM"></div><p>which grows like e^x as x &#8594; infty. Its ordinary Fourier transform diverges!</p><p>Carr-Madan&#8217;s fix was to multiply the payoff by a dampening factor before transforming. Lewis takes a cleaner route: allow the transform variable to be complex.</p><h3>Generalized Fourier Transform</h3><p>Let z = u+iv be a complex number. Define the generalized Fourier transform of the payoff:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\hat{w}(z) = \\int_{-\\infty}^\\infty e^{izx}w(x)dx&quot;,&quot;id&quot;:&quot;SYBKKUJWKU&quot;}" data-component-name="LatexBlockToDOM"></div><p>Now e^{izx} = e^{iux-vx}, and the factor e^{-vx} provides the decay that kills the growth of w(x), as long as v is large enough. For the call:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\hat{w}(z) = \\int_{\\ln K}^\\infty e^{izx}(e^x - K)dx&quot;,&quot;id&quot;:&quot;PQGUZQXMLF&quot;}" data-component-name="LatexBlockToDOM"></div><p>This does not converge unless Im(z) &gt; 1. With Im(z) &gt; 1 we have:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\hat{w}(z) = -\\frac{K^{iz+1}}{z^2-iz}, \\quad \\Im(z)>1&quot;,&quot;id&quot;:&quot;AUMTGOBUAR&quot;}" data-component-name="LatexBlockToDOM"></div><p>We call this area the <strong>strip of regularity </strong>for the call payoff:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathcal{S}_w = \\{z:\\Im(z)>1\\}&quot;,&quot;id&quot;:&quot;WYILRLHIMI&quot;}" data-component-name="LatexBlockToDOM"></div><p>You can refer to the following table from the paper for other options:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!R0m2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1620642-a7f6-4282-9626-ecdb41441984_791x603.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!R0m2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1620642-a7f6-4282-9626-ecdb41441984_791x603.png 424w, https://substackcdn.com/image/fetch/$s_!R0m2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1620642-a7f6-4282-9626-ecdb41441984_791x603.png 848w, https://substackcdn.com/image/fetch/$s_!R0m2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1620642-a7f6-4282-9626-ecdb41441984_791x603.png 1272w, https://substackcdn.com/image/fetch/$s_!R0m2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1620642-a7f6-4282-9626-ecdb41441984_791x603.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!R0m2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1620642-a7f6-4282-9626-ecdb41441984_791x603.png" width="791" height="603" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f1620642-a7f6-4282-9626-ecdb41441984_791x603.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:603,&quot;width&quot;:791,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:111090,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/200941555?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1620642-a7f6-4282-9626-ecdb41441984_791x603.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!R0m2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1620642-a7f6-4282-9626-ecdb41441984_791x603.png 424w, https://substackcdn.com/image/fetch/$s_!R0m2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1620642-a7f6-4282-9626-ecdb41441984_791x603.png 848w, https://substackcdn.com/image/fetch/$s_!R0m2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1620642-a7f6-4282-9626-ecdb41441984_791x603.png 1272w, https://substackcdn.com/image/fetch/$s_!R0m2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1620642-a7f6-4282-9626-ecdb41441984_791x603.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The characteristic function has its own regularity strip. For the characteristic function of X_T to exist, we need</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathbb{E}[e^{-vX_T}]<\\infty.&quot;,&quot;id&quot;:&quot;VUQIZMGIDA&quot;}" data-component-name="LatexBlockToDOM"></div><p>The set of valid complex v with this property forms the strip S_X. </p><p>Define the <strong>reflected strip</strong></p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathcal{S}_X^* = \\{z:-z\\in \\mathcal{S}_X\\}.&quot;,&quot;id&quot;:&quot;ZCRTHHDZPD&quot;}" data-component-name="LatexBlockToDOM"></div><p>This is where phi_T(-z) is regular, which is what appears in the pricing formula.</p><h3>Shifting the contour</h3><p>By Cauchy&#8217;s theorem, the integration contour may be shifted to any horizontal line inside the <strong>common strip of regularity</strong>:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\int_{-\\infty}^\\infty \\hat{w}(\\xi)\\phi_T(-\\xi)d\\xi = \\int_{iv-\\infty}^{iv+\\infty} \\hat{w}(\\xi)\\phi_T(-\\xi)d\\xi, \\quad v \\in \\mathcal{S}_V = \\mathcal{S}_w \\cap \\mathcal{S}_X^*&quot;,&quot;id&quot;:&quot;UFCINKLFQP&quot;}" data-component-name="LatexBlockToDOM"></div><h3>The Lewis Formula</h3><p>The option price finally becomes:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;V(S_0) = \\frac{e^{-rT}}{2\\pi}\\int_{iv-\\infty}^{iv+\\infty}e^{-izY}\\phi_T(-z)\\hat{w}(z)dz&quot;,&quot;id&quot;:&quot;NJFCFELLOC&quot;}" data-component-name="LatexBlockToDOM"></div><p>where v = Im(z) in S_V and Y = ln S_0 + (r-q)T is the log forward price, and phi denotes the characteristic function of the centred log-return X_T = log S_T - Y.</p><h3>Call Pricing Formula</h3><p>Substituting the call payoff transform hat{w} from above:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;C(S_0) = \\frac{e^{-rT}}{2\\pi} \\int_{iv-\\infty}^{iv+\\infty} e^{-izY}\\phi_T(-z)\\cdot(-\\frac{K^{iz+1}}{z^2-iz})dz, \\quad v\\in(1,b)&quot;,&quot;id&quot;:&quot;EEGPHVVLDV&quot;}" data-component-name="LatexBlockToDOM"></div><p>where b is some model-dependent upper bound below which the characteristic function stays regular. Lewi&#8217;s preferred contour is v=1/2, obtained by shifting the contour from (1,b) down to (0,1) via the residue theorem and picking up the pole at z=i. That gives</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;C(S_0) = S_0 e^{-qT}-\\frac{\\sqrt{S_0K}e^{-(r+q)T/2}}{\\pi} \\int_0^\\infty\\Re[e^{iuk}\\phi_T(u-\\frac{i}{2})]\\frac{du}{u^2+\\frac{1}{4}},&quot;,&quot;id&quot;:&quot;SLQGFZLAFW&quot;}" data-component-name="LatexBlockToDOM"></div><p>where k = ln(S_0/K) + (r-q)T is the log-moneyness. The contour v=1/2 sits symmetrically between the poles at z=0 and z=i, and requires only </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathbb{E}^\\mathbb{Q}[S_T^{1/2}] < \\infty,&quot;,&quot;id&quot;:&quot;POPDPOKOXX&quot;}" data-component-name="LatexBlockToDOM"></div><p>satisfies by practically every standard model, and is a much weaker requirement than </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathbb{E}^\\mathbb{Q}[S_T^{\\alpha+1}] < \\infty,&quot;,&quot;id&quot;:&quot;LKZJNRIBVV&quot;}" data-component-name="LatexBlockToDOM"></div><p>that Carr-Madan needs for alpha &gt; 0.</p><h3>Python Implementation</h3><p>Lewis uses the characteristic function of X_T:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;5843724a-54d3-4880-9606-988cf7f593df&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">def heston_cf_xt(omega, S0, r, q, T, kappa, theta, eta, rho, v0):
    """CF of X_T = log(S_T/S_0) - (r-q)T under Heston."""
    xi = kappa - 1j * rho * eta * omega
    d  = np.sqrt(xi**2 + eta**2 * (omega**2 + 1j * omega))
    g  = (xi - d) / (xi + d)

    C = (kappa * theta / eta**2) * (
            (xi - d) * T - 2 * np.log((1 - g * np.exp(-d * T)) / (1 - g))
        )
    D = ((xi - d) / eta**2) * (1 - np.exp(-d * T)) / (1 - g * np.exp(-d * T))

    # no (r-q) drift term since X_T is already centered
    return np.exp(C + D * v0 - 0.5 * 1j * omega * eta**2 * 0)</code></pre></div><p>Now since Lewis doesn&#8217;t use FFT by design, we have to compute strikes one by one using the contour integral, or we are smart and vectorize:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;2c465e16-6775-499a-9414-a6d4bc8b6f50&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">def lewis_calls_vectorized(S0, strikes, r, q, T, kappa, theta, eta, rho, v0,
                           N=4096, eta_grid=0.25):
    u_j = eta_grid * np.arange(0, N)
    
    # Simpson weights
    w = np.ones(N) * 2
    w[1::2] = 4
    w[0] = w[-1] = 1
    w *= eta_grid / 3

    phi = heston_cf_xt(u_j - 0.5j, S0, r, q, T, kappa, theta, eta, rho, v0)
    phi /= (u_j**2 + 0.25)

    # k for each strike: shape (n_strikes,)
    k = np.log(S0 / strikes) + (r - q) * T

    # outer product: shape (n_strikes, N)
    phase = np.exp(1j * np.outer(k, u_j))

    I = np.real(phase * phi[np.newaxis, :]) @ w / np.pi

    return S0 * np.exp(-q * T) - np.sqrt(S0 * strikes) * np.exp(-(r + q) * T / 2) * I</code></pre></div><p>And the comparison:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;0fa746e2-f90c-4d91-9beb-263da03eba3b&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">t0 = time.perf_counter()
lw_prices = lewis_calls_vectorized(strikes=strikes_to_price, **params)
lw_time = time.perf_counter() - t0

print(f"{'Strike':&gt;8} {'MC':&gt;10} {'Carr-Madan':&gt;12} {'Lewis':&gt;10} "
      f"{'CM Err':&gt;10} {'LW Err':&gt;10}")
print("-" * 64)
for K, mc, cm, lw in zip(strikes_to_price, mc_prices, cm_prices, lw_prices):
    print(f"{K:&gt;8.0f} {mc:&gt;10.4f} {cm:&gt;12.4f} {lw:&gt;10.4f} "
          f"{abs(mc-cm):&gt;10.4f} {abs(mc-lw):&gt;10.4f}")

print(f"\nMC time:          {mc_time:.2f}s")
print(f"Carr-Madan time:  {cm_time*1000:.2f}ms")
print(f"Lewis time:       {lw_time*1000:.2f}ms")

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))

ax1.plot(strikes_to_price, mc_prices, 'o', label='Monte Carlo', color='steelblue')
ax1.plot(strikes_to_price, cm_prices, '-', label='Carr-Madan', color='tomato', linewidth=2)
ax1.plot(strikes_to_price, lw_prices, '--', label='Lewis', color='seagreen', linewidth=2)
ax1.set_xlabel('Strike')
ax1.set_ylabel('Call Price')
ax1.set_title('Heston Call Prices')
ax1.legend()
ax1.grid(True, alpha=0.3)

ax2.bar(['Carr-Madan\nFFT', 'Lewis\nVectorized'],
        [cm_time, lw_time],
        color=['tomato', 'seagreen'])
ax2.set_ylabel('Time (seconds)')
ax2.set_title('Computation Time (excl. Monte Carlo)')
ax2.grid(True, alpha=0.3, axis='y')

plt.tight_layout()
plt.show()</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;08813a5c-958c-48c2-b4e9-0c9bce873e9d&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">  Strike         MC   Carr-Madan      Lewis     CM Err     LW Err
----------------------------------------------------------------
      60    43.0926      43.0487    43.1459     0.0439     0.0533
      65    38.4447      38.4019    38.5020     0.0428     0.0573
      70    33.8703      33.8281    33.9311     0.0423     0.0608
      75    29.4033      29.3614    29.4673     0.0420     0.0640
      80    25.0861      25.0447    25.1536     0.0415     0.0674
      85    20.9701      20.9298    21.0417     0.0403     0.0716
      90    17.1172      17.0758    17.1902     0.0415     0.0730
      95    13.5838      13.5438    13.6612     0.0401     0.0774
     100    10.4286      10.3950    10.5150     0.0336     0.0864
     105     7.7081       7.6798     7.8025     0.0283     0.0944
     110     5.4500       5.4306     5.5570     0.0194     0.1070
     115     3.6676       3.6572     3.7858     0.0104     0.1182
     120     2.3451       2.3334     2.4652     0.0117     0.1201
     125     1.4146       1.4061     1.5412     0.0085     0.1266
     130     0.8051       0.8002     0.9381     0.0049     0.1329
     135     0.4343       0.4309     0.5717     0.0034     0.1375
     140     0.2238       0.2206     0.3646     0.0031     0.1409

MC time:          8.09s
Carr-Madan time:  1.18ms
Lewis time:       2.49ms</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lyUP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1284676-9619-4d5f-8883-7cc73998e485_1189x390.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lyUP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1284676-9619-4d5f-8883-7cc73998e485_1189x390.png 424w, https://substackcdn.com/image/fetch/$s_!lyUP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1284676-9619-4d5f-8883-7cc73998e485_1189x390.png 848w, https://substackcdn.com/image/fetch/$s_!lyUP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1284676-9619-4d5f-8883-7cc73998e485_1189x390.png 1272w, https://substackcdn.com/image/fetch/$s_!lyUP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1284676-9619-4d5f-8883-7cc73998e485_1189x390.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lyUP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1284676-9619-4d5f-8883-7cc73998e485_1189x390.png" width="1189" height="390" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f1284676-9619-4d5f-8883-7cc73998e485_1189x390.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:390,&quot;width&quot;:1189,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:50854,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/200941555?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1284676-9619-4d5f-8883-7cc73998e485_1189x390.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!lyUP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1284676-9619-4d5f-8883-7cc73998e485_1189x390.png 424w, https://substackcdn.com/image/fetch/$s_!lyUP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1284676-9619-4d5f-8883-7cc73998e485_1189x390.png 848w, https://substackcdn.com/image/fetch/$s_!lyUP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1284676-9619-4d5f-8883-7cc73998e485_1189x390.png 1272w, https://substackcdn.com/image/fetch/$s_!lyUP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1284676-9619-4d5f-8883-7cc73998e485_1189x390.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>As you can see, when using the same N and eta as with Carr-Madan, Lewis starts diverging pretty quickly and is still over twice as slow. If we increase N and reduce eta, we are quickly multiple times slower than Carr-Madan when pricing many strikes at once. On the other hand, we get rid of the dampening parameter alpha, which can cause real problems.</p><p>Let&#8217;s finally look at our method of choice, which performs better than both Lewis and Carr-Madan.</p><div><hr></div><h1>The COS Method</h1><p>Both Carr-Madan and Lewis price options by evaluating a Fourier integral numerically. The integrand is oscillatory, which is expensive to integrate accurately with equally spaced quadrature.</p><p>The COS method (2008) takes a different route. Instead of integrating the characteristic function directly, it expands the risk-neutral density in a cosine series and reads the series coefficients directly off the characteristic function, with those coefficients often being available analytically.</p><h3>Fourier-Cosine Series Expansion</h3><p>Starting from risk-neutral pricing (once again, slightly different notation!):</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;v(x, 0) = e^{-rT}\\int_{-\\infty}^\\infty v(y,T)f(y|x)dy&quot;,&quot;id&quot;:&quot;CLWHVYRKUS&quot;}" data-component-name="LatexBlockToDOM"></div><p>where x=ln(S_0/K), y = ln(S_T/K), v(y,T) is the payoff, and f(y|x) is the risk-neutral transition density of the log-return.</p><p>We truncate to a finite interval [a,b]:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;v(x, 0) \\approx e^{-rT}\\int_{a}^b v(y,T)f(y|x)dy&quot;,&quot;id&quot;:&quot;ACLKDNKSRH&quot;}" data-component-name="LatexBlockToDOM"></div><p>Now expand f(y|x) in a cosine series on [a,b]:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;f(y|x) \\approx \\sum_{k=0}^{N-1}{}' A_k(x) \\cos (k\\pi \\frac{y-a}{b-a})&quot;,&quot;id&quot;:&quot;PFKUCGLBAR&quot;}" data-component-name="LatexBlockToDOM"></div><p>where the &#8216; in the sum means the k=0 term is weighted by 1/2, and the cosine coefficients are:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;A_k(x) = \\frac{2}{b-a}\\int_a^b f(y|x) \\cos(k\\pi \\frac{y-a}{b-a})dy&quot;,&quot;id&quot;:&quot;TTGKZJROZC&quot;}" data-component-name="LatexBlockToDOM"></div><p>Substituting into the pricing integral and swapping sum and integral (which we can do thanks to Fubini):</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;v(x,0) \\approx \\frac{b-a}{2}e^{-rT}\\sum_{k=0}^{N-1}{}'A_k(x)V_k&quot;,&quot;id&quot;:&quot;PRFWDTHYJE&quot;}" data-component-name="LatexBlockToDOM"></div><p>where:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;V_k = \\frac{2}{b-a}\\int_a^bv(y,T)\\cos(k\\pi \\frac{y-a}{b-a})dy&quot;,&quot;id&quot;:&quot;EWGJYUFJWI&quot;}" data-component-name="LatexBlockToDOM"></div><p>Note that the V_k are the cosine series coefficients of v(y,T) in y. Thus we have transformed the product of two real functions, f(y|x) and v(y,T), to that of their Fourier-cosine series coefficients.</p><h3>Coefficients from the characteristic function</h3><p>The density f(y|x) is unknown, that&#8217;s the whole reason we use Fourier methods in the first place. Comparing the definition of A_k(x) with the characteristic function phi_T(w), one finds that:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;A_k(x) = \\frac{2}{b-a}\\Re[\\phi_1(\\frac{k\\pi}{b-a})\\exp(-i\\frac{k\\pi a}{b-a})]&quot;,&quot;id&quot;:&quot;FMEGWWNYZP&quot;}" data-component-name="LatexBlockToDOM"></div><p>where phi_1 is the characteristic function computed over the truncated range [a,b]. Since [a,b] was chosen to capture essentially all the density mass, phi_1 is approx phi and so:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;A_k(x) \\approx F_k = \\frac{2}{b-a}\\Re[\\phi_T(\\frac{k\\pi}{b-a})\\exp(-i\\frac{k\\pi a}{b-a})]&quot;,&quot;id&quot;:&quot;IJMPNUCBYW&quot;}" data-component-name="LatexBlockToDOM"></div><h3>The COS Formula</h3><p>Finally, replacing A_k by F_k in the formula for V(x, t_0), we obtain:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;v(x, 0) \\approx e^{-rT}\\sum_{k=0}^{N-1}{}'\\Re[\\phi_T(\\frac{k\\pi}{b-a})e^{-ik\\pi a / (b-a)}]V_k&quot;,&quot;id&quot;:&quot;UTQLWZJVAU&quot;}" data-component-name="LatexBlockToDOM"></div><p>This is the COS formula. </p><h3>Payoff coefficients for calls and puts</h3><p>For a call, v(y,T) = K(e^y-1)^+, the integration domain reduces to [0,b] since the payoff is zero for y &lt; 0. The coefficients are:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;V_k^\\text{call} = \\frac{2}{b-a}K(\\chi_k(0,b)-\\psi_k(0,b))&quot;,&quot;id&quot;:&quot;DNZEKFDVOK&quot;}" data-component-name="LatexBlockToDOM"></div><p>where chi and psi have closed forms:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UMVO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef887e43-ad0f-49d1-8734-eb7c19f18398_698x307.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UMVO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef887e43-ad0f-49d1-8734-eb7c19f18398_698x307.png 424w, https://substackcdn.com/image/fetch/$s_!UMVO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef887e43-ad0f-49d1-8734-eb7c19f18398_698x307.png 848w, https://substackcdn.com/image/fetch/$s_!UMVO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef887e43-ad0f-49d1-8734-eb7c19f18398_698x307.png 1272w, https://substackcdn.com/image/fetch/$s_!UMVO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef887e43-ad0f-49d1-8734-eb7c19f18398_698x307.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UMVO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef887e43-ad0f-49d1-8734-eb7c19f18398_698x307.png" width="698" height="307" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ef887e43-ad0f-49d1-8734-eb7c19f18398_698x307.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:307,&quot;width&quot;:698,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:42993,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/200941555?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef887e43-ad0f-49d1-8734-eb7c19f18398_698x307.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!UMVO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef887e43-ad0f-49d1-8734-eb7c19f18398_698x307.png 424w, https://substackcdn.com/image/fetch/$s_!UMVO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef887e43-ad0f-49d1-8734-eb7c19f18398_698x307.png 848w, https://substackcdn.com/image/fetch/$s_!UMVO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef887e43-ad0f-49d1-8734-eb7c19f18398_698x307.png 1272w, https://substackcdn.com/image/fetch/$s_!UMVO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef887e43-ad0f-49d1-8734-eb7c19f18398_698x307.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">I couldn&#8217;t be bothered typing this out in LaTeX</figcaption></figure></div><p>For a put the integration domain is [a,0], and</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;V_k^\\text{put} = \\frac{2}{b-a}K(-\\chi_k(a,0)+\\psi_k(a,0))&quot;,&quot;id&quot;:&quot;ZSONBSLYYR&quot;}" data-component-name="LatexBlockToDOM"></div><p>In practice, you can price puts or calls, and recover the other via put-call parity</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;C = P + S_0e^{-qT}-Ke^{-rT}.&quot;,&quot;id&quot;:&quot;NGKHMRMGXD&quot;}" data-component-name="LatexBlockToDOM"></div><h3>Truncation Range</h3><p>The interval [a,b] must contain enough of the density without being so wide that the cosine approximation needs excessive terms to resolve the tails. Fang &amp; Oosterlee propose using cumulants of ln(S_T/K):</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;[a,b] = [c_1-L\\sqrt{c_2+\\sqrt{c_4}}, c_1+L\\sqrt{c_2+\\sqrt{c_4}}], \\quad L=10&quot;,&quot;id&quot;:&quot;XGYUFZMPWO&quot;}" data-component-name="LatexBlockToDOM"></div><p>where c_1, c_2, c_4 are the first, second and fourth cumulants of ln(S_T/K). Including c_4 matters for short maturities and fat-tailed processes where the density is sharply peaked. </p><p>You can additionally also include a c_6 term as well for extremely short maturities, but the sixth cumulant can be difficult to derive for many models. You can also go the other direction and only include the c_1 and c_2 terms.</p><h3>Benefits of the COS method</h3><p>For Carr-Madan and Lewis, accuracy is limited by how well a trapezoidal or Simpson sum approximates a slowly decaying oscillatory integral. The COS method avoids this entirely. For smooth densities like GBM, Heston, and many L&#233;vy processes at moderate maturities, the density is C^{infty} on [a,b] and the cosine coefficients decay exponentially, yielding exponential convergence.</p><p>The computational complexity is O(N) for a single strike. For a vector of strikes, the F_k are the same across all strikes, and the V_k differ only through the x-dependent phase; pricing M strikes simultaneously costs O(MN) via matrix-vector multiplication. </p><h3>Python Implementation</h3><p>We need the first and second cumulants of log(S_T/K) under Heston:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;d4215513-af76-4e8b-8076-70a5d9f3f265&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">def heston_cumulants(r, q, T, kappa, theta, eta, rho, v0):
    """First and second cumulants of log(S_T/K) under Heston."""
    c1 = (r - q) * T + (1 - np.exp(-kappa * T)) * (theta - v0) / (2 * kappa) - 0.5 * theta * T

    c2 = (1 / (8 * kappa**3)) * (
        eta * T * kappa * np.exp(-kappa * T) * (v0 - theta) * (8 * kappa * rho - 4 * eta)
        + kappa * rho * eta * (1 - np.exp(-kappa * T)) * (16 * theta - 8 * v0)
        + 2 * theta * kappa * T * (-4 * kappa * rho * eta + eta**2 + 4 * kappa**2)
        + eta**2 * ((theta - 2 * v0) * np.exp(-2 * kappa * T)
                    + theta * (6 * np.exp(-kappa * T) - 7) + 2 * v0)
        + 8 * kappa**2 * (v0 - theta) * (1 - np.exp(-kappa * T))
    )

    return c1, c2</code></pre></div><p>Fast vectorized implementation of the COS method:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;dee4a909-ad20-4743-aec4-964bc9dffbcc&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">def cos_calls(S0, strikes, r, q, T, kappa, theta, eta, rho, v0, N=128, L=12):
    c1, c2 = heston_cumulants(r, q, T, kappa, theta, eta, rho, v0)
    a = c1 - L * np.sqrt(abs(c2))
    b = c1 + L * np.sqrt(abs(c2))

    k     = np.arange(N)
    omega = k * np.pi / (b - a)

    def varphi(omega):
        xi = kappa - 1j * rho * eta * omega
        d  = np.sqrt(xi**2 + eta**2 * (omega**2 + 1j * omega))
        g  = (xi - d) / (xi + d)
        C  = ((r - q) * 1j * omega * T
              + (kappa * theta / eta**2) * (
                  (xi - d) * T - 2 * np.log((1 - g * np.exp(-d * T)) / (1 - g))
              ))
        D  = ((xi - d) / eta**2) * (1 - np.exp(-d * T)) / (1 - g * np.exp(-d * T))
        return np.exp(C + D * v0)

    def chi(c, d):
        kpi = np.where(k != 0, omega, 1.0)
        val = (np.cos(kpi * (d - a)) * np.exp(d)
             - np.cos(kpi * (c - a)) * np.exp(c)
             + kpi * np.sin(kpi * (d - a)) * np.exp(d)
             - kpi * np.sin(kpi * (c - a)) * np.exp(c)) / (1 + kpi**2)
        val[0] = np.exp(d) - np.exp(c)
        return val

    def psi(c, d):
        val      = np.empty(N)
        val[0]   = d - c
        val[1:]  = (b - a) / (k[1:] * np.pi) * (
                       np.sin(omega[1:] * (d - a)) - np.sin(omega[1:] * (c - a))
                   )
        return val

    # precompute strike-independent quantities
    basis    = varphi(omega) * np.exp(-1j * omega * a)  # vphi * e^{-i*omega*a}
    A        = np.real(basis)
    B        = np.imag(basis)
    Uk       = (2 / (b - a)) * (-chi(a, 0) + psi(a, 0))

    # cache constants
    disc     = np.exp(-r * T)
    fwd_S0   = S0 * np.exp(-q * T)
    disc_K   = np.exp(-r * T)

    # vectorize over strikes
    x        = np.log(S0 / strikes)                    # shape (M,)
    theta_mx = np.outer(x, omega)                      # shape (M, N)
    F        = A * np.cos(theta_mx) - B * np.sin(theta_mx)  # shape (M, N)
    F[:, 0] *= 0.5

    puts  = disc * strikes * (F @ Uk)
    calls = puts + fwd_S0 - strikes * disc_K
    return calls</code></pre></div><p>And last but not least, the comparison code:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;68675c02-8d02-45ef-9af8-88b823d74399&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">t0 = time.perf_counter()
cos_prices = cos_calls(strikes=strikes_to_price, **params)
cos_time = time.perf_counter() - t0

print(f"{'Strike':&gt;8} {'MC':&gt;10} {'Carr-Madan':&gt;12} {'Lewis':&gt;10} {'COS':&gt;10} "
      f"{'CM Err':&gt;10} {'LW Err':&gt;10} {'COS Err':&gt;10}")
print("-" * 84)
for K, mc, cm, lw, cos in zip(strikes_to_price, mc_prices, cm_prices, lw_prices, cos_prices):
    print(f"{K:&gt;8.0f} {mc:&gt;10.4f} {cm:&gt;12.4f} {lw:&gt;10.4f} {cos:&gt;10.4f} "
          f"{abs(mc-cm):&gt;10.4f} {abs(mc-lw):&gt;10.4f} {abs(mc-cos):&gt;10.4f}")

print(f"\nMC time:          {mc_time:.2f}s")
print(f"Carr-Madan time:  {cm_time*1000:.2f}ms")
print(f"Lewis time:       {lw_time*1000:.2f}ms")
print(f"COS time:         {cos_time*1000:.2f}ms")

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))

ax1.plot(strikes_to_price, mc_prices, 'o', label='Monte Carlo', color='steelblue')
ax1.plot(strikes_to_price, cm_prices, '-', label='Carr-Madan', color='tomato', linewidth=2)
ax1.plot(strikes_to_price, lw_prices, '--', label='Lewis', color='seagreen', linewidth=2)
ax1.plot(strikes_to_price, cos_prices, ':', label='COS', color='purple', linewidth=2)
ax1.set_xlabel('Strike')
ax1.set_ylabel('Call Price')
ax1.set_title('Heston Call Prices')
ax1.legend()
ax1.grid(True, alpha=0.3)

ax2.bar(['Carr-Madan\nFFT', 'Lewis\nVectorized', 'COS'],
        [cm_time, lw_time, cos_time],
        color=['tomato', 'seagreen', 'purple'])
ax2.set_ylabel('Time (seconds)')
ax2.set_title('Computation Time (excl. Monte Carlo)')
ax2.grid(True, alpha=0.3, axis='y')

plt.tight_layout()
plt.show()</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;214a9648-9ab2-49f3-8201-a2d418c1b1de&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">  Strike         MC   Carr-Madan      Lewis        COS     CM Err     LW Err    COS Err
------------------------------------------------------------------------------------
      60    43.0926      43.0487    43.1459    43.0487     0.0439     0.0533     0.0439
      65    38.4447      38.4019    38.5020    38.4019     0.0428     0.0573     0.0428
      70    33.8703      33.8281    33.9311    33.8280     0.0423     0.0608     0.0424
      75    29.4033      29.3614    29.4673    29.3612     0.0420     0.0640     0.0421
      80    25.0861      25.0447    25.1536    25.0446     0.0415     0.0674     0.0416
      85    20.9701      20.9298    21.0417    20.9297     0.0403     0.0716     0.0403
      90    17.1172      17.0758    17.1902    17.0753     0.0415     0.0730     0.0419
      95    13.5838      13.5438    13.6612    13.5434     0.0401     0.0774     0.0404
     100    10.4286      10.3950    10.5150    10.3942     0.0336     0.0864     0.0344
     105     7.7081       7.6798     7.8025     7.6788     0.0283     0.0944     0.0293
     110     5.4500       5.4306     5.5570     5.4303     0.0194     0.1070     0.0197
     115     3.6676       3.6572     3.7858     3.6562     0.0104     0.1182     0.0114
     120     2.3451       2.3334     2.4652     2.3326     0.0117     0.1201     0.0125
     125     1.4146       1.4061     1.5412     1.4057     0.0085     0.1266     0.0089
     130     0.8051       0.8002     0.9381     0.7996     0.0049     0.1329     0.0055
     135     0.4343       0.4309     0.5717     0.4303     0.0034     0.1375     0.0039
     140     0.2238       0.2206     0.3646     0.2203     0.0031     0.1409     0.0035

MC time:          8.09s
Carr-Madan time:  1.18ms
Lewis time:       2.49ms
COS time:         0.34ms</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1H6m!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4db5601f-c43b-4d49-9c77-24bb132dc734_1189x390.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1H6m!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4db5601f-c43b-4d49-9c77-24bb132dc734_1189x390.png 424w, https://substackcdn.com/image/fetch/$s_!1H6m!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4db5601f-c43b-4d49-9c77-24bb132dc734_1189x390.png 848w, https://substackcdn.com/image/fetch/$s_!1H6m!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4db5601f-c43b-4d49-9c77-24bb132dc734_1189x390.png 1272w, https://substackcdn.com/image/fetch/$s_!1H6m!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4db5601f-c43b-4d49-9c77-24bb132dc734_1189x390.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1H6m!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4db5601f-c43b-4d49-9c77-24bb132dc734_1189x390.png" width="1189" height="390" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4db5601f-c43b-4d49-9c77-24bb132dc734_1189x390.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:390,&quot;width&quot;:1189,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:52582,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/200941555?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4db5601f-c43b-4d49-9c77-24bb132dc734_1189x390.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!1H6m!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4db5601f-c43b-4d49-9c77-24bb132dc734_1189x390.png 424w, https://substackcdn.com/image/fetch/$s_!1H6m!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4db5601f-c43b-4d49-9c77-24bb132dc734_1189x390.png 848w, https://substackcdn.com/image/fetch/$s_!1H6m!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4db5601f-c43b-4d49-9c77-24bb132dc734_1189x390.png 1272w, https://substackcdn.com/image/fetch/$s_!1H6m!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4db5601f-c43b-4d49-9c77-24bb132dc734_1189x390.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Awesome! We are more than 3 times faster than Carr-Madan, while getting rid of annoying parameters and gaining exponential convergence!</p><p>The method naturally vectorizes into dense linear algebra operations, meaning you could still make this way way faster if you optimized it properly.</p><div><hr></div><h1>Conclusion</h1><p>Apologies for the delay since the last article! This one took a little longer than I expected since I had to verify all the math, and turn 3 papers into one article instead of the usual one paper.</p><p>I hope you enjoyed this rather math-heavy article anyway! I plan on covering more options content soon.</p><div><hr></div><h3>Other Articles You Would Enjoy</h3><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;3c0c515b-2295-454b-94e2-955f74f55fd4&quot;,&quot;caption&quot;:&quot;The volatility smile is of great importance to all options traders. Market makers use it to figure out where to quote and volatility traders use it to figure out where volatility will go.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;How to Trade the Volatility Smile&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:128680675,&quot;name&quot;:&quot;Vertox&quot;,&quot;bio&quot;:&quot;Quantitative Researcher in Digital Asset Markets | Market Making | Statistical Arbitrage | Options &quot;,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!HGUA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bf3fd86-d46a-4caa-969a-d80059b72cb9_128x128.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2025-06-29T21:34:11.716Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!qS_y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F080572fd-2897-477b-8e1b-35abe0dc2808_817x690.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.vertoxquant.com/p/how-to-trade-the-volatility-smile&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:166974509,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:37,&quot;comment_count&quot;:0,&quot;publication_id&quot;:1726874,&quot;publication_name&quot;:&quot;VertoxQuant&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!ufaQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb77b39-424b-4665-b2a7-7db519ff9e11_128x128.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;601e844f-3c5d-4c3d-bdf7-ac8f385f710b&quot;,&quot;caption&quot;:&quot;The crypto options market has been growing in popularity for years now, yet it&#8217;s still an unexplored territory for the vast majority of crypto traders.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;An Introduction to Option Market Making&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:128680675,&quot;name&quot;:&quot;Vertox&quot;,&quot;bio&quot;:&quot;Quantitative Researcher in Digital Asset Markets | Market Making | Statistical Arbitrage | Options &quot;,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!HGUA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bf3fd86-d46a-4caa-969a-d80059b72cb9_128x128.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2025-09-19T19:51:26.703Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!s2Nn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4a2ee61-3f69-4af2-a59b-fcad47566910_1590x1181.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.vertoxquant.com/p/introduction-to-option-market-making&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:171482530,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:24,&quot;comment_count&quot;:0,&quot;publication_id&quot;:1726874,&quot;publication_name&quot;:&quot;VertoxQuant&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!ufaQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb77b39-424b-4665-b2a7-7db519ff9e11_128x128.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;15c1bcca-1815-4f14-90f2-5be1d8189dcf&quot;,&quot;caption&quot;:&quot;In the previous article, we talked about how you can figure out the fair price of a polymarket bet using the options market of the underlying.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Pricing Illiquid Options Using Proxy Volatility Surfaces&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:128680675,&quot;name&quot;:&quot;Vertox&quot;,&quot;bio&quot;:&quot;Quantitative Researcher in Digital Asset Markets | Market Making | Statistical Arbitrage | Options &quot;,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!HGUA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bf3fd86-d46a-4caa-969a-d80059b72cb9_128x128.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2025-11-24T15:22:01.576Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!4QV3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdafc2860-f4ed-4f90-8d4f-2e445bc10721_1189x790.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.vertoxquant.com/p/pricing-illiquid-options-using-proxy&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:179804020,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:10,&quot;comment_count&quot;:0,&quot;publication_id&quot;:1726874,&quot;publication_name&quot;:&quot;VertoxQuant&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!ufaQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb77b39-424b-4665-b2a7-7db519ff9e11_128x128.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div><hr></div><h3><strong>Quant Corner</strong></h3><p><strong>Join Quant Corner</strong>, a community that actually <em>does things</em>. Tournaments, live Q&amp;As, open discussions, and the best place to shape what gets built next.</p><p>Join here: <a href="https://discord.gg/X7TsxKNbXg">https://discord.gg/X7TsxKNbXg</a></p>]]></content:encoded></item><item><title><![CDATA[Queue Position Estimation For Market Making]]></title><description><![CDATA[And testing it live]]></description><link>https://www.vertoxquant.com/p/queue-position-estimation</link><guid isPermaLink="false">https://www.vertoxquant.com/p/queue-position-estimation</guid><dc:creator><![CDATA[Vertox]]></dc:creator><pubDate>Fri, 29 May 2026 00:32:32 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/8a330681-73ed-4b9d-9af0-4174b06d5a3f_1197x665.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Estimating queue position is one of those things everyone talks about, but there isn&#8217;t much good literature on it. Which makes sense, it&#8217;s mostly market maker knowledge that they&#8217;d want to keep to themself! </p><p>The problem is straightforward: When you post a limit order, you know your price and your size, but you don&#8217;t know where you actually sit in the queue and how much volume is ahead of you before you get filled. An order at the front of a 10 BTC queue has a completely different fill probability than one at the back of it.</p><p>There is one particular blog post by Rigtop (2013) that proposed splitting observed volume changes proportionally between ahead and behind. It works as a heuristic, but it has a problem: it treats cancellations as events where some volume gets cancelled ahead of you and some behind, but in reality, each cancellation is either fully ahead of you or fully behind you. This means it also only gives you a point estimate of where in the queue you are, with no measure of uncertainty.</p><p>We do something more powerful. We maintain a distribution over all possible queue positions using a particle filter, which gives us a whole distribution of where we likely are in the queue. </p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;79e71126-030d-4c83-aba9-7c776c5422e3&quot;,&quot;duration&quot;:null}"></div><p>We derive the framework from scratch, implement it live on Bybit, and show the particle distribution evolving live in real time.</p><div><hr></div><p>I write about quantitative trading the way it&#8217;s actually practised:<br><br>Robust models and portfolios, combining signals and strategies, understanding the assumptions behind your models.</p><p>Topics I write about include portfolio construction, market making, risk management, research methodology, and more.</p><p>If this way of thinking resonates, you&#8217;ll probably like what I publish.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.vertoxquant.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">VertoxQuant is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h3><strong>What you&#8217;ll learn</strong></h3><ul><li><p>Why market-by-price data makes queue position a latent variable, and why the naive proportional heuristic isn&#8217;t enough.</p></li><li><p>How to model queue position as a distribution rather than a point estimate, and why that matters for execution and market making.</p></li><li><p>How to derive a particle filter for queue position from scratch, handling trades, cancellations, and fills correctly.</p></li><li><p>How to implement it live with Bybit&#8217;s WebSocket feed in Python.</p></li><li><p>What the queue position distribution actually looks like in real life, and how it evolves as the market moves.</p></li></ul>
      <p>
          <a href="https://www.vertoxquant.com/p/queue-position-estimation">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[How to Build a Model That Adapts in Real Time]]></title><description><![CDATA[Why rolling retraining isn't enough, and what to do instead.]]></description><link>https://www.vertoxquant.com/p/how-to-build-a-model-that-adapts</link><guid isPermaLink="false">https://www.vertoxquant.com/p/how-to-build-a-model-that-adapts</guid><dc:creator><![CDATA[Vertox]]></dc:creator><pubDate>Fri, 22 May 2026 22:59:32 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!oGAt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36f36af4-55ba-4ebc-af17-de674802d788_1389x1621.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the previous article, we began our online learning theory journey by introducing a model that can take multiple models&#8217; forecasts and spit out a combined forecast that is often superior to any given model and is mathematically guaranteed to perform similarly to the best model.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;f651447e-58ea-4a76-b2c5-00969f02d0e5&quot;,&quot;caption&quot;:&quot;Imagine you have multiple models forecasting asset returns.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;md&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Optimally Combining Forecasts&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:128680675,&quot;name&quot;:&quot;Vertox&quot;,&quot;bio&quot;:&quot;Quantitative Researcher in Digital Asset Markets | Market Making | Statistical Arbitrage | Options &quot;,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!HGUA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bf3fd86-d46a-4caa-969a-d80059b72cb9_128x128.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2026-05-19T22:51:10.194Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!kb4Y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F232c763f-61b8-4d92-abb9-0509513b040e_1390x1190.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.vertoxquant.com/p/optimally-combining-forecasts&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:198322476,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:5,&quot;comment_count&quot;:0,&quot;publication_id&quot;:1726874,&quot;publication_name&quot;:&quot;VertoxQuant&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!ufaQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb77b39-424b-4665-b2a7-7db519ff9e11_128x128.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>The models we used to forecast returns were themself not &#8220;online&#8221; though. They were trained on a warm-up set and then kept frozen. The first improvement that comes to mind is simply retraining them periodically, but it turns out there is a more powerful method that lets you learn every single timestep and not miss out on crucial shifts.</p><p>That&#8217;s what we&#8217;ll be implementing in this article.</p><div><hr></div><p>I write about quantitative trading the way it&#8217;s actually practiced:<br>Robust models and portfolios, combining signals and strategies, understanding the assumptions behind your models.</p><p>Topics I write about include portfolio construction, market making, risk management, research methodology, and more.</p><p>If this way of thinking resonates, you&#8217;ll probably like what I publish.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.vertoxquant.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">VertoxQuant is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h3>What you&#8217;ll learn</h3><ul><li><p>Why rolling window retraining is fundamentally limited and what assumptions it silently makes about your data.</p></li><li><p>How AROWR works: a second-order Bayesian online regression algorithm that maintains a full posterior over model weights and updates every single timestep.</p></li><li><p>How ARCOR extends AROWR with a principled covariance reset mechanism that detects when the market has changed and restores the model's ability to adapt.</p></li><li><p>How to implement AROWR and ARCOR from scratch in Python and apply them to any regression problem that updates in real time.</p></li><li><p>How we applied ARCOR to BTC beta estimation across 355 crypto assets over 4 years, significantly improving performance over rolling OLS, especially during LUNA, FTX, and similar situations.</p></li></ul>
      <p>
          <a href="https://www.vertoxquant.com/p/how-to-build-a-model-that-adapts">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Optimally Combining Forecasts]]></title><description><![CDATA[Online Learning with provable performance guarantees]]></description><link>https://www.vertoxquant.com/p/optimally-combining-forecasts</link><guid isPermaLink="false">https://www.vertoxquant.com/p/optimally-combining-forecasts</guid><dc:creator><![CDATA[Vertox]]></dc:creator><pubDate>Tue, 19 May 2026 22:51:10 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!kb4Y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F232c763f-61b8-4d92-abb9-0509513b040e_1390x1190.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Imagine you have multiple models forecasting asset returns. </p><p>Maybe one is a linear autoregressive model that performs well in trending markets. Another is a mean-reversion model, and a third is a more complex machine learning model that captures nonlinear patterns. Each has its strengths and weaknesses, and most importantly, you don&#8217;t know in advance which one will be best tomorrow.</p><p>The naive approach is to pick the best model in-sample and deploy it. Another naive approach is equal weighting. But those two approaches ignore everything you learn as new data arrives.</p><p>What if there exists a principled way to combine your models that:</p><ul><li><p>Allocates a lot of weight to models that currently perform well and less weight to models that perform poorly.</p></li><li><p>Requires no retraining, no hyperparameter tuning, no rebalancing decisions.</p></li><li><p>Comes with a mathematical guarantee that you perform nearly as well as the best model.</p></li></ul><p>In this article, we present an algorithm that is able to achieve all of the above, demonstrate its behavior, and show how this model shines when there are different regimes where different models perform best.</p><div><hr></div><p>I write about quantitative trading the way it&#8217;s actually practiced:<br><br>Robust models and portfolios, combining signals and strategies, understanding the assumptions behind your models.</p><p>Topics I write about include portfolio construction, market making, risk management, research methodology, and more.</p><p>If this way of thinking resonates, you&#8217;ll probably like what I publish.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.vertoxquant.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">VertoxQuant is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h3><strong>What you&#8217;ll learn:</strong></h3><ul><li><p>The theoretical framework of online learning and how it applies to forecast combination.</p></li><li><p>What regret is, why minimizing it is the right objective, and how it differs from standard in-sample loss minimization.</p></li><li><p>Why square loss has a special property called 2-mixability that enables a provably optimal combination algorithm.</p></li><li><p>How the aggregating forecaster works, why it is minimax optimal, and how to implement it from scratch in Python.</p></li><li><p>How to extend the algorithm with polynomial discounting to handle non-stationary markets with regime changes.</p></li><li><p>Why the optimal discount rate depends on regime persistence, and how to tune it empirically.</p></li></ul>
      <p>
          <a href="https://www.vertoxquant.com/p/optimally-combining-forecasts">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[The Effective Number of Tested Strategies]]></title><description><![CDATA[A correlation-aware correction for multiple testing in strategy research]]></description><link>https://www.vertoxquant.com/p/the-effective-number-of-tested-strategies</link><guid isPermaLink="false">https://www.vertoxquant.com/p/the-effective-number-of-tested-strategies</guid><dc:creator><![CDATA[Vertox]]></dc:creator><pubDate>Thu, 14 May 2026 22:47:45 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!TxFj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2727c5-6948-4e5a-98ce-b6a7af94ee79_1005x701.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In one of my <a href="https://www.vertoxquant.com/p/backtests-lie">recent articles,</a> we looked at a paper that proposed a measure of how many strategies you effectively tested in-sample. I found the idea of such a measure really interesting and useful, so I went deeper into it, uncovered problems with existing measures, and ultimately came up with my own measure that has all the properties I desire from such a measure!</p><h4>What is the point of such a measure?</h4><p>Let&#8217;s say you are testing a moving-average crossover strategy, and you test 20 different combinations of moving-average lookbacks. Even for different parameter settings, the strategy returns will be correlated, so you didn&#8217;t <em>really</em> test 20 different strategies. </p><p>Let&#8217;s now dive into ways of measuring this and why it&#8217;s incredibly useful.</p><div><hr></div><p>I write about quantitative trading the way it&#8217;s actually practiced:<br><br>Robust models and portfolios, combining signals and strategies, understanding the assumptions behind your models.</p><p>More broadly, I write about:</p><ul><li><p>Statistical and cross-sectional arbitrage</p></li><li><p>Managing multiple strategies and signals</p></li><li><p>Risk and capital allocation</p></li><li><p>Research tooling and methodology</p></li><li><p>In-depth model assumptions and derivations</p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.vertoxquant.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">VertoxQuant is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p><strong>What you&#8217;ll learn:</strong></p><ul><li><p>Why the raw number of tested strategies dramatically overstates overfitting risk.</p></li><li><p>Why dependence geometry determines multiple-testing complexity.</p></li><li><p>How expected chi-squared maxima define a continuous effective number of tests.</p></li><li><p>How to compute K_eff numerically.</p></li></ul><div><hr></div><h1>The 5 Axioms</h1><p>If I think of a measure of how many strategies were effectively tested, I think of a few intuitive axioms that such a measure should follow:</p><ul><li><p><strong>1 &lt;= K_eff &lt;= K</strong>: You can&#8217;t test fewer than one strategy, and you can&#8217;t test more strategies than you&#8217;ve actually tested. </p></li><li><p><strong>K_eff = 1 iff all strategies are perfectly correlated/anticorrelated</strong>: If all your strategies are perfectly correlated/anticorrelated, then you&#8217;ve effectively only tested a single strategy.</p></li><li><p><strong>K_eff = K iff all strategies are uncorrelated</strong>: If all your strategies are perfectly uncorrelated (or independent, which is the same in the Gaussian world), then you can&#8217;t get more information; you really tested as many strategies as you got.</p></li><li><p><strong>K_eff is non-decreasing in K</strong>: If we test more strategies, our effective number of strategies that we tested can&#8217;t decrease; it should only increase, or stay constant if the new strategy is perfectly correlated/anticorrelated to a previously tested strategy.</p></li><li><p><strong>The expectancy of the maximum of the absolute Z-scores of your K strategies grows asymptotically like the square root of twice the logarithm of K_eff</strong>: Okay, this one may not be so intuitive&#8230; Let me explain! Let Z_i be the Z-score of strategy i. We assume the Z&#8217;s to be standard Gaussian random variables with covariance matrix Sigma. A standard result in extreme value theory is that:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathbb{E}[\\max_{1\\leq i \\leq K} |Z_i|] \\sim \\sqrt{2 \\log K}&quot;,&quot;id&quot;:&quot;YPMNRUUIRY&quot;}" data-component-name="LatexBlockToDOM"></div><p>We want K_eff to be defined so that your correlated portfolio of K strategies looks exactly like K_eff independent strategies in terms of expected best absolute Z-score.</p></li></ul><div><hr></div><h1>Why Popular Measures Fail</h1><p>I&#8217;m not the first one to come up with a notion of &#8220;effective number of strategies tested&#8221;, so let&#8217;s look at some of the existing definitions and where they ultimately break down.</p><h3>Spectral Participation Rate</h3><p>Spectral Participation Rate is the measure that was used in the following article:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;ad3ff4b7-4ce0-4681-a5c0-8335d93fbad1&quot;,&quot;caption&quot;:&quot;Look at this backtest I found online:&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Backtests Lie: Building a Stress-Test Framework for Trading Signals&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:128680675,&quot;name&quot;:&quot;Vertox&quot;,&quot;bio&quot;:&quot;Quantitative Researcher in Digital Asset Markets | Market Making | Statistical Arbitrage | Options &quot;,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!HGUA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bf3fd86-d46a-4caa-969a-d80059b72cb9_128x128.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2026-04-22T21:57:16.195Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!NzDd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5a0ac2-d023-4c25-a9e6-9b9450d9f31d_790x490.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.vertoxquant.com/p/backtests-lie&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:194942463,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:19,&quot;comment_count&quot;:8,&quot;publication_id&quot;:1726874,&quot;publication_name&quot;:&quot;VertoxQuant&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!ufaQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb77b39-424b-4665-b2a7-7db519ff9e11_128x128.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>It&#8217;s defined as follows:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;K_\\text{eff} = \\frac{(\\text{tr} \\ K)^2}{||\\Sigma||_F^2} = \\frac{(\\sum_{i=1}^K \\lambda_i)^2}{\\sum_{i=1}^K \\lambda_i^2} = \\frac{K^2}{||\\Sigma||^2_F}&quot;,&quot;id&quot;:&quot;OPGHWKCLED&quot;}" data-component-name="LatexBlockToDOM"></div><p>where &#955;_1, &#8230;, &#955;_K are the eigenvalues of Sigma, which is the correlation matrix of our Z-scores.</p><p>By construction, K_eff = K under independence and decreases toward 1 as configurations become collinear. And there you have your problem, K_eff decreases toward 1 as configurations become collinear. Let&#8217;s say you have strategies A and B, which are completely independent, so K_eff = 2. Now imagine you were to test strategy B over and over again. You would want K_eff to stay 2, but something else happens.</p><p>If you keep adding copies of strategy B, your correlation matrix becomes:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\Sigma =\n\\begin{bmatrix}\n1 &amp; 0 &amp; 0 &amp; \\cdots \\\\\n0 &amp; 1 &amp; 1 &amp; \\cdots \\\\\n0 &amp; 1 &amp; 1 &amp; \\cdots \\\\\n\\vdots &amp; \\vdots &amp; \\vdots &amp; \\ddots\n\\end{bmatrix}&quot;,&quot;id&quot;:&quot;CGDWUQAUKU&quot;}" data-component-name="LatexBlockToDOM"></div><p>The eigenvalues of Sigma are:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\lambda_1 = K - 1, \\quad \\lambda_2 = 1, \\quad \\lambda_3 = ... = \\lambda_K = 0&quot;,&quot;id&quot;:&quot;YJQOWPPWCY&quot;}" data-component-name="LatexBlockToDOM"></div><p>So:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;K_\\text{eff} \\frac{K^2}{\\sum_{i=1}^K \\lambda_i^2} = \\frac{K^2}{(K-1)^2 + 1}&quot;,&quot;id&quot;:&quot;GSQPAAVBNR&quot;}" data-component-name="LatexBlockToDOM"></div><p>And as K goes to infinity, K_eff converges towards 1! </p><p>While this is an extreme example, it happens in reality with adaptive search as well. In Bayesian optimization, you explore parameter areas that previously gave you good results more thoroughly, which in turn gives you a highly correlated strategy and causes K_eff to decrease.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NzDd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5a0ac2-d023-4c25-a9e6-9b9450d9f31d_790x490.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NzDd!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5a0ac2-d023-4c25-a9e6-9b9450d9f31d_790x490.png 424w, https://substackcdn.com/image/fetch/$s_!NzDd!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5a0ac2-d023-4c25-a9e6-9b9450d9f31d_790x490.png 848w, https://substackcdn.com/image/fetch/$s_!NzDd!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5a0ac2-d023-4c25-a9e6-9b9450d9f31d_790x490.png 1272w, https://substackcdn.com/image/fetch/$s_!NzDd!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5a0ac2-d023-4c25-a9e6-9b9450d9f31d_790x490.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NzDd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5a0ac2-d023-4c25-a9e6-9b9450d9f31d_790x490.png" width="790" height="490" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6c5a0ac2-d023-4c25-a9e6-9b9450d9f31d_790x490.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:490,&quot;width&quot;:790,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!NzDd!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5a0ac2-d023-4c25-a9e6-9b9450d9f31d_790x490.png 424w, https://substackcdn.com/image/fetch/$s_!NzDd!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5a0ac2-d023-4c25-a9e6-9b9450d9f31d_790x490.png 848w, https://substackcdn.com/image/fetch/$s_!NzDd!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5a0ac2-d023-4c25-a9e6-9b9450d9f31d_790x490.png 1272w, https://substackcdn.com/image/fetch/$s_!NzDd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5a0ac2-d023-4c25-a9e6-9b9450d9f31d_790x490.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Axiom 4 is clearly violated, and thus, this is not usable for us.</p><h3>Effective Rank</h3><p>Effective rank is defined in <a href="https://www.eurasip.org/Proceedings/Eusipco/Eusipco2007/Papers/a5p-h05.pdf">Roy &amp; Vetterli (2007)</a>, and measures effective dimensionality by providing a real-valued extension to the rank of a matrix.</p><p>Consider the singular value decomposition (SVD) of Sigma:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\Sigma = UDV&quot;,&quot;id&quot;:&quot;ISSJVYUAWX&quot;}" data-component-name="LatexBlockToDOM"></div><p>where U and V are unitary matrices, and D is a diagonal matrix containing the singular values</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\sigma_1 \\geq \\sigma_2 \\geq ... \\geq \\sigma_K \\geq 0&quot;,&quot;id&quot;:&quot;HYFTJVQTJS&quot;}" data-component-name="LatexBlockToDOM"></div><p>Let the singular value distribution be </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;p_k = \\frac{\\sigma_k}{||\\sigma||_1}, \\quad k=1,2,...,K&quot;,&quot;id&quot;:&quot;SAWFAAUNBB&quot;}" data-component-name="LatexBlockToDOM"></div><p>where sigma is the vector of singular values and ||.||_1 the l1-norm. </p><p>The effective rank of the matrix Sigma is defined as</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\text{erank}(\\Sigma) = \\exp( H(p_1, p_2, ..., p_K)),&quot;,&quot;id&quot;:&quot;SVRSYLBRNL&quot;}" data-component-name="LatexBlockToDOM"></div><p>where H is the Shannon entropy given by</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;H(p_1, p_2, ..., p_K) = - \\sum_{k=1}^K p_k \\log p_k&quot;,&quot;id&quot;:&quot;SSPKWLQUCQ&quot;}" data-component-name="LatexBlockToDOM"></div><p>We will use this effective rank as our K_eff.</p><p>Consider again the scenario of independent strategies A and B, and testing strategy B over and over again. Since Sigma is SPD, the eigenvalues and singular values are the same:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\sigma_1 = K-1, \\quad \\sigma_2 = 1, \\quad \\sigma_3 = ... = \\sigma_K = 0&quot;,&quot;id&quot;:&quot;KEHKJNJZMO&quot;}" data-component-name="LatexBlockToDOM"></div><p>The l1 norm is:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;||\\sigma||_1 = K - 1 + 1 = K&quot;,&quot;id&quot;:&quot;KRMFVHNVEM&quot;}" data-component-name="LatexBlockToDOM"></div><p>And the singular value distribution is:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;p_1 = \\frac{K-1}{K}, \\quad p_2 = \\frac{1}{K}, \\quad p_3=...=p_K = 0&quot;,&quot;id&quot;:&quot;GMTZTGWGWP&quot;}" data-component-name="LatexBlockToDOM"></div><p>With this, erank(Sigma), or K_eff, becomes</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\text{erank}(\\Sigma) = \\exp(-\\frac{K-1}{K} \\log \\frac{K-1}{K} - \\frac{1}{K} \\log \\frac{1}{K}) \\to 1 \\quad \\text{as} \\ K \\to \\infty.&quot;,&quot;id&quot;:&quot;OAWXVIJCAI&quot;}" data-component-name="LatexBlockToDOM"></div><p>This suffers from the same problem as the spectral participation rate! The problem is that those two measures only look at the <em>shape</em> of the spectrum, not its <em>scale</em>. Adding more copies of B drowns out the contribution of A in the normalized distribution, pulling K_eff towards 1.</p><h3>Bailey &amp; L&#243;pez de Prado </h3><p>In the paper <a href="https://download.ssrn.com/19/05/30/ssrn_id2460551_code87814.pdf?response-content-disposition=inline&amp;X-Amz-Security-Token=IQoJb3JpZ2luX2VjEJn%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLWVhc3QtMSJHMEUCIHWbneth2mI6u1rupjNkDmsC24r7YhYtKqwzBrCdrBu1AiEA0WU%2B4iCvwSVB5ONW7ALjmPrdNS6r5OrCqrozPtwM%2FQIqvQUIYRAEGgwzMDg0NzUzMDEyNTciDCm525KNaW%2F%2FvbobXiqaBbM%2F10wzVAYLOFWs%2FBdHXoSs6z5TXKBRa4bQHQy6BIHTYZVfS6SLO4RbFKq5vL90d4VompUznee4RwIw3OsdFEJI2pEHmfDfklheeL8yN1MV8f4DR%2FRVhgvD2%2BPW3PPDL5HVERXsgHm9zDsPg7kkNifeAJBJEq%2FAvLsXA5j0Rib7JO3LWuDD6p0hCGU80x9345MhtxoyeZqCp5xndHj9UPhQzihMHPCRTH3KF3BFCCCB9OU3NPk7LNRcKGFo79dmnBdYnwqG7vhmLKp79MSxpeCQ%2BwEHl%2BKWF5tSlsVUOcQ8BwpbXT%2BfV8JQ6AM1MWAwy8XBAQ26FyrzzyqRsMuztXukttYEqyoybKKfzlF3bsXFk9fwF%2BWIMXm7C7SGxjC6NlGGgOQlE%2BI3jrbtm3zWMhMOeZK8ECyHe693vpzCW3fBsDhgi4GV%2BZIdQQKd%2BCoUoEHYQazMy6wku2sj9gG8PkNwIuLSLLIkcLdzCE1cmk6xZlHSEGGHKPZSpw4vHsw5m4xKnZOiquQlJGyHeIvvrl9yIjLVWdfInTlvvIp%2BK5CBvgVeP4Cx%2FKTUL4NmDx%2FB8ho5hfl2So6vKLFCy6B56b1oVoDPcCV5tMnRMk8yjy591i84Ulf2C5zphuEs4IYOLbGuTI9eqnUD57ifgOxnb%2B305GtO0nv6giMHgywu5O6pPH6IYH6vdxLxOnbbU8pjOad10Q53Wb2jQ39%2B0MZhbaprdcfinrz2wBoZZC6CmWsZzsbj5apKFAkGVOXXrmB4tihcRCtGsDfkD5P%2BpYJeZX%2FjqWR4VyqN4tFHvtjmXKP6C%2BMzpt5aej2KSZBR7po%2BCFm4%2BxkUl4DcucaL3fMJN4bNj9SOCakqON8ObGeWgsStFK9c0eFuv2hSSzC355fQBjqxAQoG21%2Ba57fWqweZ7Kb8BR1WXwhe7bE20M0VSwGZL5HZdsLE0mio22kgEM5%2BxQbVyKClcKNBkL%2B5RuwOmF5jJsxmf4N09LHgKWodjBVIMD549%2BnebRGLp%2BxbQNtfg9kNKJO%2FzmJFGzyqU%2B07e0H7cvz%2Fl3mAsntZUcRyWCxYsOc0OS03J88Xj9%2FFrqVA3nWoCL9tftQpH6CjtMFLjBAoVp7UrXYJdpxhA49yGnCh5PyVEA%3D%3D&amp;X-Amz-Algorithm=AWS4-HMAC-SHA256&amp;X-Amz-Date=20260514T164544Z&amp;X-Amz-SignedHeaders=host&amp;X-Amz-Expires=300&amp;X-Amz-Credential=ASIAUPUUPRWES6RLE2DD%2F20260514%2Fus-east-1%2Fs3%2Faws4_request&amp;X-Amz-Signature=83dcbd6f904a7443203ec090e39e9feccf55d87f98e12cc0830d61f80c432d91&amp;abstractId=2460551">"The Deflated Sharpe Ratio: Correcting for Selection Bias, Backtest Overfitting and Non-Normality"</a>, Bailey and L&#243;pez de Prado present another method of measuring the effective number of strategies tested.</p><p>They define</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;K_\\text{eff} = K(1 - \\hat{\\rho}(1-\\hat{\\rho})) + \\hat{\\rho},&quot;,&quot;id&quot;:&quot;IUCKHIGFOH&quot;}" data-component-name="LatexBlockToDOM"></div><p>where the equal-weighted average pairwise correlation is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\hat{\\rho} = \\frac{\\sum_{i\\neq j}\\Sigma_{ij}}{K(K-1)}.&quot;,&quot;id&quot;:&quot;ZWBQRJXSSY&quot;}" data-component-name="LatexBlockToDOM"></div><p>Here is an example where this measure also breaks down:</p><p>Let A and B be two perfectly anti-correlated strategies. Then</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\Sigma = \\begin{bmatrix}\n1 &amp; -1 \\\\\n-1 &amp; 1\n\\end{bmatrix}&quot;,&quot;id&quot;:&quot;AYTKIFYMIG&quot;}" data-component-name="LatexBlockToDOM"></div><p>and the average pairwise correlation is -1.</p><p>We get</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;K_\\text{eff} = 2(1 +(1+1)) -1 = 5.&quot;,&quot;id&quot;:&quot;JZSUKBKTYJ&quot;}" data-component-name="LatexBlockToDOM"></div><p>With this definition, our effective number of strategies tested is 5, even though we only tested 2 strategies. It also violates a bunch of other axioms. </p><div><hr></div><h1>A Definition That Works</h1><p>Here is what I propose. Let M(x) be the expected maximum of x i.i.d. squared standard normal random variables:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;M(x) = \\mathbb{E}[\\max_{1\\leq i \\leq x} \\tilde{Z}_i^2], \\quad \\tilde{Z}_1,...,\\tilde{Z}_x \\sim \\mathcal{N}(0,1)&quot;,&quot;id&quot;:&quot;AYIJCNVLSB&quot;}" data-component-name="LatexBlockToDOM"></div><p>Equivalently, since squaring a standard normal random variable yields a chi-squared random variable, this is the expected maximum of x i.i.d. chi-squared random variables. Using the PDF and CDF, we write the expected maximum as:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;M(x) = \\int_0^\\infty t \\cdot x \\cdot f_{\\chi_1^2}(t) \\cdot F_{\\chi_1^2}(t)^{x-1}dt&quot;,&quot;id&quot;:&quot;JNAFUJAYFI&quot;}" data-component-name="LatexBlockToDOM"></div><p>M is strictly increasing and continuous, so it has a well-defined inverse</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;M^{-1}: [0,\\infty) \\to [1, \\infty).&quot;,&quot;id&quot;:&quot;RGDYNAJOUT&quot;}" data-component-name="LatexBlockToDOM"></div><p>We then define the effective number of tested strategies as:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;K_\\text{eff} := M^{-1}(\\mathbb{E}[\\max_{1\\leq i \\leq K}Z_i^2])&quot;,&quot;id&quot;:&quot;JASOIIYWAI&quot;}" data-component-name="LatexBlockToDOM"></div><p>where Z_1, &#8230;, Z_K are the actual strategy Z-scores with correlation matrix Sigma. In other words, K_eff is the number of independent strategies that would produce the same expected best squared Z-score as your actual correlated portfolio of K strategies.</p><p>Now, let&#8217;s prove that this definition actually follows the 5 axioms.</p><h3>Axiom 1</h3><p>Since M is strictly increasing, it suffices to show that</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;M(1) \\leq \\mathbb{E}[\\max_{1\\leq i \\leq K} Z_i^2] \\leq M(K).&quot;,&quot;id&quot;:&quot;HOHMIDXDFI&quot;}" data-component-name="LatexBlockToDOM"></div><p><strong>Lower bound:</strong></p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathbb{E}[\\max_{1 \\leq i \\leq K} Z_i^2] \\geq \\mathbb{E}[Z_1^2] = 1 = M(1)&quot;,&quot;id&quot;:&quot;OCMYFQRGHQ&quot;}" data-component-name="LatexBlockToDOM"></div><p><strong>Upper bound:</strong></p><p>By &#352;id&#225;k&#8217;s inequality for centered Gaussian vectors,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;P(|Z_1| \\leq t, ..., |Z_K| \\leq t) \\geq \\prod_{i=1}^K P(|Z_i| \\leq t).&quot;,&quot;id&quot;:&quot;NHVTXLWKMJ&quot;}" data-component-name="LatexBlockToDOM"></div><p>Since each Z_i is standard normal, we have</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\prod_{i=1}^K P(|Z_i| \\leq t) = P(\\max_{1 \\leq i \\leq K} |\\tilde{Z}_i|\\leq t)&quot;,&quot;id&quot;:&quot;MLXQNCLEOO&quot;}" data-component-name="LatexBlockToDOM"></div><p>and hence</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\max_{1 \\leq i \\leq K} Z_i^2 \\leq_{st} \\max_{1 \\leq i \\leq K} |\\tilde{Z}_i|,&quot;,&quot;id&quot;:&quot;CZFITWJFHM&quot;}" data-component-name="LatexBlockToDOM"></div><p>where st means stochastically dominated. And because x &#8594; x^2 is increasing,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\max_{1 \\leq i \\leq K} Z_i^2 \\leq_{st} \\max_{1 \\leq i \\leq K} \\tilde{Z}_i^2.&quot;,&quot;id&quot;:&quot;YJVRKXPEQG&quot;}" data-component-name="LatexBlockToDOM"></div><p>Taking expectations gives</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathbb{E}[\\max_{1 \\leq i \\leq K} Z_i^2] \\leq \\mathbb{E}[\\max_{1 \\leq i \\leq K} \\tilde{Z}_i^2] = M(K).&quot;,&quot;id&quot;:&quot;JSVWMVMOWJ&quot;}" data-component-name="LatexBlockToDOM"></div><h3>Axiom 2</h3><p>If all strategies are perfectly correlated or anticorrelated, then for every i,j,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;|\\Sigma_{ij}| = 1.&quot;,&quot;id&quot;:&quot;PZBWQXOPGD&quot;}" data-component-name="LatexBlockToDOM"></div><p>Since each Z_i is standard Gaussian, this implies there exists a single standard normal random variable X and signs epsilon_i, either -1 or 1, such that</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;Z_i = \\epsilon_i X \\quad \\forall i.&quot;,&quot;id&quot;:&quot;IASXXUCNUO&quot;}" data-component-name="LatexBlockToDOM"></div><p>Therefore,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;Z_i^2 = X^2 \\quad \\forall i,&quot;,&quot;id&quot;:&quot;KQSCOMBDOB&quot;}" data-component-name="LatexBlockToDOM"></div><p>so</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\max_{1 \\leq i \\leq K} Z_i^2 = X^2.&quot;,&quot;id&quot;:&quot;HNFISJARZU&quot;}" data-component-name="LatexBlockToDOM"></div><p>Taking expectations,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathbb{E}[\\max_{1 \\leq i \\leq K} Z_i^2] = \\mathbb{E}[X^2] = M(1) = 1.&quot;,&quot;id&quot;:&quot;ZYMEGGOQRC&quot;}" data-component-name="LatexBlockToDOM"></div><p>Applying the inverse of M,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;K_\\text{eff} = M^{-1}(M(1)) = 1.&quot;,&quot;id&quot;:&quot;YQVRCVXFFN&quot;}" data-component-name="LatexBlockToDOM"></div><p>Now the other direction. Assume K_eff = 1. Since M(1) = 1, </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;K_\\text{eff} = 1 \\iff \\mathbb{E}[\\max_{1 \\leq i \\leq K} Z_i^2] = 1.&quot;,&quot;id&quot;:&quot;IDPRLCQYTA&quot;}" data-component-name="LatexBlockToDOM"></div><p>Since each Z_i is standard Gaussian, we have E[Z_i^2] = 1.</p><p>Since </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathbb{E}[\\max_{1 \\leq i \\leq K} Z_i^2] \\geq \\mathbb{E}[Z_j^2] = 1,&quot;,&quot;id&quot;:&quot;JLMXTDWLRP&quot;}" data-component-name="LatexBlockToDOM"></div><p>the equality</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathbb{E}[\\max_{1 \\leq i \\leq K} Z_i^2] = 1&quot;,&quot;id&quot;:&quot;AANFFOICSY&quot;}" data-component-name="LatexBlockToDOM"></div><p>can occur only if</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\max_{1 \\leq i \\leq K} Z_i^2 = Z_j^2 \\quad \\text{a.s.} \\ \\forall j.&quot;,&quot;id&quot;:&quot;NZCTCHLRKJ&quot;}" data-component-name="LatexBlockToDOM"></div><p>Thus</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;Z_1^2 = ... = Z_K^2 \\quad \\text{a.s.}&quot;,&quot;id&quot;:&quot;KCZAJFDLMI&quot;}" data-component-name="LatexBlockToDOM"></div><p>For jointly Gaussian variables, this implies</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;Z_i = \\pm Z_j \\quad \\text{a.s.}&quot;,&quot;id&quot;:&quot;KPNYJDPLGI&quot;}" data-component-name="LatexBlockToDOM"></div><p>and therefore</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\text{Corr}(Z_i, Z_j) = \\pm 1.&quot;,&quot;id&quot;:&quot;OUUXZJNAIN&quot;}" data-component-name="LatexBlockToDOM"></div><h3>Axiom 3</h3><p>If all strategies are uncorrelated, we have</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\Sigma = I_K,&quot;,&quot;id&quot;:&quot;WZLOXHABHI&quot;}" data-component-name="LatexBlockToDOM"></div><p>which implies that</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;(Z_1, ..., Z_K) \\overset{d}{=} (\\tilde{Z}_1, ..., \\tilde{Z}_K).&quot;,&quot;id&quot;:&quot;BNKVSSQYZD&quot;}" data-component-name="LatexBlockToDOM"></div><p>Therefore,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathbb{E}[\\max_{1 \\leq i \\leq K} Z_i^2] = \\mathbb{E}[\\max_{1 \\leq i \\leq K} \\tilde{Z}_i^2] = M(K).&quot;,&quot;id&quot;:&quot;ODDZHDUXOY&quot;}" data-component-name="LatexBlockToDOM"></div><p>Applying the inverse of M, we get</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;K_\\text{eff} = M^{-1}(M(K)) = K.&quot;,&quot;id&quot;:&quot;YDSGOCCMGK&quot;}" data-component-name="LatexBlockToDOM"></div><p>Now the other direction. Assume K_eff = K. Since M is strictly increasing,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathbb{E}[\\max_{1 \\leq i \\leq K} Z_i^2] = M(K) = \\mathbb{E}[\\max_{1 \\leq i \\leq K} \\tilde{Z}_i^2].&quot;,&quot;id&quot;:&quot;OWXQOCRACX&quot;}" data-component-name="LatexBlockToDOM"></div><p>Now let </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;X := \\max_{1 \\leq i \\leq K} Z_i^2, \\quad Y := \\max_{1 \\leq i \\leq K} \\tilde{Z}_i^2.&quot;,&quot;id&quot;:&quot;STQJGRXHML&quot;}" data-component-name="LatexBlockToDOM"></div><p>From the proof of Axiom 1, we know that </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;X \\leq_{st} Y,&quot;,&quot;id&quot;:&quot;TQLUONNEZS&quot;}" data-component-name="LatexBlockToDOM"></div><p>i.e.</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;P(X > t) \\leq P(Y > t) \\quad \\forall t \\geq 0.&quot;,&quot;id&quot;:&quot;PULFEPLXYX&quot;}" data-component-name="LatexBlockToDOM"></div><p>Using the tail-integral formula,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathbb{E}[Y] - \\mathbb{E}[X] = \\int_0^\\infty (P(Y > t) - P(X > t))dt&quot;,&quot;id&quot;:&quot;SUETPCVNDC&quot;}" data-component-name="LatexBlockToDOM"></div><p>The integrand is nonnegative everywhere, and the left-hand side is zero since E[X] = E[Y]. Hence</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;P(X > t) = P(Y > t) \\quad \\forall t \\geq 0.&quot;,&quot;id&quot;:&quot;CQULXWILIM&quot;}" data-component-name="LatexBlockToDOM"></div><p>Thus, X and Y have the same distribution. Equivalently,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;P(|Z_1| \\leq t, ..., |Z_K| \\leq t) = \\prod_{i=1}^K P(|Z_i| \\leq t) \\quad \\forall t \\geq 0.&quot;,&quot;id&quot;:&quot;NWFPJRLMYW&quot;}" data-component-name="LatexBlockToDOM"></div><p>By the equality case of &#352;id&#225;k&#8217;s inequality, this implies that Z_1, &#8230;, Z_K are independent, which for Gaussian random variables is equivalent to being uncorrelated.</p><h3>Axiom 4:</h3><p>We have</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\max(\\max_{1 \\leq i \\leq K}Z_i^2, Z_{K+1}^2) \\geq \\max_{1 \\leq i \\leq K} Z_i^2 \\quad \\text{a.s.}&quot;,&quot;id&quot;:&quot;ULHTTCGETR&quot;}" data-component-name="LatexBlockToDOM"></div><p>Taking expectation</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathbb{E}[\\max(\\max_{1 \\leq i \\leq K}Z_i^2, Z_{K+1}^2)] \\geq \\mathbb{E}[\\max_{1 \\leq i \\leq K} Z_i^2],&quot;,&quot;id&quot;:&quot;ZJJFLAPMUT&quot;}" data-component-name="LatexBlockToDOM"></div><p>and applying the inverse of M, we get </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;K_\\text{eff}(K+1) \\geq K_\\text{eff}(K).&quot;,&quot;id&quot;:&quot;AUKSODZVHC&quot;}" data-component-name="LatexBlockToDOM"></div><h3>Axiom 5:</h3><p>Let</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;Y_k := \\max_{1 \\leq i \\leq k} |\\tilde{Z}_i|.&quot;,&quot;id&quot;:&quot;QFEGTTDNDT&quot;}" data-component-name="LatexBlockToDOM"></div><p>Then</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;M(k) = \\mathbb{E}[Y_k^2].&quot;,&quot;id&quot;:&quot;JIZDEIQWWC&quot;}" data-component-name="LatexBlockToDOM"></div><p>A standard result from Gaussian extreme-value theory states that</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\frac{Y_k}{\\sqrt{2 \\log k}} \\to 1 \\quad \\text{in probability}.&quot;,&quot;id&quot;:&quot;DENHZQGZJL&quot;}" data-component-name="LatexBlockToDOM"></div><p>Moreover, </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\frac{Y_k^2}{2 \\log k}&quot;,&quot;id&quot;:&quot;MKFYHDONDI&quot;}" data-component-name="LatexBlockToDOM"></div><p>is uniformly integrable. Hence, convergence in probability implies convergence of expectations:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\frac{\\mathbb{E}[Y_k^2]}{2 \\log k} \\to 1.&quot;,&quot;id&quot;:&quot;VSIGVTSOYE&quot;}" data-component-name="LatexBlockToDOM"></div><p>Hence</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;M(k) = \\mathbb{E}[Y_k^2] \\sim 2 \\log k&quot;,&quot;id&quot;:&quot;AENIOOBGGZ&quot;}" data-component-name="LatexBlockToDOM"></div><p>Substituting k = K_eff yields</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathbb{E}[\\max_{1 \\leq i \\leq K} Z_i^2] = M(K_\\text{eff}) \\sim 2 \\log K_\\text{eff}.&quot;,&quot;id&quot;:&quot;ADFIPBQXDK&quot;}" data-component-name="LatexBlockToDOM"></div><p>Since</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\max_{1\\leq i \\leq K} Z_i^2 = (\\max_{1 \\leq i \\leq K}|Z_i|)^2,&quot;,&quot;id&quot;:&quot;WTVWACBJJO&quot;}" data-component-name="LatexBlockToDOM"></div><p>we obtain</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathbb{E}[(\\max_{1 \\leq i \\leq K} |Z_i|)^2] \\sim 2 \\log K_\\text{eff}.&quot;,&quot;id&quot;:&quot;FWDRKYWKBP&quot;}" data-component-name="LatexBlockToDOM"></div><p>Since Gaussian maxima concentrate sharply, the first and second moments are asymptotically equivalent up to square-root scaling. Therefore,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathbb{E}[\\max_{1 \\leq i \\leq K} |Z_i|] \\sim \\sqrt{2 \\log K_\\text{eff}}.&quot;,&quot;id&quot;:&quot;RRYXOUMETZ&quot;}" data-component-name="LatexBlockToDOM"></div><div><hr></div><h1>Simulation</h1><p>Below is the code used for computing K_eff:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;189169c9-5192-4c6e-8b4f-3584a139ab1a&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">import numpy as np
from scipy.stats import chi2
from scipy.optimize import brentq


def M(x: float, n_quad: int = 4000) -&gt; float:
    """
    Compute M(x) = E[max of x i.i.d. chi^2_1 variables] via numerical
    quadrature, working in log space to avoid underflow.

    Parameters
    ----------
    x       : effective count (any real &gt;= 1)
    n_quad  : number of quadrature points

    Returns
    -------
    float : E[max_i Z_i^2] for x i.i.d. N(0,1) variables
    """
    # Adaptive upper limit: tail of chi^2_1 maximum decays beyond this
    hi = chi2.ppf(1 - 1e-10 / x, df=1) if x &gt; 1 else chi2.ppf(1 - 1e-8, df=1)
    t  = np.linspace(0, hi, n_quad + 1)[1:]  # avoid t=0 where pdf diverges

    log_F   = chi2.logcdf(t, df=1)
    log_f   = chi2.logpdf(t, df=1)
    log_ker = np.log(t) + np.log(x) + log_f + (x - 1) * log_F

    # Zero out terms that underflow (negligible contribution)
    mask       = log_ker &gt; -700
    integrand  = np.zeros_like(t)
    integrand[mask] = np.exp(log_ker[mask])

    return float(np.trapezoid(integrand, t))


def M_inv(val: float, tol: float = 1e-8) -&gt; float:
    """
    Compute M^{-1}(val) via Brent's method.

    Parameters
    ----------
    val : target value, must be &gt;= M(1) = 1
    tol : tolerance for root finding

    Returns
    -------
    float : x such that M(x) = val
    """
    if val &lt;= 1.0:
        return 1.0

    # Bracket: expand upper bound until M(hi) &gt; val
    hi = 2.0
    while M(hi) &lt; val:
        hi *= 2.0

    return brentq(lambda x: M(x) - val, 1.0, hi, xtol=tol)


def K_eff(Sigma: np.ndarray, n_sim: int = 200_000, seed: int = 42) -&gt; float:
    """
    Compute K_eff for a portfolio of K strategies with correlation matrix Sigma.

    Uses Monte Carlo to estimate E[max_i Z_i^2], then inverts M analytically.

    Parameters
    ----------
    Sigma : (K, K) correlation matrix
    n_sim : number of Monte Carlo samples
    seed  : random seed

    Returns
    -------
    float : K_eff in [1, K]
    """
    K   = Sigma.shape[0]
    rng = np.random.default_rng(seed)
    L   = np.linalg.cholesky(Sigma)
    Z   = (L @ rng.standard_normal((K, n_sim)))  # (K, n_sim)
    E_max_Z2 = float(np.mean(np.max(Z**2, axis=0)))
    return M_inv(E_max_Z2)</code></pre></div><p>And now let&#8217;s simulate how K_eff evolves as K grows for different families of strategies:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;8bda2bcd-10b6-4db6-93ff-a7cab552200d&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">import matplotlib.pyplot as plt


# ============================================================
# Helper: build equicorrelation matrix
# ============================================================

def equicorr_matrix(K, rho):
    """
    Build K x K equicorrelation matrix with off-diagonal rho.
    """

    Sigma = np.full((K, K), rho, dtype=float)
    np.fill_diagonal(Sigma, 1.0)

    return Sigma


# ============================================================
# Sequential simulation
# ============================================================

def sequential_keff(mode, K_max=100):

    K_vals    = []
    Keff_vals = []

    # Persistent storage for sequential random strategies
    random_vectors = []

    rng = np.random.default_rng(123)

    for K in range(1, K_max + 1):

        # ----------------------------------------------------
        # Independent
        # ----------------------------------------------------
        if mode == "independent":

            Sigma = np.eye(K, dtype=float)

        # ----------------------------------------------------
        # Perfect dependence
        # ----------------------------------------------------
        elif mode == "dependent":

            Sigma = np.ones((K, K), dtype=float)

        # ----------------------------------------------------
        # rho = 0.5
        # ----------------------------------------------------
        elif mode == "rho_0.5":

            Sigma = equicorr_matrix(K, 0.5)

        # ----------------------------------------------------
        # Maximally negative equicorrelation
        # ----------------------------------------------------
        elif mode == "negative_boundary":

            if K == 1:
                rho = 0.0
            else:
                # PSD boundary:
                # rho &gt;= -1/(K-1)
                rho = -0.9 / (K - 1)

            Sigma = equicorr_matrix(K, rho)

        # ----------------------------------------------------
        # Sequential random correlated strategies
        # ----------------------------------------------------
        elif mode == "random":

            # Add ONE new latent-factor strategy
            v = rng.standard_normal(5)

            # Normalize
            v /= np.linalg.norm(v)

            random_vectors.append(v)

            X = np.stack(random_vectors)

            # Correlation matrix
            Sigma = X @ X.T

        else:
            raise ValueError(f"Unknown mode: {mode}")

        # ----------------------------------------------------
        # Numerical stabilization
        # ----------------------------------------------------

        Sigma = Sigma.astype(float)

        Sigma += 1e-10 * np.eye(K)

        # ----------------------------------------------------
        # Compute K_eff
        # ----------------------------------------------------

        keff = K_eff(Sigma)

        K_vals.append(K)
        Keff_vals.append(keff)

        print(
            f"{mode:20s} | "
            f"K = {K:3d} | "
            f"K_eff = {keff:8.3f}"
        )

    return np.array(K_vals), np.array(Keff_vals)


# ============================================================
# Run all simulations
# ============================================================

modes = [
    "independent",
    "dependent",
    "rho_0.5",
    "negative_boundary",
    "random"
]

results = {}

for mode in modes:

    K, Keff = sequential_keff(mode, K_max=100)

    results[mode] = (K, Keff)


# ============================================================
# Plot
# ============================================================

plt.figure(figsize=(12, 8))

for mode in modes:

    K, Keff = results[mode]

    plt.plot(K, Keff, linewidth=2, label=mode)

# Reference line
plt.plot(
    np.arange(1, 101),
    np.arange(1, 101),
    linestyle="--",
    linewidth=2,
    label="K_eff = K"
)

plt.xlabel("Raw Number of Tested Strategies (K)")
plt.ylabel("Effective Number of Strategies (K_eff)")

plt.title(
    "Sequential Growth of K_eff Under Different Correlation Structures"
)

plt.legend()
plt.grid(True)

plt.show()</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TxFj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2727c5-6948-4e5a-98ce-b6a7af94ee79_1005x701.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TxFj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2727c5-6948-4e5a-98ce-b6a7af94ee79_1005x701.png 424w, https://substackcdn.com/image/fetch/$s_!TxFj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2727c5-6948-4e5a-98ce-b6a7af94ee79_1005x701.png 848w, https://substackcdn.com/image/fetch/$s_!TxFj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2727c5-6948-4e5a-98ce-b6a7af94ee79_1005x701.png 1272w, https://substackcdn.com/image/fetch/$s_!TxFj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2727c5-6948-4e5a-98ce-b6a7af94ee79_1005x701.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TxFj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2727c5-6948-4e5a-98ce-b6a7af94ee79_1005x701.png" width="1005" height="701" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8f2727c5-6948-4e5a-98ce-b6a7af94ee79_1005x701.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:701,&quot;width&quot;:1005,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:86377,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/197731389?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2727c5-6948-4e5a-98ce-b6a7af94ee79_1005x701.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!TxFj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2727c5-6948-4e5a-98ce-b6a7af94ee79_1005x701.png 424w, https://substackcdn.com/image/fetch/$s_!TxFj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2727c5-6948-4e5a-98ce-b6a7af94ee79_1005x701.png 848w, https://substackcdn.com/image/fetch/$s_!TxFj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2727c5-6948-4e5a-98ce-b6a7af94ee79_1005x701.png 1272w, https://substackcdn.com/image/fetch/$s_!TxFj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2727c5-6948-4e5a-98ce-b6a7af94ee79_1005x701.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h1>Conclusion</h1><p>K_eff is not just theoretical; it has immediate practical applications.</p><p>The most direct one is improving the Deflated Sharpe Ratio presented by Bailey and De Prado. More broadly, K_eff can be used anywhere you need to correct for multiple testing across correlated strategies.</p><p>It can also directly guide you in determining when to stop searching while tuning hyperparameters.</p><p>I will explore those and many other things K_eff is capable of, and the math behind K_eff in more detail in future articles, which I then plan to all combine into a research paper!</p><p>Join Quant Corner: <a href="https://discord.gg/X7TsxKNbXg">https://discord.gg/X7TsxKNbXg</a></p><p>Quick reminder that I&#8217;m now open for consulting and short-term engagements. If your team needs help with anything in the quant space, like strategy research, portfolio construction, execution analysis, signal development, or just a second brain on a hard problem, I'm available. You can DM me on Discord or email me at vertoxquant@gmail.com.</p>]]></content:encoded></item><item><title><![CDATA[Going full-time on VertoxQuant]]></title><description><![CDATA[And I'm up for hire!]]></description><link>https://www.vertoxquant.com/p/going-full-time-on-vertoxquant</link><guid isPermaLink="false">https://www.vertoxquant.com/p/going-full-time-on-vertoxquant</guid><dc:creator><![CDATA[Vertox]]></dc:creator><pubDate>Mon, 11 May 2026 17:03:45 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ufaQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb77b39-424b-4665-b2a7-7db519ff9e11_128x128.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey everyone,</p><p>I have some news to share. As of today, I'm going fully independent and dedicating all of my time to VertoxQuant. </p><p>For the past few years, I've been splitting my hours between my work as a quant researcher and the newsletter. That chapter is now closed, which means every hour I would have spent on industry work is now going straight into research, writing, and building things here. </p><p>In practice, that means more articles, deeper dives, and more time to explore the corners of quant finance I actually find interesting, not just the stuff that's immediately commercially useful. </p><p>For those newer here: my background is in quantitative research and systematic trading, with experience across strategy research, portfolio construction, execution analysis, and signal development. I also hold a degree in mathematics, though I tend to approach problems very practically while maintaining the right level of mathematical rigor. VertoxQuant started as a place to share ideas and research publicly, and it has grown into a community of people who care deeply about quantitative finance. </p><p>I'm also now open for consulting and short-term engagements. If your team needs help with anything in the quant space, like strategy research, portfolio construction, execution analysis, signal development, or just a second brain on a hard problem, I'm available. You can DM me on Discord or email me at vertoxquant@gmail.com.</p><p>I&#8217;m incredibly excited for what comes next. </p><p>-VertoxQuant</p>]]></content:encoded></item><item><title><![CDATA[Topological Risk Parity]]></title><description><![CDATA[Tree-Based Long/Short Portfolio Construction]]></description><link>https://www.vertoxquant.com/p/topological-risk-parity</link><guid isPermaLink="false">https://www.vertoxquant.com/p/topological-risk-parity</guid><dc:creator><![CDATA[Vertox]]></dc:creator><pubDate>Thu, 07 May 2026 10:18:28 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ox8k!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd6d67bb9-0135-41b9-beba-4d38c255d804_2590x1990.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Portfolio construction is one of the most studied problems in quantitative finance, yet it&#8217;s still surprisingly hard to get it done in practice. Mean-variance optimization is notoriously unstable. We talk about how to make it stable here:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;42c92dbf-ba88-427c-aaaa-6e3a2ed3396a&quot;,&quot;caption&quot;:&quot;Introduction&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Why Mean-Variance Optimization Breaks Down&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:128680675,&quot;name&quot;:&quot;Vertox&quot;,&quot;bio&quot;:&quot;Quantitative Researcher in Digital Asset Markets | Market Making | Statistical Arbitrage | Options &quot;,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!HGUA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bf3fd86-d46a-4caa-969a-d80059b72cb9_128x128.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2026-02-03T23:01:54.857Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!YSLy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89f1c92b-a219-4a6b-afc1-7a900bc204d7_925x675.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.vertoxquant.com/p/why-mean-variance-optimization-breaks&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:186718680,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:19,&quot;comment_count&quot;:0,&quot;publication_id&quot;:1726874,&quot;publication_name&quot;:&quot;VertoxQuant&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!ufaQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb77b39-424b-4665-b2a7-7db519ff9e11_128x128.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>Rather than trying to fix a method, you can also go down the route of using specially designed portfolio optimization techniques that don&#8217;t suffer from instability as much. Hierarchical Risk Parity (HRP) is one of the most popular such techniques, replacing the covariance inverse with a recursive clustering procedure that is more robust by construction. But even HRP has its limitations; It&#8217;s designed to be long-only, and it takes no signal input whatsoever. It&#8217;s a pure risk allocation method. Any alpha you&#8217;ve worked so hard to generate is completely ignored by it.</p><p>This matters enormously for stat-arb and long-short strategies, where both the signal and the risk structure are crucial. What you want is a portfolio construction method that uses market structure to shape position sizes while preserving signal direction. That is exactly what Topological Risk Parity (TRP), introduced by Nayar, Ainasse, and Kulkarni (2026), is designed to do.</p><p>In this article, we implement TRP from scratch in Python on a crypto universe. We also implement the Semi-Supervised variant of TRP, which allows you to impose an economic prior on the hierarchy, like forcing BTC to be the market root and major L1s as the second layer. We then apply Random Matrix Theory (RMT) to further improve TRP across every performance metric!</p><div><hr></div><p><strong>What you&#8217;ll learn:</strong></p><ul><li><p>What Topological Risk Parity is and why it outperforms HRP for long-short strategies</p></li><li><p>How to build a Minimum Spanning Tree from a correlation matrix and what it reveals about market structure</p></li><li><p>How Random Matrix Theory separates genuine economic signals from statistical noise in correlation matrices</p></li><li><p>How to denoise a correlation matrix using Ledoit-Wolf shrinkage and hard thresholding</p></li><li><p>How to implement TRP from scratch in Python, including the Semi-Supervised variant with economic anchoring</p></li></ul><div><hr></div><p>I write about quantitative trading the way it&#8217;s actually practiced:<br><br>Robust models and portfolios, combining signals and strategies, understanding the assumptions behind your models.</p><p>More broadly, I write about:</p><ul><li><p>Statistical and cross-sectional arbitrage</p></li><li><p>Managing multiple strategies and signals</p></li><li><p>Risk and capital allocation</p></li><li><p>Research tooling and methodology</p></li><li><p>In-depth model assumptions and derivations</p></li></ul><p>If this way of thinking resonates, you&#8217;ll probably like what I publish.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.vertoxquant.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">VertoxQuant is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h1>Mapping the Market with Correlation Networks</h1>
      <p>
          <a href="https://www.vertoxquant.com/p/topological-risk-parity">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Backtests Lie: Building a Stress-Test Framework for Trading Signals]]></title><description><![CDATA[Synthetic nulls, falsification audits, and backtest inflation diagnostics in Python.]]></description><link>https://www.vertoxquant.com/p/backtests-lie</link><guid isPermaLink="false">https://www.vertoxquant.com/p/backtests-lie</guid><dc:creator><![CDATA[Vertox]]></dc:creator><pubDate>Wed, 22 Apr 2026 21:57:16 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!NzDd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5a0ac2-d023-4c25-a9e6-9b9450d9f31d_790x490.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Look at this backtest I found online:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!svQw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2047df2c-3000-48bc-9349-3f4214af42b7_1838x816.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!svQw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2047df2c-3000-48bc-9349-3f4214af42b7_1838x816.png 424w, https://substackcdn.com/image/fetch/$s_!svQw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2047df2c-3000-48bc-9349-3f4214af42b7_1838x816.png 848w, https://substackcdn.com/image/fetch/$s_!svQw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2047df2c-3000-48bc-9349-3f4214af42b7_1838x816.png 1272w, https://substackcdn.com/image/fetch/$s_!svQw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2047df2c-3000-48bc-9349-3f4214af42b7_1838x816.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!svQw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2047df2c-3000-48bc-9349-3f4214af42b7_1838x816.png" width="1456" height="646" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2047df2c-3000-48bc-9349-3f4214af42b7_1838x816.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:646,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:90931,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/194942463?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2047df2c-3000-48bc-9349-3f4214af42b7_1838x816.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!svQw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2047df2c-3000-48bc-9349-3f4214af42b7_1838x816.png 424w, https://substackcdn.com/image/fetch/$s_!svQw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2047df2c-3000-48bc-9349-3f4214af42b7_1838x816.png 848w, https://substackcdn.com/image/fetch/$s_!svQw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2047df2c-3000-48bc-9349-3f4214af42b7_1838x816.png 1272w, https://substackcdn.com/image/fetch/$s_!svQw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2047df2c-3000-48bc-9349-3f4214af42b7_1838x816.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>One of your first thoughts when looking at a stranger&#8217;s backtest is probably that it&#8217;s overfit, or that there is some look-ahead somewhere.</p><p>When you go a step further, you are probably constantly worried about overfitting your own backtests too!</p><p>In this article, we will introduce a framework that allows you to identify both! It&#8217;s a two-stage approach introduced in <a href="https://arxiv.org/pdf/2604.15531">D. Nikolopoulos (2026)</a>. We will introduce the method, develop the two-stage approach, test the methodology empirically on a crypto dataset, look at some limitations, and also add some improvements of my own!</p><div><hr></div><p>I write about quantitative trading the way it&#8217;s actually practiced:<br>Robust models and portfolios, combining signals and strategies, understanding the assumptions behind your models.</p><p>More broadly, I write about:</p><ul><li><p>Statistical and cross-sectional arbitrage</p></li><li><p>Managing multiple strategies and signals</p></li><li><p>Risk and capital allocation</p></li><li><p>Research tooling and methodology</p></li><li><p>In-depth model assumptions and derivations</p></li></ul><p>If this way of thinking resonates, you&#8217;ll probably like what I publish.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.vertoxquant.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">VertoxQuant is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h1>How Backtests Lie</h1>
      <p>
          <a href="https://www.vertoxquant.com/p/backtests-lie">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Strategy Decay Detection: Building a Warning System for Alpha Erosion]]></title><description><![CDATA[Knowing when to pull the plug]]></description><link>https://www.vertoxquant.com/p/strategy-decay-detection</link><guid isPermaLink="false">https://www.vertoxquant.com/p/strategy-decay-detection</guid><dc:creator><![CDATA[Vertox]]></dc:creator><pubDate>Tue, 14 Apr 2026 09:17:32 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Yd5E!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4f0da95-24ec-4bd1-9b6f-73a13887cf7a_1189x2390.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Imagine the following: You spend weeks working on a strategy, the backtest looks great, a Sharpe of 1.5. You decide to go live, and it slowly and quietly stops working.<br>Did you overfit? Or maybe it&#8217;s alpha decay? </p><p>Everyone talks about alpha decay, but no one tells you how to actually quantify it. In this article, we&#8217;ll figure out how to do so and build a warning system that tells you when it&#8217;s time to pull the plug on a strategy.</p><p>We do this by implementing Minimum Regime Performance (MRP), a framework introduced by Alexander and Fabozzi (2026) that measures how a strategy holds up across structurally distinct market regimes. We will apply this method to a universe of crypto factors.</p><p>Beyond signal monitoring, MRP is also relevant in portfolio construction. Just as you would punish strategy tail risk like Value at Risk, you can also punish strategies that have a high tendency to decay. </p><p>The article will use the factors discussed in the following article:</p><div class="embedded-post-wrap" data-attrs="{&quot;id&quot;:185829391,&quot;url&quot;:&quot;https://www.vertoxquant.com/p/the-myth-of-factor-free-crypto&quot;,&quot;publication_id&quot;:1726874,&quot;publication_name&quot;:&quot;VertoxQuant&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!ufaQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb77b39-424b-4665-b2a7-7db519ff9e11_128x128.png&quot;,&quot;title&quot;:&quot;The Myth of Factor-Free Crypto&quot;,&quot;truncated_body_text&quot;:&quot;People keep telling you to take what works in equities and apply it to crypto.&quot;,&quot;date&quot;:&quot;2026-01-27T11:58:38.274Z&quot;,&quot;like_count&quot;:9,&quot;comment_count&quot;:0,&quot;bylines&quot;:[{&quot;id&quot;:128680675,&quot;name&quot;:&quot;Vertox&quot;,&quot;handle&quot;:&quot;vertox&quot;,&quot;previous_name&quot;:null,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!HGUA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bf3fd86-d46a-4caa-969a-d80059b72cb9_128x128.jpeg&quot;,&quot;bio&quot;:&quot;Quantitative Researcher in Digital Asset Markets | Market Making | Statistical Arbitrage | Options &quot;,&quot;profile_set_up_at&quot;:&quot;2023-06-12T09:38:30.926Z&quot;,&quot;reader_installed_at&quot;:&quot;2023-06-12T09:50:35.665Z&quot;,&quot;publicationUsers&quot;:[{&quot;id&quot;:1706583,&quot;user_id&quot;:128680675,&quot;publication_id&quot;:1726874,&quot;role&quot;:&quot;admin&quot;,&quot;public&quot;:true,&quot;is_primary&quot;:true,&quot;publication&quot;:{&quot;id&quot;:1726874,&quot;name&quot;:&quot;VertoxQuant&quot;,&quot;subdomain&quot;:&quot;vertox&quot;,&quot;custom_domain&quot;:&quot;www.vertoxquant.com&quot;,&quot;custom_domain_optional&quot;:false,&quot;hero_text&quot;:&quot;Applied quantitative research on trading, risk, and systematic strategy design.&quot;,&quot;logo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5fb77b39-424b-4665-b2a7-7db519ff9e11_128x128.png&quot;,&quot;author_id&quot;:128680675,&quot;primary_user_id&quot;:128680675,&quot;theme_var_background_pop&quot;:&quot;#9A6600&quot;,&quot;created_at&quot;:&quot;2023-06-12T09:38:54.325Z&quot;,&quot;email_from_name&quot;:null,&quot;copyright&quot;:&quot;Vertox&quot;,&quot;founding_plan_name&quot;:null,&quot;community_enabled&quot;:true,&quot;invite_only&quot;:false,&quot;payments_state&quot;:&quot;enabled&quot;,&quot;language&quot;:null,&quot;explicit&quot;:false,&quot;homepage_type&quot;:&quot;newspaper&quot;,&quot;is_personal_mode&quot;:false,&quot;logo_url_wide&quot;:null}}],&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100,&quot;status&quot;:{&quot;bestsellerTier&quot;:100,&quot;subscriberTier&quot;:null,&quot;leaderboard&quot;:null,&quot;vip&quot;:false,&quot;badge&quot;:{&quot;type&quot;:&quot;bestseller&quot;,&quot;tier&quot;:100},&quot;paidPublicationIds&quot;:[],&quot;subscriber&quot;:null}}],&quot;utm_campaign&quot;:null,&quot;belowTheFold&quot;:false,&quot;type&quot;:&quot;newsletter&quot;,&quot;language&quot;:&quot;en&quot;,&quot;source&quot;:null}" data-component-name="EmbeddedPostToDOM"><a class="embedded-post" native="true" href="https://www.vertoxquant.com/p/the-myth-of-factor-free-crypto?utm_source=substack&amp;utm_campaign=post_embed&amp;utm_medium=web"><div class="embedded-post-header"><img class="embedded-post-publication-logo" src="https://substackcdn.com/image/fetch/$s_!ufaQ!,w_56,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb77b39-424b-4665-b2a7-7db519ff9e11_128x128.png"><span class="embedded-post-publication-name">VertoxQuant</span></div><div class="embedded-post-title-wrapper"><div class="embedded-post-title">The Myth of Factor-Free Crypto</div></div><div class="embedded-post-body">People keep telling you to take what works in equities and apply it to crypto&#8230;</div><div class="embedded-post-cta-wrapper"><span class="embedded-post-cta">Read more</span></div><div class="embedded-post-meta">5 months ago &#183; 9 likes &#183; Vertox</div></a></div><p>Knowledge of regime switching models is NOT required.</p><div><hr></div><p>I write about quantitative trading the way it&#8217;s actually practiced:<br>Robust models and portfolios, combining signals and strategies, understanding the assumptions behind your models.</p><p>More broadly, I write about:</p><ul><li><p>Statistical and cross-sectional arbitrage</p></li><li><p>Managing multiple strategies and signals</p></li><li><p>Risk and capital allocation</p></li><li><p>Research tooling and methodology</p></li><li><p>In-depth model assumptions and derivations</p></li></ul><p>If this way of thinking resonates, you&#8217;ll probably like what I publish.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.vertoxquant.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">VertoxQuant is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>
      <p>
          <a href="https://www.vertoxquant.com/p/strategy-decay-detection">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[If you share this, you get paid back]]></title><description><![CDATA[Referral rewards are now live]]></description><link>https://www.vertoxquant.com/p/if-you-share-this-you-get-paid-back</link><guid isPermaLink="false">https://www.vertoxquant.com/p/if-you-share-this-you-get-paid-back</guid><dc:creator><![CDATA[Vertox]]></dc:creator><pubDate>Wed, 08 Apr 2026 10:52:46 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ufaQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb77b39-424b-4665-b2a7-7db519ff9e11_128x128.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The Substack grows almost entirely through word of mouth. So I&#8217;m rewarding people who share it: </p><ul><li><p>1 referral &#8594; 20% off</p></li><li><p>5 referrals &#8594; 1 month free</p></li><li><p>25 referrals &#8594; 6 months free</p></li></ul><p>If you&#8217;ve gotten value from it, help me grow by recommending it. It costs you nothing! </p><p>You can find your personal referral link at the bottom of this email or right here: </p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.vertoxquant.com/leaderboard&quot;,&quot;text&quot;:&quot;Leaderboard&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.vertoxquant.com/leaderboard"><span>Leaderboard</span></a></p><p>Thanks!</p><p>-Vertox</p>]]></content:encoded></item><item><title><![CDATA[Looking Inside The Black Box]]></title><description><![CDATA[Model-agnostic interpretable machine learning]]></description><link>https://www.vertoxquant.com/p/looking-inside-the-black-box</link><guid isPermaLink="false">https://www.vertoxquant.com/p/looking-inside-the-black-box</guid><dc:creator><![CDATA[Vertox]]></dc:creator><pubDate>Sun, 05 Apr 2026 01:24:47 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!JtoU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b1c8fb9-1162-43d1-8c86-ade28ac62021_889x390.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>People often criticise how ML models are just black boxes that take in some features and spit out a prediction. While some models (like linear regression) are naturally a lot more interpretable than others (like neural networks), it&#8217;s wrong that you can&#8217;t figure out why a model made a certain prediction and how the different features affect the prediction.</p><p>In this article, we will look at some useful model-agnostic methods (meaning that it doesn&#8217;t matter what model we apply it to) for figuring out why one specific prediction is what it is (Local Methods) and why predictions are what they are on average (Global Methods).</p><p>This is important for a few very important reasons.</p><ol><li><p><strong>Detecting problems in the model:</strong><br>Say you built a model that forecasts raw returns, and you see that the error has a lower error than some baseline model. A lot of people would quit here, but you dig deeper and find out that the only feature that matters to the model is volatility, and that the only thing that the model learned to do well is predict the magnitude of the return, not the sign. Suddenly, the model is completely useless for what it was supposed to do!</p></li><li><p><strong>Regulatory &amp; risk management requirements</strong>:</p><p>Regulators increasingly require that automated trading and risk models be explainable. If your model flags a position as too risky or generates a trade signal, compliance needs to know <em>why</em>. A black box doesn&#8217;t pass that bar.</p></li><li><p><strong>Detecting data leakage</strong>:</p><p>If your model is suspiciously good, interpretability tells you what it&#8217;s actually learning. Example: a return-prediction model that learned to exploit a look-ahead bias in a feature, e.g., using end-of-day prices to predict intraday moves, shows up immediately as one feature with overwhelming importance.</p></li><li><p><strong>Feature engineering feedback loop:</strong></p><p>Once you know which features are actually driving predictions, you can iterate intelligently; drop redundant factors, identify which alpha signals are being ignored, or understand why a signal that worked in research is being suppressed by the model in production.</p></li><li><p><strong>Regime analysis:</strong></p><p>Local methods let you compare <em>why</em> the model made a prediction in a bull market vs. a crisis period. If the feature importances shift dramatically across regimes, that&#8217;s a red flag for out-of-sample robustness; your model may have overfit to one regime&#8217;s dynamics.</p></li></ol><p>More interpretable models are often less accurate, and model-agnostic post-hoc methods let you have both: full model flexibility <em>and</em> explanations.</p><div><hr></div><p>I write about quantitative trading the way it&#8217;s actually practiced:<br>Robust models and portfolios, combining signals and strategies, understanding the assumptions behind your models.</p><p>More broadly, I write about:</p><ul><li><p>Statistical and cross-sectional arbitrage</p></li><li><p>Managing multiple strategies and signals</p></li><li><p>Risk and capital allocation</p></li><li><p>Research tooling and methodology</p></li><li><p>In-depth model assumptions and derivations</p></li></ul><p>If this way of thinking resonates, you&#8217;ll probably like what I publish.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.vertoxquant.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">VertoxQuant is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h1>1. Local Model-agnostic Methods</h1><p>Local methods answer a specific question: <strong>why did the model predict </strong><em><strong>this</strong></em><strong> value for </strong><em><strong>this</strong></em><strong> observation?</strong> Rather than summarising model behaviour across the entire dataset, they explain a single prediction by attributing it to the input features of that one data point.</p><p>Example: Your model predicts a large positive return for a particular asset on a particular day. A global method might tell you that momentum is generally the most important feature in your model. But a local method tells you that <em>for this specific prediction</em>, the signal was driven almost entirely by a spike in order flow imbalance, while momentum actually pushed the prediction slightly lower. That distinction matters enormously when you're trying to understand a model's live behaviour, debug an unexpected signal, or explain a specific trade to a risk committee.</p><p>Let&#8217;s go over some of the most popular methods.</p><h2>1.1 Ceteris Paribus Plots</h2><p>The name sounds really complicated, but it&#8217;s actually the simplest method you could use. Ceteris Paribus is Latin for "all other things being equal". As the name implies, to analyze a certain feature, you simply change its value while keeping all other features unchanged and look at the resulting predictions.</p><p>Before looking more into this method, let us train a model that we will keep using as an example for all methods. We will do a 1-day-ahead prediction of SPY returns using some basic features like momentum, RSI, etc. Doesn&#8217;t matter if the model is garbage as long as we can run our analysis on it.</p><p>First we load our data:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;e1bacc22-c222-48ca-865b-7a316c675030&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import yfinance as yf</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;17cfc353-cbba-42e1-b94a-4e3e6eecca22&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">def load_spy():
    df = yf.download("SPY", start="2010-01-01", end="2026-03-27", auto_adjust=True)
    df.columns = df.columns.droplevel(1)

    df["ret"] = df["Close"].pct_change()
    df["target"] = df["ret"].shift(-1)  # next-day return

    # Momentum
    df["mom_5"]   = df["ret"].rolling(5).mean()
    df["mom_20"]  = df["ret"].rolling(20).mean()
    df["mom_60"]  = df["ret"].rolling(60).mean()

    # Volatility
    df["vol_5"]   = df["ret"].rolling(5).std()
    df["vol_20"]  = df["ret"].rolling(20).std()
    df["vol_ratio"] = df["vol_5"] / df["vol_20"]  # vol regime indicator

    # Mean reversion
    df["rsi_14"]  = _rsi(df["Close"], 14)
    df["zscore_20"] = (df["Close"] - df["Close"].rolling(20).mean()) / df["Close"].rolling(20).std()

    # Volume
    df["volume_z"] = (df["Volume"] - df["Volume"].rolling(20).mean()) / df["Volume"].rolling(20).std()

    # Price-based
    df["hl_range"] = (df["High"] - df["Low"]) / df["Close"]  # normalized daily range
    df["gap"]      = (df["Open"] - df["Close"].shift(1)) / df["Close"].shift(1)  # overnight gap

    # Autocorrelation signal
    df["ret_lag1"] = df["ret"].shift(1)
    df["ret_lag2"] = df["ret"].shift(2)

    features = [
        "mom_5", "mom_20", "mom_60",
        "vol_5", "vol_20", "vol_ratio",
        "rsi_14", "zscore_20",
        "volume_z", "hl_range", "gap",
        "ret_lag1", "ret_lag2"
    ]

    df = df[["target"] + features].dropna()
    return df

def _rsi(close, period=14):
    delta = close.diff()
    gain = delta.clip(lower=0).rolling(period).mean()
    loss = (-delta.clip(upper=0)).rolling(period).mean()
    rs = gain / loss
    return 100 - (100 / (1 + rs))</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;3377e323-f1a3-47ba-a4d3-fa8e9ecec89d&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">df = load_spy()
df</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jDOZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb489db4-8418-4e59-b184-cb5451885de3_1167x424.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jDOZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb489db4-8418-4e59-b184-cb5451885de3_1167x424.png 424w, https://substackcdn.com/image/fetch/$s_!jDOZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb489db4-8418-4e59-b184-cb5451885de3_1167x424.png 848w, https://substackcdn.com/image/fetch/$s_!jDOZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb489db4-8418-4e59-b184-cb5451885de3_1167x424.png 1272w, https://substackcdn.com/image/fetch/$s_!jDOZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb489db4-8418-4e59-b184-cb5451885de3_1167x424.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jDOZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb489db4-8418-4e59-b184-cb5451885de3_1167x424.png" width="1167" height="424" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cb489db4-8418-4e59-b184-cb5451885de3_1167x424.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:424,&quot;width&quot;:1167,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:64232,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/193204015?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb489db4-8418-4e59-b184-cb5451885de3_1167x424.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!jDOZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb489db4-8418-4e59-b184-cb5451885de3_1167x424.png 424w, https://substackcdn.com/image/fetch/$s_!jDOZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb489db4-8418-4e59-b184-cb5451885de3_1167x424.png 848w, https://substackcdn.com/image/fetch/$s_!jDOZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb489db4-8418-4e59-b184-cb5451885de3_1167x424.png 1272w, https://substackcdn.com/image/fetch/$s_!jDOZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb489db4-8418-4e59-b184-cb5451885de3_1167x424.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>And now let&#8217;s train an XGBoost model to predict the next day&#8217;s return using our features (We won&#8217;t be doing any train-test splits or other important steps here, this is purely an exercise model!):</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;7996d73f-dfe5-4848-a589-5ce3937ef09b&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">from xgboost import XGBRegressor
from sklearn.metrics import r2_score</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;f02f950e-90c7-415d-a56d-9e1e043a8204&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">FEATURES = [c for c in df.columns if c != "target"]
X = df[FEATURES]
y = df["target"]
 
model = XGBRegressor(n_estimators=300, max_depth=4, learning_rate=0.05,
                     subsample=0.8, colsample_bytree=0.8, random_state=42)
model.fit(X, y)</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;d8267f57-3758-417a-80d6-0dc475ea5d72&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">preds = model.predict(X)
df["forecast"] = preds
df[["target", "forecast"]].to_csv("forecasts.csv")</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;0762b2ae-e10b-4338-9600-d5b44397e16e&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">Price         target  forecast
Date                          
2010-03-31  0.006837  0.000646
2010-04-01  0.008149  0.000556
2010-04-05  0.002358 -0.000046
2010-04-06 -0.005712  0.000146
2010-04-07  0.003464  0.001303</code></pre></div><p>Back to Ceteris Paribus.</p><p>Here is an implementation of it:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;78eca2f1-d68f-4656-9b0a-40bb0b491a51&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">def cp_profile(model, X, obs_idx, feature, n_points=100):
    x_obs = X.iloc[[obs_idx]].copy()
    grid = np.linspace(X[feature].min(), X[feature].max(), n_points)
    preds = []
    for val in grid:
        x_obs[feature] = val
        preds.append(model.predict(x_obs)[0])
    return grid, np.array(preds)</code></pre></div><p>Let&#8217;s try it on the 2026-03-03 prediction for the features "mom_20", "vol_20", "rsi_14", "zscore_20":</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;9ccb0edd-04b7-43df-8bc0-22b795c1b224&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">Price
target        0.007055
mom_5        -0.002033
mom_20       -0.001063
mom_60       -0.000015
vol_5         0.006754
vol_20        0.008314
vol_ratio     0.812388
rsi_14       39.089484
zscore_20    -1.367428
volume_z      1.027870
hl_range      0.019035
gap          -0.016492
ret_lag1      0.000569
ret_lag2     -0.004802
forecast      0.001172
Name: 2026-03-03 00:00:00, dtype: float64</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;8e836a53-08d3-4dfa-b7af-b522cddc6946&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">obs_idx = X.index.get_loc("2026-03-03")
features_to_plot = ["mom_20", "vol_20", "rsi_14", "zscore_20"]

fig, axes = plt.subplots(len(features_to_plot), 1, figsize=(9, 14))
fig.suptitle("Ceteris Paribus Profiles &#8212; SPY XGBoost (2026-03-01)", fontsize=14, fontweight="bold")

for ax, feat in zip(axes, features_to_plot):
    grid, preds = cp_profile(model, X, obs_idx, feat)
    ax.plot(grid, preds, linewidth=1.8)
    ax.axvline(X.iloc[obs_idx][feat], color="red", linestyle="--", label="observed value")
    ax.axhline(0, color="black", linewidth=0.8, linestyle="--")
    ax.set_xlabel(feat, fontsize=11)
    ax.set_ylabel("Predicted return", fontsize=10)
    ax.legend(fontsize=9)
    ax.grid(True, alpha=0.3)

plt.tight_layout()</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Wub_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8923b7db-7ec0-480e-8604-4adb9dd72c26_889x1377.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Wub_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8923b7db-7ec0-480e-8604-4adb9dd72c26_889x1377.png 424w, https://substackcdn.com/image/fetch/$s_!Wub_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8923b7db-7ec0-480e-8604-4adb9dd72c26_889x1377.png 848w, https://substackcdn.com/image/fetch/$s_!Wub_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8923b7db-7ec0-480e-8604-4adb9dd72c26_889x1377.png 1272w, https://substackcdn.com/image/fetch/$s_!Wub_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8923b7db-7ec0-480e-8604-4adb9dd72c26_889x1377.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Wub_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8923b7db-7ec0-480e-8604-4adb9dd72c26_889x1377.png" width="889" height="1377" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8923b7db-7ec0-480e-8604-4adb9dd72c26_889x1377.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1377,&quot;width&quot;:889,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:146329,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/193204015?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8923b7db-7ec0-480e-8604-4adb9dd72c26_889x1377.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Wub_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8923b7db-7ec0-480e-8604-4adb9dd72c26_889x1377.png 424w, https://substackcdn.com/image/fetch/$s_!Wub_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8923b7db-7ec0-480e-8604-4adb9dd72c26_889x1377.png 848w, https://substackcdn.com/image/fetch/$s_!Wub_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8923b7db-7ec0-480e-8604-4adb9dd72c26_889x1377.png 1272w, https://substackcdn.com/image/fetch/$s_!Wub_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8923b7db-7ec0-480e-8604-4adb9dd72c26_889x1377.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>If momentum were even more negative, we would have predicted an even more positive return (mean reversion effect).  If volatility were higher, we would have flipped to strongly negative instead (flipping from mean reversion to momentum).</p><p>Many of the methods we will look at are creative combinations of multiple Ceteris Paribus plots that tell us more.</p><p>The BIG problem with this (and many other) methods is correlation among features.<br>Changing one feature while keeping the others unchanged can give us unrealistic feature combinations, like huge recent momentum while volatility is very low.</p><h2>1.2 Individual Conditional Expectation (ICE)</h2><p>An ICE plot is simply many Ceteris Paribus plots overlaid, one per observation.</p><p>Here is an implementation:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;df548425-168c-4796-9605-9c79a2cfbee9&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">def ice_plot(model, X, feature, n_obs=100, n_points=100):
    sample = X.sample(n_obs, random_state=42)
    grid = np.linspace(X[feature].min(), X[feature].max(), n_points)
    
    fig, ax = plt.subplots(figsize=(9, 4))
    for idx in range(len(sample)):
        _, preds = cp_profile(model, sample.reset_index(drop=True), idx, feature, n_points)
        ax.plot(grid, preds, color="steelblue", alpha=0.4, linewidth=0.8)
    
    ax.axhline(0, color="black", linewidth=0.8, linestyle="--")
    ax.set_xlabel(feature)
    ax.set_ylabel("Predicted return")
    ax.grid(True, alpha=0.3)
    plt.title(f"ICE Plot &#8212; {feature}")
    plt.tight_layout()</code></pre></div><p>Let&#8217;s run it for &#8220;mom_20&#8221;:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;b560fb2a-969e-4b5b-afd8-1bb302ea2308&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">ice_plot(model, X, "mom_20")</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!luzM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F935753a8-53c8-4fc8-bc80-92b3c441f148_889x390.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!luzM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F935753a8-53c8-4fc8-bc80-92b3c441f148_889x390.png 424w, https://substackcdn.com/image/fetch/$s_!luzM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F935753a8-53c8-4fc8-bc80-92b3c441f148_889x390.png 848w, https://substackcdn.com/image/fetch/$s_!luzM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F935753a8-53c8-4fc8-bc80-92b3c441f148_889x390.png 1272w, https://substackcdn.com/image/fetch/$s_!luzM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F935753a8-53c8-4fc8-bc80-92b3c441f148_889x390.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!luzM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F935753a8-53c8-4fc8-bc80-92b3c441f148_889x390.png" width="889" height="390" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/935753a8-53c8-4fc8-bc80-92b3c441f148_889x390.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:390,&quot;width&quot;:889,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:89828,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/193204015?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F935753a8-53c8-4fc8-bc80-92b3c441f148_889x390.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!luzM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F935753a8-53c8-4fc8-bc80-92b3c441f148_889x390.png 424w, https://substackcdn.com/image/fetch/$s_!luzM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F935753a8-53c8-4fc8-bc80-92b3c441f148_889x390.png 848w, https://substackcdn.com/image/fetch/$s_!luzM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F935753a8-53c8-4fc8-bc80-92b3c441f148_889x390.png 1272w, https://substackcdn.com/image/fetch/$s_!luzM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F935753a8-53c8-4fc8-bc80-92b3c441f148_889x390.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>We can explore interactions with this method by using colors.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;27a011f1-9730-4adf-8291-97f58a0c38bc&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">def ice_plot(model, X, feature, color_by=None, n_obs=100, n_points=100):
    sample = X.sample(n_obs, random_state=42).reset_index(drop=True)
    grid = np.linspace(X[feature].quantile(0.01), X[feature].quantile(0.99), n_points)

    fig, ax = plt.subplots(figsize=(9, 4))
    for idx in range(len(sample)):
        _, preds = cp_profile(model, sample, idx, feature, n_points)
        if color_by is not None:
            median = sample[color_by].median()
            color = "#d62728" if sample[color_by].iloc[idx] &gt; median else "#1f77b4"
        else:
            color = "steelblue"
        ax.plot(grid, preds, color=color, alpha=0.4, linewidth=0.8)

    if color_by is not None:
        ax.plot([], [], color="#d62728", label=f"{color_by} high")
        ax.plot([], [], color="#1f77b4", label=f"{color_by} low")
        ax.legend(fontsize=9)

    ax.axhline(0, color="black", linewidth=0.8, linestyle="--")
    ax.set_xlabel(feature)
    ax.set_ylabel("Predicted return")
    ax.grid(True, alpha=0.3)
    plt.title(f"ICE Plot &#8212; {feature}" + (f" | colored by {color_by}" if color_by else ""))
    plt.tight_layout()</code></pre></div><p>Let&#8217;s color in low/high volatility:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;76383872-406c-42ac-a042-458bdb3989f2&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">ice_plot(model, X, "mom_20", "vol_20")</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6Zcg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00d16e2f-60f9-4eff-a86a-f78e881620e3_889x390.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6Zcg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00d16e2f-60f9-4eff-a86a-f78e881620e3_889x390.png 424w, https://substackcdn.com/image/fetch/$s_!6Zcg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00d16e2f-60f9-4eff-a86a-f78e881620e3_889x390.png 848w, https://substackcdn.com/image/fetch/$s_!6Zcg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00d16e2f-60f9-4eff-a86a-f78e881620e3_889x390.png 1272w, https://substackcdn.com/image/fetch/$s_!6Zcg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00d16e2f-60f9-4eff-a86a-f78e881620e3_889x390.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6Zcg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00d16e2f-60f9-4eff-a86a-f78e881620e3_889x390.png" width="889" height="390" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/00d16e2f-60f9-4eff-a86a-f78e881620e3_889x390.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:390,&quot;width&quot;:889,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:101474,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/193204015?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00d16e2f-60f9-4eff-a86a-f78e881620e3_889x390.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6Zcg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00d16e2f-60f9-4eff-a86a-f78e881620e3_889x390.png 424w, https://substackcdn.com/image/fetch/$s_!6Zcg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00d16e2f-60f9-4eff-a86a-f78e881620e3_889x390.png 848w, https://substackcdn.com/image/fetch/$s_!6Zcg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00d16e2f-60f9-4eff-a86a-f78e881620e3_889x390.png 1272w, https://substackcdn.com/image/fetch/$s_!6Zcg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00d16e2f-60f9-4eff-a86a-f78e881620e3_889x390.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Centered ICE Plot:</h3><p>It can be hard to tell if the different curves are affected equally by the feature of interest because they have different levels.</p><p>A simple solution is to subtract each curve's value at some specific value of x. This removes the vertical spread caused by other features and lets you focus purely on the effect of varying the feature of interest.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;d3b296e6-d85f-41a0-8f63-1a5dddf22222&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">def cp_profile(model, X, obs_idx, feature, grid):
    x_obs = X.iloc[[obs_idx]].copy()
    preds = [model.predict(x_obs.assign(**{feature: val}))[0] for val in grid]
    return np.array(preds)

def ice_plot(model, X, feature, color_by=None, centered=False, ref_value=None, n_obs=100, n_points=100):
    sample = X.sample(n_obs, random_state=42).reset_index(drop=True)
    grid = np.linspace(X[feature].quantile(0.01), X[feature].quantile(0.99), n_points)
    if centered and ref_value is not None:
        grid = np.sort(np.append(grid, ref_value))  # ensure ref_value is exactly in grid

    fig, ax = plt.subplots(figsize=(9, 4))
    for idx in range(len(sample)):
        preds = cp_profile(model, sample, idx, feature, grid)
        if centered:
            ref = ref_value if ref_value is not None else grid[0]
            ref_pred = preds[np.searchsorted(grid, ref)]
            preds = preds - ref_pred
        color = "steelblue"
        if color_by is not None:
            color = "#d62728" if sample[color_by].iloc[idx] &gt; sample[color_by].median() else "#1f77b4"
        ax.plot(grid, preds, color=color, alpha=0.3, linewidth=0.8)

    if color_by is not None:
        ax.plot([], [], color="#d62728", label=f"{color_by} high")
        ax.plot([], [], color="#1f77b4", label=f"{color_by} low")
        ax.legend(fontsize=9)

    ax.axhline(0, color="black", linewidth=0.8, linestyle="--")
    ax.set_xlabel(feature)
    ax.set_ylabel("Change in predicted return" if centered else "Predicted return")
    ax.grid(True, alpha=0.3)
    plt.title(f"{'c-ICE' if centered else 'ICE'} Plot &#8212; {feature}" + (f" | colored by {color_by}" if color_by else ""))
    plt.tight_layout()</code></pre></div><p>A natural reference point for momentum is 0:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;34ff0696-eb56-43d3-aeac-96af1f906251&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">ice_plot(model, X, "mom_20", "vol_20", centered=True, ref_value=0)</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JtoU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b1c8fb9-1162-43d1-8c86-ade28ac62021_889x390.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JtoU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b1c8fb9-1162-43d1-8c86-ade28ac62021_889x390.png 424w, https://substackcdn.com/image/fetch/$s_!JtoU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b1c8fb9-1162-43d1-8c86-ade28ac62021_889x390.png 848w, https://substackcdn.com/image/fetch/$s_!JtoU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b1c8fb9-1162-43d1-8c86-ade28ac62021_889x390.png 1272w, https://substackcdn.com/image/fetch/$s_!JtoU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b1c8fb9-1162-43d1-8c86-ade28ac62021_889x390.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JtoU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b1c8fb9-1162-43d1-8c86-ade28ac62021_889x390.png" width="889" height="390" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3b1c8fb9-1162-43d1-8c86-ade28ac62021_889x390.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:390,&quot;width&quot;:889,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:108287,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/193204015?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b1c8fb9-1162-43d1-8c86-ade28ac62021_889x390.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!JtoU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b1c8fb9-1162-43d1-8c86-ade28ac62021_889x390.png 424w, https://substackcdn.com/image/fetch/$s_!JtoU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b1c8fb9-1162-43d1-8c86-ade28ac62021_889x390.png 848w, https://substackcdn.com/image/fetch/$s_!JtoU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b1c8fb9-1162-43d1-8c86-ade28ac62021_889x390.png 1272w, https://substackcdn.com/image/fetch/$s_!JtoU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b1c8fb9-1162-43d1-8c86-ade28ac62021_889x390.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Can see a pretty clear pattern on the left! When volatility is high, momentum works. When volatility is low, mean reversion works.</p><h2>1.3 Local interpretable model-agnostic explanations (LIME)</h2><p>CP profiles and ICE show you how the prediction changes as you vary one feature. But they don&#8217;t give you a single number answering: <em><strong>how much did feature x contribute to this specific prediction?</strong></em> LIME does exactly that.</p><p>The basic idea is that our black box method f is too complex to interpret globally, so we interpret near a specific observation x (all our features at one specific date) by training a simpler model (for example linear) in a small neighborhood of x.</p><p>Here is how LIME does this exactly (using linear regression as an example for the interpretable model):</p><ol><li><p><strong>Perturbing the observation:</strong><br>Generate N synthetic samples by randomly perturbing the features around x. For tabular data, this is done by sampling each feature from its marginal distribution. For continuous data, this is done by sampling from a normal distribution with equal means and standard deviations to the training set (This again ignores correlations! A typical weakness of LIME).</p></li><li><p><strong>Weighing by proximity:<br></strong>Each synthetic sample z is weighted by how close it is to x using an exponential kernel:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\pi_x(z) = \\exp(-\\frac{d(x,z)^2}{\\sigma^2})&quot;,&quot;id&quot;:&quot;LEIOEOAQFB&quot;}" data-component-name="LatexBlockToDOM"></div><p>In our case, d will be euclidian distance, but other measures of distance can be chosen too.</p></li><li><p><strong>Fitting a weighted linear model:<br></strong>Run the black-box model on all synthetic samples to get labels, then fit a weighted linear regression:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\hat{g} = \\arg \\min_g \\sum_z \\pi_x(z) (\\hat{f}(z) - g(z))^2&quot;,&quot;id&quot;:&quot;RDDSQYLKUL&quot;}" data-component-name="LatexBlockToDOM"></div></li><li><p><strong>Reading the explanation:</strong><br>Now we interpret the resulting model. In the case of linear regression, that&#8217;s easy, as we simply look at the coefficients.</p></li></ol><p>Let&#8217;s implement this with ridge regression, which handles our correlated features better:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;91cabe3b-eeeb-47ff-8182-4f8202c3abb2&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">def lime_explain(model, X, obs_idx, n_samples=1000, sigma=1.0, ridge_alpha=1.0):
    x_obs = X.iloc[obs_idx].values
    means = X.mean().values
    stds  = X.std().values

    # 1. perturb
    Z = np.random.normal(means, stds, size=(n_samples, X.shape[1]))

    # 2. weights
    Z_std = (Z - x_obs) / stds
    distances = np.sqrt((Z_std ** 2).sum(axis=1))
    weights = np.exp(-distances ** 2 / sigma ** 2)

    # 3. black-box labels
    labels = model.predict(Z)

    # 4. fit weighted linear model
    lr = Ridge(alpha=ridge_alpha)
    lr.fit(Z, labels, sample_weight=weights)

    return dict(zip(X.columns, lr.coef_))</code></pre></div><p>And run it again for our 2026-03-03 forecast:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;8d33caa2-4341-47de-b038-3b8d2535e695&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">obs_idx = X.index.get_loc("2026-03-03")
explanation = lime_explain(model, X, obs_idx)
print(explanation)</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;6109c00f-163c-4e26-bf7c-a640072f7662&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">mom_5       -2.096855e-09
mom_20      -4.942316e-09
mom_60       4.846428e-09
vol_5        4.087705e-08
vol_20       1.238100e-08
vol_ratio    5.578009e-07
rsi_14      -1.130377e-05
zscore_20   -2.909305e-06
volume_z    -1.143078e-06
hl_range    -4.011315e-08
gap          2.016699e-08
ret_lag1     1.007680e-08
ret_lag2     5.326466e-08</code></pre></div><p>Another challenge in using LIME is choosing the neighborhood of x. There is no clear solution to this, and results can generally be unstable as well.</p><h2>1.4 SHAP</h2><p>SHAP (SHapley Additive exPlanations) is a game-theoretic approach.</p><p>The question SHAP asks is: Given that the model made a prediction hat{y}, how do we <em>fairly </em>distribute the difference between this prediction and the average prediction E[y] among the features?</p><p>Think of the features as players in a cooperative game, where the "payout" is the model's prediction. The Shapley value of feature j is its average marginal contribution across all possible orderings (coalitions) of features:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\phi_j = \\sum_{S \\subseteq F\\backslash\\{j\\}} \\frac{|S|!(|F|-|S|-1)!}{|F|!}[\\hat{f}_{S \\cup \\{j\\}}(x) - \\hat{f}_S(x)]&quot;,&quot;id&quot;:&quot;COTPSRDXXZ&quot;}" data-component-name="LatexBlockToDOM"></div><p>where F is the full set of features, S is a subset excluding feature j, and \hat{f}_S is the model&#8217;s prediction using only features in S.</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\hat{f}_S(x) = \\mathbb{E}[\\hat{f}(z)|z_S = x_S]&quot;,&quot;id&quot;:&quot;TKMCYJIDYK&quot;}" data-component-name="LatexBlockToDOM"></div><p>The Shapley values must satisfy the following four properties (and is the only attribution method that does so):</p><h4><strong>Efficiency:</strong></h4><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\hat{f}(x) = \\mathbb{E}[\\hat{f}(\\cdot)] + \\sum_{j=1}^p \\phi_j,&quot;,&quot;id&quot;:&quot;HAVFZWFTTS&quot;}" data-component-name="LatexBlockToDOM"></div><p>so the contributions exactly decompose the prediction relative to the baseline.</p><h4><strong>Symmetry:</strong></h4><p>If two features j and k contribute equally to every coalition, i.e., for all</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;S \\subseteq F \\backslash \\{j,k\\}&quot;,&quot;id&quot;:&quot;YYQGEUTQYP&quot;}" data-component-name="LatexBlockToDOM"></div><p>we have</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\hat{f}_{S \\cup \\{j\\}} = \\hat{f}_{S \\cup \\{k\\}}&quot;,&quot;id&quot;:&quot;JQWTCHBJCC&quot;}" data-component-name="LatexBlockToDOM"></div><p>then they must have the same Shapley value</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\phi_j = \\phi_k.&quot;,&quot;id&quot;:&quot;PFAWISJVSM&quot;}" data-component-name="LatexBlockToDOM"></div><h4><strong>Dummy:</strong></h4><p>If feature j contributes nothing to any coalition, i.e., for all </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;S \\subseteq F \\backslash \\{j\\}&quot;,&quot;id&quot;:&quot;LPTPXGWUNJ&quot;}" data-component-name="LatexBlockToDOM"></div><p>we have</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\hat{f}_{S \\cup \\{j\\}} = \\hat{f}_S&quot;,&quot;id&quot;:&quot;BIUHFHRWVZ&quot;}" data-component-name="LatexBlockToDOM"></div><p>then the Shapley value must be zero </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\phi_j = 0.&quot;,&quot;id&quot;:&quot;DWYTWKAGVN&quot;}" data-component-name="LatexBlockToDOM"></div><h4><strong>Linearity:</strong></h4><p>If the model can be decomposed as f = f^A + f^B, then</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\phi_j(\\hat{f}) = \\phi_j(\\hat{f}^A) + \\phi_j(\\hat{f}^B)&quot;,&quot;id&quot;:&quot;GOPIIZAUZV&quot;}" data-component-name="LatexBlockToDOM"></div><h3>Estimating Shapley values:</h3><p>The number of possible coalitions increases exponentially as you increase the number of features in your model (2^|F|). You therefore typically want to approximate it via Monte-Carlo sampling. Instead of summing over all coalitions, sample random permutations pi of the features and estimate the marginal contribution of j in each:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\hat{f}_j = \\frac{1}{M} \\sum_{m=1}^M [\\hat{f}_{S^m \\cup \\{j\\}}(x) - \\hat{f}_{S^m}(x)]&quot;,&quot;id&quot;:&quot;KTDITHEJQC&quot;}" data-component-name="LatexBlockToDOM"></div><p>where S^m is the set of features appearing before j in the m-th random permutation. This converges to the true Shapley value as M &#8594; infinity.</p><p>You want M to be reasonably big, so the variance of your estimated Shapley value is small. This means that for big models doing a SHAP analysis can take a long time, which is one major drawback of it.</p><p>For tree-based models (XGBoost, LightGBM, Random Forests, etc.), there is an exact polynomial-time algorithm that exploits the tree structure to compute exact Shapley values in O(TLD^2) time, where T is the number of trees, L is the number of leaves, and D is the maximum depth.</p><p>Let&#8217;s implement this with the shap library. There are a ton of useful tools!</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;6a2cb586-4bdc-4ac9-8df1-c3b196f2e1d9&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">import shap
import copy

explainer  = shap.TreeExplainer(model)
shap_values = explainer(X)

obs_idx = X.index.get_loc("2026-03-03")

# Transforming to basis-points for better readability
sv_bps = copy.deepcopy(shap_values)
sv_bps.values = shap_values.values * 10000
sv_bps.base_values = shap_values.base_values * 10000
sv_bps.data = shap_values.data</code></pre></div><h3>waterfall_plot:</h3><p>Shows how each feature pushes the prediction up/down from the baseline E[f(.)] to the final prediction f(x).</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;c3f41532-2a65-4b79-8dd8-c71e78ba8f2c&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">shap.waterfall_plot(sv_bps[obs_idx])</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!evMK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4ec5ae5-d9ee-4ba1-bf70-8a63b1b3769e_893x600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!evMK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4ec5ae5-d9ee-4ba1-bf70-8a63b1b3769e_893x600.png 424w, https://substackcdn.com/image/fetch/$s_!evMK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4ec5ae5-d9ee-4ba1-bf70-8a63b1b3769e_893x600.png 848w, https://substackcdn.com/image/fetch/$s_!evMK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4ec5ae5-d9ee-4ba1-bf70-8a63b1b3769e_893x600.png 1272w, https://substackcdn.com/image/fetch/$s_!evMK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4ec5ae5-d9ee-4ba1-bf70-8a63b1b3769e_893x600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!evMK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4ec5ae5-d9ee-4ba1-bf70-8a63b1b3769e_893x600.png" width="893" height="600" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f4ec5ae5-d9ee-4ba1-bf70-8a63b1b3769e_893x600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:893,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:59079,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/193204015?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4ec5ae5-d9ee-4ba1-bf70-8a63b1b3769e_893x600.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!evMK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4ec5ae5-d9ee-4ba1-bf70-8a63b1b3769e_893x600.png 424w, https://substackcdn.com/image/fetch/$s_!evMK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4ec5ae5-d9ee-4ba1-bf70-8a63b1b3769e_893x600.png 848w, https://substackcdn.com/image/fetch/$s_!evMK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4ec5ae5-d9ee-4ba1-bf70-8a63b1b3769e_893x600.png 1272w, https://substackcdn.com/image/fetch/$s_!evMK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4ec5ae5-d9ee-4ba1-bf70-8a63b1b3769e_893x600.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>As you can see, momentum pushed the prediction in one direction, but volume_z and RSI pushed it back in the other direction.</p><h3>force_plot:</h3><p>Same information as waterfall, but horizontal.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;d86d6018-7cf9-4a6a-80b4-c4f97b0722ba&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">shap.initjs()
shap.force_plot(sv_bps[obs_idx])</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Xyiw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41aa8f9a-f2ce-465f-ad0c-7f5d42d08c74_1146x112.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Xyiw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41aa8f9a-f2ce-465f-ad0c-7f5d42d08c74_1146x112.png 424w, https://substackcdn.com/image/fetch/$s_!Xyiw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41aa8f9a-f2ce-465f-ad0c-7f5d42d08c74_1146x112.png 848w, https://substackcdn.com/image/fetch/$s_!Xyiw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41aa8f9a-f2ce-465f-ad0c-7f5d42d08c74_1146x112.png 1272w, https://substackcdn.com/image/fetch/$s_!Xyiw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41aa8f9a-f2ce-465f-ad0c-7f5d42d08c74_1146x112.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Xyiw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41aa8f9a-f2ce-465f-ad0c-7f5d42d08c74_1146x112.png" width="1146" height="112" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/41aa8f9a-f2ce-465f-ad0c-7f5d42d08c74_1146x112.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:112,&quot;width&quot;:1146,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:24118,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/193204015?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41aa8f9a-f2ce-465f-ad0c-7f5d42d08c74_1146x112.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Xyiw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41aa8f9a-f2ce-465f-ad0c-7f5d42d08c74_1146x112.png 424w, https://substackcdn.com/image/fetch/$s_!Xyiw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41aa8f9a-f2ce-465f-ad0c-7f5d42d08c74_1146x112.png 848w, https://substackcdn.com/image/fetch/$s_!Xyiw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41aa8f9a-f2ce-465f-ad0c-7f5d42d08c74_1146x112.png 1272w, https://substackcdn.com/image/fetch/$s_!Xyiw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41aa8f9a-f2ce-465f-ad0c-7f5d42d08c74_1146x112.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h3>decision_plot:</h3><p>Also gives the same information by showing the cumulative sum of SHAP values as a path from the baseline E[f(.)] to the final prediction.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;e2f8c33f-c6e2-4a84-a89b-801a54e077ea&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">shap.decision_plot(explainer.expected_value, shap_values[obs_idx].values, X.iloc[obs_idx])</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_Pw7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F651e9932-4b80-4319-9b4c-92f3bfaec0f3_763x608.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_Pw7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F651e9932-4b80-4319-9b4c-92f3bfaec0f3_763x608.png 424w, https://substackcdn.com/image/fetch/$s_!_Pw7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F651e9932-4b80-4319-9b4c-92f3bfaec0f3_763x608.png 848w, https://substackcdn.com/image/fetch/$s_!_Pw7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F651e9932-4b80-4319-9b4c-92f3bfaec0f3_763x608.png 1272w, https://substackcdn.com/image/fetch/$s_!_Pw7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F651e9932-4b80-4319-9b4c-92f3bfaec0f3_763x608.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_Pw7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F651e9932-4b80-4319-9b4c-92f3bfaec0f3_763x608.png" width="763" height="608" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/651e9932-4b80-4319-9b4c-92f3bfaec0f3_763x608.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:608,&quot;width&quot;:763,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:67871,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/193204015?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F651e9932-4b80-4319-9b4c-92f3bfaec0f3_763x608.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!_Pw7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F651e9932-4b80-4319-9b4c-92f3bfaec0f3_763x608.png 424w, https://substackcdn.com/image/fetch/$s_!_Pw7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F651e9932-4b80-4319-9b4c-92f3bfaec0f3_763x608.png 848w, https://substackcdn.com/image/fetch/$s_!_Pw7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F651e9932-4b80-4319-9b4c-92f3bfaec0f3_763x608.png 1272w, https://substackcdn.com/image/fetch/$s_!_Pw7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F651e9932-4b80-4319-9b4c-92f3bfaec0f3_763x608.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>You can also pass multiple observations to compare them side by side:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;31c78cec-6f17-4a3d-ab97-9feb744e567e&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">shap.decision_plot(explainer.expected_value, shap_values.values[:50], X.iloc[:50])</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vKqo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F559ef0e3-097b-4204-b531-15a608278919_739x608.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vKqo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F559ef0e3-097b-4204-b531-15a608278919_739x608.png 424w, https://substackcdn.com/image/fetch/$s_!vKqo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F559ef0e3-097b-4204-b531-15a608278919_739x608.png 848w, https://substackcdn.com/image/fetch/$s_!vKqo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F559ef0e3-097b-4204-b531-15a608278919_739x608.png 1272w, https://substackcdn.com/image/fetch/$s_!vKqo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F559ef0e3-097b-4204-b531-15a608278919_739x608.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vKqo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F559ef0e3-097b-4204-b531-15a608278919_739x608.png" width="739" height="608" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/559ef0e3-097b-4204-b531-15a608278919_739x608.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:608,&quot;width&quot;:739,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:157119,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/193204015?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F559ef0e3-097b-4204-b531-15a608278919_739x608.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!vKqo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F559ef0e3-097b-4204-b531-15a608278919_739x608.png 424w, https://substackcdn.com/image/fetch/$s_!vKqo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F559ef0e3-097b-4204-b531-15a608278919_739x608.png 848w, https://substackcdn.com/image/fetch/$s_!vKqo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F559ef0e3-097b-4204-b531-15a608278919_739x608.png 1272w, https://substackcdn.com/image/fetch/$s_!vKqo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F559ef0e3-097b-4204-b531-15a608278919_739x608.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>We will get back to SHAP again when looking at global model-agnostic methods!</p><div><hr></div><h1>2. Global Model-agnostic Methods</h1><p>Global methods answer a different question: not why did the model predict <em>this</em> value for <em>this</em> observation, but how does the model behave <em>on average</em> across the entire dataset? Rather than explaining a single prediction, they summarise the overall relationship between features and the target learned by the model.</p><p>Example: You&#8217;ve trained a return-forecasting model on SPY, and it performs well out of sample. A local method tells you why the model predicted a large positive return on one specific day. But a global method tells you that across all predictions, volatility is the dominant driver, momentum matters mainly in low-volatility regimes, and the overnight gap feature is essentially ignored by the model. </p><p>Let&#8217;s go over some of the most popular methods.</p><h2>2.1 Partial Dependence Plot (PDP)</h2><p>Remember Individual Conditional Expectation (ICE)? PDP is simply the average of all ICE curves. This also means the PDP inherits the main weakness of ICE: It assumes the feature is independent of the others.</p><p>Just like with ICE, a centered version also exists. Let&#8217;s implement it as a thick line inside our centered ICE plot:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;17e64388-a293-407b-aea7-842aff3d1735&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">def ice_plot(model, X, feature, color_by=None, centered=False, ref_value=None, n_obs=100, n_points=100):
    sample = X.sample(n_obs, random_state=42).reset_index(drop=True)
    grid = np.linspace(X[feature].quantile(0.01), X[feature].quantile(0.99), n_points)
    if centered and ref_value is not None:
        grid = np.sort(np.append(grid, ref_value))

    fig, ax = plt.subplots(figsize=(9, 4))
    all_preds = []
    for idx in range(len(sample)):
        preds = cp_profile(model, sample, idx, feature, grid)
        if centered:
            ref = ref_value if ref_value is not None else grid[0]
            ref_pred = preds[np.searchsorted(grid, ref)]
            preds = preds - ref_pred
        all_preds.append(preds)
        color = "steelblue"
        if color_by is not None:
            color = "#d62728" if sample[color_by].iloc[idx] &gt; sample[color_by].median() else "#1f77b4"
        ax.plot(grid, preds, color=color, alpha=0.3, linewidth=0.8)

    pdp = np.mean(all_preds, axis=0)
    ax.plot(grid, pdp, color="black", linewidth=2.5, label="PDP")

    if color_by is not None:
        ax.plot([], [], color="#d62728", label=f"{color_by} high")
        ax.plot([], [], color="#1f77b4", label=f"{color_by} low")

    ax.legend(fontsize=9)
    ax.axhline(0, color="black", linewidth=0.8, linestyle="--")
    ax.set_xlabel(feature)
    ax.set_ylabel("Change in predicted return" if centered else "Predicted return")
    ax.grid(True, alpha=0.3)
    plt.title(f"{'c-ICE' if centered else 'ICE'} Plot &#8212; {feature}" + (f" | colored by {color_by}" if color_by else ""))
    plt.tight_layout()</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;a9e46e79-2c47-41cf-8e75-653897460f9d&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">ice_plot(model, X, "mom_20", "vol_20", centered=True, ref_value=0)</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!g00b!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da03327-5ad3-43cd-9726-64a53f05bf02_889x390.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!g00b!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da03327-5ad3-43cd-9726-64a53f05bf02_889x390.png 424w, https://substackcdn.com/image/fetch/$s_!g00b!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da03327-5ad3-43cd-9726-64a53f05bf02_889x390.png 848w, https://substackcdn.com/image/fetch/$s_!g00b!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da03327-5ad3-43cd-9726-64a53f05bf02_889x390.png 1272w, https://substackcdn.com/image/fetch/$s_!g00b!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da03327-5ad3-43cd-9726-64a53f05bf02_889x390.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!g00b!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da03327-5ad3-43cd-9726-64a53f05bf02_889x390.png" width="889" height="390" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6da03327-5ad3-43cd-9726-64a53f05bf02_889x390.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:390,&quot;width&quot;:889,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:107936,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/193204015?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da03327-5ad3-43cd-9726-64a53f05bf02_889x390.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!g00b!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da03327-5ad3-43cd-9726-64a53f05bf02_889x390.png 424w, https://substackcdn.com/image/fetch/$s_!g00b!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da03327-5ad3-43cd-9726-64a53f05bf02_889x390.png 848w, https://substackcdn.com/image/fetch/$s_!g00b!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da03327-5ad3-43cd-9726-64a53f05bf02_889x390.png 1272w, https://substackcdn.com/image/fetch/$s_!g00b!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6da03327-5ad3-43cd-9726-64a53f05bf02_889x390.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>2.2 Accumulated Local Effects (ALE)</h2><p>PDP&#8217;s main weakness is that it sweeps feature x_j across its range while holding other features fixed at their observed values, generating unrealistic feature combinations when features are correlated. ALE fixes this by only looking at the effect of x_j locally, within small neighbourhoods where the feature combinations are realistics, and then accumulating these local effects to get a global picture.</p><p>Partition the range of x_j into K intervals [z_{k-1}, z_k]. For each interval, compute the local effect of x_j by averaging the finite difference of predictions over observations that actually fall in that interval:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\text{ALE}_j(x) = \\sum_{k=1}^{K(x)} \\frac{1}{n_k} \\sum_{i:x_j^{(i)} \\in [z_{k-1}, z_k]}[\\hat{f}(x_{-j}^{(i)}, z_k) - \\hat{f}(x_{-j}^{(i)},z_{k-1})]&quot;,&quot;id&quot;:&quot;CIPJLBIVEZ&quot;}" data-component-name="LatexBlockToDOM"></div><p>where K(x) is the index of the inerval containing x, and n_k is the number of observations in interval k. x_{-j}^(i), z_k means that the j-th feature value in x^(i) got replaced with z_k (here i stays for the i-th observation).</p><p>Let&#8217;s implement this:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;3a64c849-4ca7-420a-8a06-28295552042c&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">def ale_plot(model, X, feature, n_bins=20):
    quantiles = np.quantile(X[feature], np.linspace(0, 1, n_bins + 1))
    quantiles = np.unique(quantiles)

    ale = np.zeros(len(quantiles) - 1)
    bin_centers = np.zeros(len(quantiles) - 1)

    for k in range(len(quantiles) - 1):
        mask = (X[feature] &gt;= quantiles[k]) &amp; (X[feature] &lt; quantiles[k + 1])
        if mask.sum() == 0:
            continue
        X_bin = X[mask].copy()
        preds_high = model.predict(X_bin.assign(**{feature: quantiles[k + 1]}))
        preds_low  = model.predict(X_bin.assign(**{feature: quantiles[k]}))
        ale[k] = (preds_high - preds_low).mean()
        bin_centers[k] = (quantiles[k] + quantiles[k + 1]) / 2

    ale = np.cumsum(ale)
    ale -= ale.mean()

    fig, ax = plt.subplots(figsize=(9, 4))
    ax.plot(bin_centers, ale, color="steelblue", linewidth=2)
    ax.axhline(0, color="black", linewidth=0.8, linestyle="--")
    ax.set_xlabel(feature)
    ax.set_ylabel("ALE")
    ax.grid(True, alpha=0.3)
    plt.title(f"ALE Plot &#8212; {feature}")
    plt.tight_layout()</code></pre></div><p>And run it for &#8220;mom_20&#8221;:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jX8_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feda6d14e-23d7-4250-a2e7-c39a0de11a7a_887x390.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jX8_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feda6d14e-23d7-4250-a2e7-c39a0de11a7a_887x390.png 424w, https://substackcdn.com/image/fetch/$s_!jX8_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feda6d14e-23d7-4250-a2e7-c39a0de11a7a_887x390.png 848w, https://substackcdn.com/image/fetch/$s_!jX8_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feda6d14e-23d7-4250-a2e7-c39a0de11a7a_887x390.png 1272w, https://substackcdn.com/image/fetch/$s_!jX8_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feda6d14e-23d7-4250-a2e7-c39a0de11a7a_887x390.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jX8_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feda6d14e-23d7-4250-a2e7-c39a0de11a7a_887x390.png" width="887" height="390" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/eda6d14e-23d7-4250-a2e7-c39a0de11a7a_887x390.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:390,&quot;width&quot;:887,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:37025,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/193204015?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feda6d14e-23d7-4250-a2e7-c39a0de11a7a_887x390.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!jX8_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feda6d14e-23d7-4250-a2e7-c39a0de11a7a_887x390.png 424w, https://substackcdn.com/image/fetch/$s_!jX8_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feda6d14e-23d7-4250-a2e7-c39a0de11a7a_887x390.png 848w, https://substackcdn.com/image/fetch/$s_!jX8_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feda6d14e-23d7-4250-a2e7-c39a0de11a7a_887x390.png 1272w, https://substackcdn.com/image/fetch/$s_!jX8_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feda6d14e-23d7-4250-a2e7-c39a0de11a7a_887x390.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>2.3 Friedman&#8217;s H statistic</h2><p>So far, all methods look at the effect of one feature at a time. But in practice, features often interact; the effect of mom_20 on the prediction might be very different in high-volatility vs low-volatility regimes. Friedman&#8217;s H-statistic measures the strength of such interactions.</p><p>If two features x_j and x_k do not interact, then the point partial dependence can be decomposed as the sum of the individual partial dependences:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\text{PDP}_{jk}(x_j, x_k) = \\text{PDP}_j(x_j) + \\text{PDP}_k(x_k)&quot;,&quot;id&quot;:&quot;GBLEPNIBDD&quot;}" data-component-name="LatexBlockToDOM"></div><p>The H-statistic measures how much of the joint PDP&#8217;s variance is <em><strong>not </strong></em>explained by the sum of the individual PDPs:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;H_{jk}^2 = \\frac{\\sum_{i=1}^n[\\text{PDP}_{jk}(x_j^{(i)},x_k^{(i)})-\\text{PDP}_j(x_j^{(i)})-\\text{PDP}_k(x_k^{(i)})]^2}{\\sum_{i=1}^n [\\text{PDP}_{jk}(x_j^{(i)}, x_k^{(i)})]^2}&quot;,&quot;id&quot;:&quot;NOLSXKAGHC&quot;}" data-component-name="LatexBlockToDOM"></div><p>H_{jk}^2 is in [0,1], where 0 means no interaction and 1 means the entire joint effect is due to interaction.</p><p>There is also a <em><strong>total </strong></em>interaction statistic for feature j measuring its interaction with <em><strong>all</strong></em> other features simultaneously:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;H_j^2 = \\frac{\\sum_{i=1}^n[\\text{PDP}_j(x_j^{(i)})-\\hat{f}(x^{(i)})+\\text{PDP}_{-j}(x_{-j}^{(i)})]^2}{\\sum_{i=1}^n \\hat{f}(x^{(i)})^2}&quot;,&quot;id&quot;:&quot;HMBBLNAZRM&quot;}" data-component-name="LatexBlockToDOM"></div><p>Let&#8217;s implement both:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;0b3070e2-4027-4b4b-af37-c073ea5f3a7f&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">from sklearn.inspection import partial_dependence

def h_stat_pairwise(model, X, feat1, feat2, n_samples=500):
    X_s = X.sample(n_samples, random_state=42)
    
    pd12 = partial_dependence(model, X_s, [feat1, feat2], kind="average", grid_resolution=20)
    pd1  = partial_dependence(model, X_s, [feat1], kind="average", grid_resolution=20)
    pd2  = partial_dependence(model, X_s, [feat2], kind="average", grid_resolution=20)
    
    grid1 = pd12["grid_values"][0]
    grid2 = pd12["grid_values"][1]
    joint = pd12["average"][0]
    
    joint -= joint.mean()
    v1 = pd1["average"][0] - pd1["average"][0].mean()
    v2 = pd2["average"][0] - pd2["average"][0].mean()
    
    numerator, denominator = 0.0, 0.0
    for _, row in X_s.iterrows():
        f12 = joint[np.argmin(np.abs(grid1 - row[feat1])), np.argmin(np.abs(grid2 - row[feat2]))]
        f1  = v1[np.argmin(np.abs(pd1["grid_values"][0] - row[feat1]))]
        f2  = v2[np.argmin(np.abs(pd2["grid_values"][0] - row[feat2]))]
        numerator   += (f12 - f1 - f2) ** 2
        denominator += f12 ** 2
    
    return np.sqrt(numerator / denominator)

def h_stat_total(model, X, feature, n_samples=500):
    X_s = X.sample(n_samples, random_state=42).reset_index(drop=True)
    
    f_hats = model.predict(X_s)
    
    # PD_j: marginalise out all features except j (standard 1D PDP)
    pd_j = partial_dependence(model, X_s, [feature], kind="average", grid_resolution=20)
    grid_j = pd_j["grid_values"][0]
    v_j = pd_j["average"][0]

    # PD_{-j}: for each observation, fix x_{-j} and average over x_j
    pd_minus_j = np.zeros(len(X_s))
    for idx in range(len(X_s)):
        X_temp = X_s.copy()
        X_temp[feature] = X_s[feature]  # vary x_j over training dist
        X_temp.loc[:, [c for c in X_s.columns if c != feature]] = \
            X_s.iloc[idx][[c for c in X_s.columns if c != feature]].values
        pd_minus_j[idx] = model.predict(X_temp).mean()

    numerator, denominator = 0.0, 0.0
    for idx, (_, row) in enumerate(X_s.iterrows()):
        fj    = v_j[np.argmin(np.abs(grid_j - row[feature]))]
        f_hat = f_hats[idx]
        numerator   += (f_hat - fj - pd_minus_j[idx]) ** 2
        denominator += f_hat ** 2

    return np.sqrt(numerator / denominator)</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;152741a3-b54b-471d-95be-0f97776390bf&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">from tqdm import tqdm
import seaborn as sns

features = X.columns.tolist()
h_matrix = np.zeros((len(features), len(features)))

pairs = [(i, j, f1, f2) for i, f1 in enumerate(features) for j, f2 in enumerate(features) if i &lt; j]

for i, j, f1, f2 in tqdm(pairs, desc="Pairwise H"):
    h = h_stat_pairwise(model, X, f1, f2)
    h_matrix[i, j] = h
    h_matrix[j, i] = h

total_h = []
for f in tqdm(features, desc="Total H"):
    total_h.append(h_stat_total(model, X, f))

features_sorted, total_h_sorted = zip(*sorted(zip(features, total_h), key=lambda x: x[1]))

fig, axes = plt.subplots(1, 2, figsize=(16, 5))

sns.heatmap(h_matrix, xticklabels=features, yticklabels=features,
            annot=True, fmt=".2f", cmap="YlOrRd", ax=axes[0],
            linewidths=0.5, cbar_kws={"label": "H-statistic"}, vmin=0, vmax=1)
axes[0].set_title("Pairwise H-statistics", fontsize=13, fontweight="bold")

axes[1].barh(features_sorted, total_h_sorted, color="steelblue")
axes[1].axvline(0, color="black", linewidth=0.8)
axes[1].set_xlabel("H-statistic")
axes[1].set_title("Total H-statistics", fontsize=13, fontweight="bold")
axes[1].grid(True, alpha=0.3, axis="x")

plt.tight_layout()</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kjcw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127e2312-c62c-4036-821c-87ed0938507e_1590x490.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kjcw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127e2312-c62c-4036-821c-87ed0938507e_1590x490.png 424w, https://substackcdn.com/image/fetch/$s_!kjcw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127e2312-c62c-4036-821c-87ed0938507e_1590x490.png 848w, https://substackcdn.com/image/fetch/$s_!kjcw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127e2312-c62c-4036-821c-87ed0938507e_1590x490.png 1272w, https://substackcdn.com/image/fetch/$s_!kjcw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127e2312-c62c-4036-821c-87ed0938507e_1590x490.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kjcw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127e2312-c62c-4036-821c-87ed0938507e_1590x490.png" width="1456" height="449" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/127e2312-c62c-4036-821c-87ed0938507e_1590x490.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:449,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:156912,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/193204015?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127e2312-c62c-4036-821c-87ed0938507e_1590x490.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!kjcw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127e2312-c62c-4036-821c-87ed0938507e_1590x490.png 424w, https://substackcdn.com/image/fetch/$s_!kjcw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127e2312-c62c-4036-821c-87ed0938507e_1590x490.png 848w, https://substackcdn.com/image/fetch/$s_!kjcw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127e2312-c62c-4036-821c-87ed0938507e_1590x490.png 1272w, https://substackcdn.com/image/fetch/$s_!kjcw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127e2312-c62c-4036-821c-87ed0938507e_1590x490.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This suffers from the typical drawback of all interpretable machine learning methods: It&#8217;s computationally expensive. It also only tells us the strength of the interactions, not what those interactions look like. A good workflow is to measure the interaction strengths with this method and then examine the strongest interactions in more detail using other methods (like specific SHAP plots that we will get to soon).</p><h2>2.4 SHAP</h2><p>We already covered how SHAP works so I will only showcase the plots that focus on global effect here.</p><h3>beeswarm:</h3><p>Shows the distribution of SHAP values for every feature across all observations.<br>Each dot is one observation, color indicates the feature value (red=high, blue=low).<br>Features are sorted by mean absolute SHAP value.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qeS8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e815aa8-4b3f-4836-90cd-ddb8c6f92be3_758x660.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qeS8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e815aa8-4b3f-4836-90cd-ddb8c6f92be3_758x660.png 424w, https://substackcdn.com/image/fetch/$s_!qeS8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e815aa8-4b3f-4836-90cd-ddb8c6f92be3_758x660.png 848w, https://substackcdn.com/image/fetch/$s_!qeS8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e815aa8-4b3f-4836-90cd-ddb8c6f92be3_758x660.png 1272w, https://substackcdn.com/image/fetch/$s_!qeS8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e815aa8-4b3f-4836-90cd-ddb8c6f92be3_758x660.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qeS8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e815aa8-4b3f-4836-90cd-ddb8c6f92be3_758x660.png" width="758" height="660" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1e815aa8-4b3f-4836-90cd-ddb8c6f92be3_758x660.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:660,&quot;width&quot;:758,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:80226,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/193204015?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e815aa8-4b3f-4836-90cd-ddb8c6f92be3_758x660.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!qeS8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e815aa8-4b3f-4836-90cd-ddb8c6f92be3_758x660.png 424w, https://substackcdn.com/image/fetch/$s_!qeS8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e815aa8-4b3f-4836-90cd-ddb8c6f92be3_758x660.png 848w, https://substackcdn.com/image/fetch/$s_!qeS8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e815aa8-4b3f-4836-90cd-ddb8c6f92be3_758x660.png 1272w, https://substackcdn.com/image/fetch/$s_!qeS8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e815aa8-4b3f-4836-90cd-ddb8c6f92be3_758x660.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Can see here that very negative momentum causes very SHAP values (mean reversion).</p><h3>mean absolute SHAP:</h3><p>Mean absolute SHAP value per feature (global feature importance).<br>Simpler than beeswarm, good for reporting which features matter most on average.</p><p>shap.summary_plot(sv_bps, X, plot_type="bar")</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EVo6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe140671f-d93b-41e9-b5d9-1245f4f584cc_790x659.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EVo6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe140671f-d93b-41e9-b5d9-1245f4f584cc_790x659.png 424w, https://substackcdn.com/image/fetch/$s_!EVo6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe140671f-d93b-41e9-b5d9-1245f4f584cc_790x659.png 848w, https://substackcdn.com/image/fetch/$s_!EVo6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe140671f-d93b-41e9-b5d9-1245f4f584cc_790x659.png 1272w, https://substackcdn.com/image/fetch/$s_!EVo6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe140671f-d93b-41e9-b5d9-1245f4f584cc_790x659.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EVo6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe140671f-d93b-41e9-b5d9-1245f4f584cc_790x659.png" width="790" height="659" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e140671f-d93b-41e9-b5d9-1245f4f584cc_790x659.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:659,&quot;width&quot;:790,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:36951,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/193204015?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe140671f-d93b-41e9-b5d9-1245f4f584cc_790x659.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EVo6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe140671f-d93b-41e9-b5d9-1245f4f584cc_790x659.png 424w, https://substackcdn.com/image/fetch/$s_!EVo6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe140671f-d93b-41e9-b5d9-1245f4f584cc_790x659.png 848w, https://substackcdn.com/image/fetch/$s_!EVo6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe140671f-d93b-41e9-b5d9-1245f4f584cc_790x659.png 1272w, https://substackcdn.com/image/fetch/$s_!EVo6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe140671f-d93b-41e9-b5d9-1245f4f584cc_790x659.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Dependence Plots:</h3><p>For each feature, it plots phi_j vs x_j across all observations.<br>Color is automatically chosen as the feature that interacts most with x_j, revealing how the effect of x_j changes depending on another feature's value.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;5faa21fb-f275-47d3-99f4-f4a839cba66d&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">for feat in X.columns:
    shap.dependence_plot(feat, sv_bps.values, X, interaction_index="auto")</code></pre></div><p>Here is a notable ones:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Rnof!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97938be7-05ca-4076-b72b-7d32415a661b_685x453.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Rnof!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97938be7-05ca-4076-b72b-7d32415a661b_685x453.png 424w, https://substackcdn.com/image/fetch/$s_!Rnof!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97938be7-05ca-4076-b72b-7d32415a661b_685x453.png 848w, https://substackcdn.com/image/fetch/$s_!Rnof!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97938be7-05ca-4076-b72b-7d32415a661b_685x453.png 1272w, https://substackcdn.com/image/fetch/$s_!Rnof!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97938be7-05ca-4076-b72b-7d32415a661b_685x453.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Rnof!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97938be7-05ca-4076-b72b-7d32415a661b_685x453.png" width="685" height="453" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/97938be7-05ca-4076-b72b-7d32415a661b_685x453.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:453,&quot;width&quot;:685,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:49461,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/193204015?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97938be7-05ca-4076-b72b-7d32415a661b_685x453.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Rnof!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97938be7-05ca-4076-b72b-7d32415a661b_685x453.png 424w, https://substackcdn.com/image/fetch/$s_!Rnof!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97938be7-05ca-4076-b72b-7d32415a661b_685x453.png 848w, https://substackcdn.com/image/fetch/$s_!Rnof!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97938be7-05ca-4076-b72b-7d32415a661b_685x453.png 1272w, https://substackcdn.com/image/fetch/$s_!Rnof!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97938be7-05ca-4076-b72b-7d32415a661b_685x453.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>When momentum is very negative and volume is very low, SHAP values become positive. The other ones didn&#8217;t have obvious interactions:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!de_V!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef38b0cb-1d4a-48fa-9360-e22b7132398e_684x453.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!de_V!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef38b0cb-1d4a-48fa-9360-e22b7132398e_684x453.png 424w, https://substackcdn.com/image/fetch/$s_!de_V!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef38b0cb-1d4a-48fa-9360-e22b7132398e_684x453.png 848w, https://substackcdn.com/image/fetch/$s_!de_V!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef38b0cb-1d4a-48fa-9360-e22b7132398e_684x453.png 1272w, https://substackcdn.com/image/fetch/$s_!de_V!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef38b0cb-1d4a-48fa-9360-e22b7132398e_684x453.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!de_V!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef38b0cb-1d4a-48fa-9360-e22b7132398e_684x453.png" width="430" height="284.780701754386" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ef38b0cb-1d4a-48fa-9360-e22b7132398e_684x453.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:453,&quot;width&quot;:684,&quot;resizeWidth&quot;:430,&quot;bytes&quot;:43260,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/193204015?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef38b0cb-1d4a-48fa-9360-e22b7132398e_684x453.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!de_V!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef38b0cb-1d4a-48fa-9360-e22b7132398e_684x453.png 424w, https://substackcdn.com/image/fetch/$s_!de_V!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef38b0cb-1d4a-48fa-9360-e22b7132398e_684x453.png 848w, https://substackcdn.com/image/fetch/$s_!de_V!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef38b0cb-1d4a-48fa-9360-e22b7132398e_684x453.png 1272w, https://substackcdn.com/image/fetch/$s_!de_V!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef38b0cb-1d4a-48fa-9360-e22b7132398e_684x453.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!f1uo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a02db6e-3806-4be1-a4bb-61793e7dbfd1_675x453.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!f1uo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a02db6e-3806-4be1-a4bb-61793e7dbfd1_675x453.png 424w, https://substackcdn.com/image/fetch/$s_!f1uo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a02db6e-3806-4be1-a4bb-61793e7dbfd1_675x453.png 848w, https://substackcdn.com/image/fetch/$s_!f1uo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a02db6e-3806-4be1-a4bb-61793e7dbfd1_675x453.png 1272w, https://substackcdn.com/image/fetch/$s_!f1uo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a02db6e-3806-4be1-a4bb-61793e7dbfd1_675x453.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!f1uo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a02db6e-3806-4be1-a4bb-61793e7dbfd1_675x453.png" width="431" height="289.24888888888887" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1a02db6e-3806-4be1-a4bb-61793e7dbfd1_675x453.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:453,&quot;width&quot;:675,&quot;resizeWidth&quot;:431,&quot;bytes&quot;:59493,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/193204015?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a02db6e-3806-4be1-a4bb-61793e7dbfd1_675x453.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!f1uo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a02db6e-3806-4be1-a4bb-61793e7dbfd1_675x453.png 424w, https://substackcdn.com/image/fetch/$s_!f1uo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a02db6e-3806-4be1-a4bb-61793e7dbfd1_675x453.png 848w, https://substackcdn.com/image/fetch/$s_!f1uo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a02db6e-3806-4be1-a4bb-61793e7dbfd1_675x453.png 1272w, https://substackcdn.com/image/fetch/$s_!f1uo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a02db6e-3806-4be1-a4bb-61793e7dbfd1_675x453.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rwJ6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde4b9ba9-3037-449b-80c3-0a7285f5b49a_682x453.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rwJ6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde4b9ba9-3037-449b-80c3-0a7285f5b49a_682x453.png 424w, https://substackcdn.com/image/fetch/$s_!rwJ6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde4b9ba9-3037-449b-80c3-0a7285f5b49a_682x453.png 848w, https://substackcdn.com/image/fetch/$s_!rwJ6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde4b9ba9-3037-449b-80c3-0a7285f5b49a_682x453.png 1272w, https://substackcdn.com/image/fetch/$s_!rwJ6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde4b9ba9-3037-449b-80c3-0a7285f5b49a_682x453.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rwJ6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde4b9ba9-3037-449b-80c3-0a7285f5b49a_682x453.png" width="436" height="289.6011730205279" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/de4b9ba9-3037-449b-80c3-0a7285f5b49a_682x453.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:453,&quot;width&quot;:682,&quot;resizeWidth&quot;:436,&quot;bytes&quot;:74402,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/193204015?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde4b9ba9-3037-449b-80c3-0a7285f5b49a_682x453.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!rwJ6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde4b9ba9-3037-449b-80c3-0a7285f5b49a_682x453.png 424w, https://substackcdn.com/image/fetch/$s_!rwJ6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde4b9ba9-3037-449b-80c3-0a7285f5b49a_682x453.png 848w, https://substackcdn.com/image/fetch/$s_!rwJ6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde4b9ba9-3037-449b-80c3-0a7285f5b49a_682x453.png 1272w, https://substackcdn.com/image/fetch/$s_!rwJ6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde4b9ba9-3037-449b-80c3-0a7285f5b49a_682x453.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Headmap:</h3><p>Shows phi_j for every feature j and every observation i simultaneously, features as rows and observations as columns. Each cell is colored by the SHAP value: red means the feature pushed the prediction up, blue means it pushed it down.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;b9ae0a1f-275b-4b7a-9b91-394a4aa388f3&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">shap.plots.heatmap(sv_bps)</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!AanD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa1c95f2-16bc-4e00-a4ce-2fb7af44c5ff_929x558.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!AanD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa1c95f2-16bc-4e00-a4ce-2fb7af44c5ff_929x558.png 424w, https://substackcdn.com/image/fetch/$s_!AanD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa1c95f2-16bc-4e00-a4ce-2fb7af44c5ff_929x558.png 848w, https://substackcdn.com/image/fetch/$s_!AanD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa1c95f2-16bc-4e00-a4ce-2fb7af44c5ff_929x558.png 1272w, https://substackcdn.com/image/fetch/$s_!AanD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa1c95f2-16bc-4e00-a4ce-2fb7af44c5ff_929x558.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!AanD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa1c95f2-16bc-4e00-a4ce-2fb7af44c5ff_929x558.png" width="929" height="558" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fa1c95f2-16bc-4e00-a4ce-2fb7af44c5ff_929x558.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:558,&quot;width&quot;:929,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:59924,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/193204015?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa1c95f2-16bc-4e00-a4ce-2fb7af44c5ff_929x558.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!AanD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa1c95f2-16bc-4e00-a4ce-2fb7af44c5ff_929x558.png 424w, https://substackcdn.com/image/fetch/$s_!AanD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa1c95f2-16bc-4e00-a4ce-2fb7af44c5ff_929x558.png 848w, https://substackcdn.com/image/fetch/$s_!AanD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa1c95f2-16bc-4e00-a4ce-2fb7af44c5ff_929x558.png 1272w, https://substackcdn.com/image/fetch/$s_!AanD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa1c95f2-16bc-4e00-a4ce-2fb7af44c5ff_929x558.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>2.5 Permutation Feature Importance (PFI)</h2><p>We already know about mean absolute SHAP as a general measure of how important a feature is in a model. PFI is another such singular value. If a feature x_j is important, then randomly shuffling its values across observations will destroy its relationship with the target and cause the model&#8217;s performance to degrade. If it&#8217;s unimportant, shuffling it changes nothing.</p><p>We first fit the model and compute a baseline performance metric L (e.g. MSE, R^2, IC) on the dataset. Then, for each feature j, we randomly permute the values of x_j across all observations, leaving all other features unchanged. We recompute the performance metric L^(j) on the permuted dataset, and the importance of feature j becomes</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\Delta L_j = L^{(j)} - L&quot;,&quot;id&quot;:&quot;QRDBYDNPYM&quot;}" data-component-name="LatexBlockToDOM"></div><p>A large Delta L_j means the model relied heavily on x_j, and destroying it hurt performance a lot.</p><p>Since permutation is random, it&#8217;s standard to repeat this K times and average:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\text{PFI}_j = \\frac{1}{K} \\sum_{k=1}^K [L^{(j,k)}-L]&quot;,&quot;id&quot;:&quot;FSOOPWAFTV&quot;}" data-component-name="LatexBlockToDOM"></div><p>This is much faster to compute than SHAP and is directly tied to model performance, which is what we ultimately care about.</p><p>One BIG disadvantage is that if two features are highly correlated, then shuffling one leaves the other intact, and therefore both will receive a lot of permutation importance, even if they are super important to the model performance.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;02e2bc11-86dd-445e-9cd8-caefcb35bb62&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">from sklearn.inspection import permutation_importance

result = permutation_importance(model, X, y, n_repeats=30, random_state=42, scoring="r2")

sorted_idx = result.importances_mean.argsort()

fig, ax = plt.subplots(figsize=(8, 5))
ax.barh(X.columns[sorted_idx], result.importances_mean[sorted_idx], 
        xerr=result.importances_std[sorted_idx], color="steelblue", capsize=3)
ax.axvline(0, color="black", linewidth=0.8)
ax.set_xlabel("Mean decrease in $R^2$")
ax.set_title("Permutation Feature Importance", fontsize=13, fontweight="bold")
ax.grid(True, alpha=0.3, axis="x")
plt.tight_layout()</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7GB5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d5e11e8-ec5c-4596-9543-b68115f662c8_790x489.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7GB5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d5e11e8-ec5c-4596-9543-b68115f662c8_790x489.png 424w, https://substackcdn.com/image/fetch/$s_!7GB5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d5e11e8-ec5c-4596-9543-b68115f662c8_790x489.png 848w, https://substackcdn.com/image/fetch/$s_!7GB5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d5e11e8-ec5c-4596-9543-b68115f662c8_790x489.png 1272w, https://substackcdn.com/image/fetch/$s_!7GB5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d5e11e8-ec5c-4596-9543-b68115f662c8_790x489.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7GB5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d5e11e8-ec5c-4596-9543-b68115f662c8_790x489.png" width="790" height="489" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7d5e11e8-ec5c-4596-9543-b68115f662c8_790x489.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:489,&quot;width&quot;:790,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:32574,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/193204015?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d5e11e8-ec5c-4596-9543-b68115f662c8_790x489.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!7GB5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d5e11e8-ec5c-4596-9543-b68115f662c8_790x489.png 424w, https://substackcdn.com/image/fetch/$s_!7GB5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d5e11e8-ec5c-4596-9543-b68115f662c8_790x489.png 848w, https://substackcdn.com/image/fetch/$s_!7GB5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d5e11e8-ec5c-4596-9543-b68115f662c8_790x489.png 1272w, https://substackcdn.com/image/fetch/$s_!7GB5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d5e11e8-ec5c-4596-9543-b68115f662c8_790x489.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>2.6 Leave One Feature Out (LOFO) Importance</h2><p>Instead of permuting a feature and evaluating with the same model, we completely drop a feature and retrain the model without it. LOFO Importance then measures the performance drop compared to the full model:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\text{LOFO}_j = L_{\\text{full}} - L_{-j}&quot;,&quot;id&quot;:&quot;KBYSOYURWS&quot;}" data-component-name="LatexBlockToDOM"></div><p>This is extremely useful for feature selection, but it is incredibly expensive and suffers from the same issue that highly correlated features get low LOFO importance. If you remove features one at a time, that problem becomes less relevant, as when one of them drops, the other increases in importance and won&#8217;t be dropped again. </p><p>Let&#8217;s implement this with R^2 as our performance metric:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;79b16a3f-8b29-464a-adf7-f0904a694e0a&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">from sklearn.metrics import r2_score

baseline = r2_score(y, model.predict(X))

loo_importance = {}
for feat in tqdm(features, desc="LOO"):
    X_loo = X.drop(columns=[feat])
    m = XGBRegressor(n_estimators=300, max_depth=4, learning_rate=0.05,
                     subsample=0.8, colsample_bytree=0.8, random_state=42)
    m.fit(X_loo, y)
    loo_importance[feat] = baseline - r2_score(y, m.predict(X_loo))

sorted_feats, sorted_vals = zip(*sorted(loo_importance.items(), key=lambda x: x[1]))

fig, ax = plt.subplots(figsize=(8, 5))
ax.barh(sorted_feats, sorted_vals, color="steelblue")
ax.axvline(0, color="black", linewidth=0.8)
ax.set_xlabel("Decrease in $R^2$")
ax.set_title("Leave-One-Out Feature Importance", fontsize=13, fontweight="bold")
ax.grid(True, alpha=0.3, axis="x")
plt.tight_layout()</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HkR0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6426b196-097f-4807-9eab-9cdf8342d560_789x489.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HkR0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6426b196-097f-4807-9eab-9cdf8342d560_789x489.png 424w, https://substackcdn.com/image/fetch/$s_!HkR0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6426b196-097f-4807-9eab-9cdf8342d560_789x489.png 848w, https://substackcdn.com/image/fetch/$s_!HkR0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6426b196-097f-4807-9eab-9cdf8342d560_789x489.png 1272w, https://substackcdn.com/image/fetch/$s_!HkR0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6426b196-097f-4807-9eab-9cdf8342d560_789x489.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HkR0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6426b196-097f-4807-9eab-9cdf8342d560_789x489.png" width="789" height="489" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6426b196-097f-4807-9eab-9cdf8342d560_789x489.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:489,&quot;width&quot;:789,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:30358,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/193204015?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6426b196-097f-4807-9eab-9cdf8342d560_789x489.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!HkR0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6426b196-097f-4807-9eab-9cdf8342d560_789x489.png 424w, https://substackcdn.com/image/fetch/$s_!HkR0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6426b196-097f-4807-9eab-9cdf8342d560_789x489.png 848w, https://substackcdn.com/image/fetch/$s_!HkR0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6426b196-097f-4807-9eab-9cdf8342d560_789x489.png 1272w, https://substackcdn.com/image/fetch/$s_!HkR0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6426b196-097f-4807-9eab-9cdf8342d560_789x489.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h1>3. Conclusion</h1><p>I&#8217;ve never really written about ML before. If you enjoyed this article and would like to read more about ML, please let me know!</p><div class="poll-embed" data-attrs="{&quot;id&quot;:489630}" data-component-name="PollToDOM"></div><p>Join Quant Corner: <a href="https://discord.gg/X7TsxKNbXg">https://discord.gg/X7TsxKNbXg</a></p><p>If you enjoyed this article, please share it!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.vertoxquant.com/p/looking-inside-the-black-box?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.vertoxquant.com/p/looking-inside-the-black-box?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p>If you want to read more, consider subscribing!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.vertoxquant.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">VertoxQuant is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Finding the Best Portfolio Optimization Technique]]></title><description><![CDATA[A comparative study of modern portfolio construction methods on crypto markets]]></description><link>https://www.vertoxquant.com/p/finding-the-best-portfolio-optimization</link><guid isPermaLink="false">https://www.vertoxquant.com/p/finding-the-best-portfolio-optimization</guid><dc:creator><![CDATA[Vertox]]></dc:creator><pubDate>Tue, 17 Mar 2026 22:32:28 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/29087727-5b71-4b01-9d0f-0a8aebd991f8_986x584.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2><p>This article provides a rigorous, hands-on walkthrough of portfolio optimization methods used in both research and industry. Rather than focusing on theory alone, we emphasize how these approaches behave in practice; what they optimize, which constraints matter, and the trade-offs they impose.</p><p>After briefly introducing the minimal notation, we move directly into the major families of portfolio construction techniques, including mean&#8211;variance, risk-based, and hierarchical approaches. The goal is not just to present these methods, but to understand when and why they work (or fail), especially in noisy and high-volatility environments.</p><p><strong>Prerequisite (recommended):</strong><br>This article assumes basic familiarity with Markowitz Mean&#8211;Variance Optimization (MVO). For full derivations of the efficient frontier, the tangency portfolio, and a detailed discussion of estimation error and its practical remedies (e.g., shrinkage, factor models, Black&#8211;Litterman, and robust optimization), see:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;78f039c9-df53-4801-9164-3b180e73ab1d&quot;,&quot;caption&quot;:&quot;Introduction&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;md&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Why Mean-Variance Optimization Breaks Down&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:128680675,&quot;name&quot;:&quot;Vertox&quot;,&quot;bio&quot;:&quot;Quantitative Researcher in Digital Asset Markets | Market Making | Statistical Arbitrage | Options &quot;,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!HGUA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bf3fd86-d46a-4caa-969a-d80059b72cb9_128x128.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2026-02-03T23:01:54.857Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!aB9w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc64a161-9abb-481e-b211-33545c699a4d_824x464.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.vertoxquant.com/p/why-mean-variance-optimization-breaks&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:186718680,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:16,&quot;comment_count&quot;:0,&quot;publication_id&quot;:1726874,&quot;publication_name&quot;:&quot;VertoxQuant&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!ufaQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb77b39-424b-4665-b2a7-7db519ff9e11_128x128.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><h2><strong>Notation and Setup</strong></h2><p>Consider n risky assets with (random) single-period returns r &#8712; &#8477;&#8319;. A portfolio is represented by weights w &#8712; &#8477;&#8319;. In the simplest setting, the portfolio return is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;r_p = w^\\top r.&quot;,&quot;id&quot;:&quot;YLGDOMNGNP&quot;}" data-component-name="LatexBlockToDOM"></div><p>Let the expected returns be</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mu = \\mathbb{E}[r] \\in \\mathbb{R}^n,&quot;,&quot;id&quot;:&quot;MTKLSFMJOM&quot;}" data-component-name="LatexBlockToDOM"></div><p>and the covariance matrix be</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\Sigma = \\mathrm{Cov}(r) = \\mathbb{E}\\big[(r-\\mu)(r-\\mu)^\\top\\big] \\in \\mathbb{R}^{n \\times n}.&quot;,&quot;id&quot;:&quot;XFAJOAUUBQ&quot;}" data-component-name="LatexBlockToDOM"></div><p>Then the portfolio&#8217;s expected return and variance are</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathbb{E}[r_p] = w^\\top \\mu,\\qquad \\mathrm{Var}(r_p) = w^\\top \\Sigma w.&quot;,&quot;id&quot;:&quot;IHXCWXDKGK&quot;}" data-component-name="LatexBlockToDOM"></div><p>A standard budget constraint is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathbf{1}^\\top w = 1,&quot;,&quot;id&quot;:&quot;GDTVTKQMDL&quot;}" data-component-name="LatexBlockToDOM"></div><p>where the left 1 is the all-ones vector in &#8477;&#8319;. Additional constraints may include long-only constraints w &gt;= 0, leverage limits |w|_1 &lt;= L, box constraints l &lt;= w &lt;= u, factor exposure constraints, and turnover constraints. Note: if w &gt;= 0 and 1^&#8868; w = 1, then |w|_1 = 1 is constant; l_1 leverage constraints/penalties matter primarily for long/short portfolios, active weights a = w - w_b, or turnover terms |wt - w_(t-1)|_1.</p><p>To set us up let&#8217;s first import the necessary libraries and set plot styles:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;fcbdc1f0-d58a-4116-a9b4-5765cc112240&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">import os
import glob
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

from scipy import linalg
from scipy import optimize
from scipy.optimize import linprog
from scipy.cluster.hierarchy import linkage, to_tree, dendrogram
from scipy.spatial.distance import squareform

# Plot style defaults.
plt.rcParams.update(
    {
        &#8220;figure.figsize&#8221;: (10, 6),
        &#8220;axes.grid&#8221;: True,
        &#8220;grid.alpha&#8221;: 0.3,
        &#8220;axes.titlesize&#8221;: 14,
        &#8220;axes.labelsize&#8221;: 12,
        &#8220;legend.fontsize&#8221;: 10,
    }
)</code></pre></div><p>We don&#8217;t  wanna be trading stablecoins, so we&#8217;ll exclude them:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;4dc3fad0-7f6b-4157-87e7-c33578c2ae7b&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">STABLE_SYMBOLS = {
    &#8220;USDT&#8221;, &#8220;USDC&#8221;, &#8220;USDS&#8221;, &#8220;USDE&#8221;, &#8220;DAI&#8221;, &#8220;PYUSD&#8221;, &#8220;USD1&#8221;, &#8220;XAUT&#8221;, &#8220;USDF&#8221;,
    &#8220;PAXG&#8221;, &#8220;USDG&#8221;, &#8220;RLUSD&#8221;, &#8220;BFUSD&#8221;, &#8220;USDD&#8221;, &#8220;USDTB&#8221;, &#8220;USD0&#8221;, &#8220;FDUSD&#8221;, &#8220;A7A5&#8221;,
    &#8220;GHO&#8221;, &#8220;TUSD&#8221;, &#8220;CUSD&#8221;, &#8220;USDB&#8221;, &#8220;USR&#8221;, &#8220;KAU&#8221;, &#8220;EURC&#8221;, &#8220;CRVUSD&#8221;, &#8220;KAG&#8221;,
    &#8220;BUSD&#8221;, &#8220;USX&#8221;, &#8220;FRAX&#8221;, &#8220;USDC.N&#8221;, &#8220;YLDS&#8221;, &#8220;USDA&#8221;, &#8220;AUSD&#8221;, &#8220;DUSD&#8221;, &#8220;SATUSD&#8221;,
    &#8220;GUSD&#8221;, &#8220;EURS&#8221;, &#8220;DOLA&#8221;, &#8220;FRXUSD&#8221;, &#8220;PUSD&#8221;, &#8220;AIDAUSDC&#8221;, &#8220;USDZ&#8221;, &#8220;AVUSD&#8221;, &#8220;MNEE&#8221;,
    &#8220;USDR&#8221;, &#8220;PGOLD&#8221;, &#8220;CASH&#8221;, &#8220;EURCV&#8221;, &#8220;SUSDA&#8221;, &#8220;USDO&#8221;, &#8220;FEUSD&#8221;, &#8220;USDX&#8221;, &#8220;YZUSD&#8221;,
    &#8220;MIM&#8221;, &#8220;USDKG&#8221;, &#8220;REUSD&#8221;, &#8220;USDM&#8221;, &#8220;USD+&#8221;, &#8220;USDP&#8221;, &#8220;YUSD&#8221;, &#8220;XUSD&#8221;, &#8220;BOLD&#8221;,
    &#8220;HYUSD&#8221;, &#8220;LISUSD&#8221;, &#8220;USTC&#8221;, &#8220;USDN&#8221;, &#8220;LUSD&#8221;, &#8220;FXUSD&#8221;, &#8220;HBD&#8221;, &#8220;XTUSD&#8221;, &#8220;HONEY&#8221;,
    &#8220;EUSD&#8221;, &#8220;ZCHF&#8221;, &#8220;MIMATIC&#8221;, &#8220;USN&#8221;, &#8220;SUSD&#8221;, &#8220;EURE&#8221;, &#8220;BUCK&#8221;, &#8220;MUSD&#8221;, &#8220;EURA&#8221;,
    &#8220;GYD&#8221;, &#8220;USDH&#8221;, &#8220;MSUSD&#8221;, &#8220;UTY&#8221;, &#8220;WEMIX$&#8221;, &#8220;YU&#8221;, &#8220;HOLLAR&#8221;, &#8220;ALUSD&#8221;, &#8220;XSGD&#8221;,
    &#8220;EURR&#8221;,
}</code></pre></div><p>Next, some useful helper function:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;431831cd-9592-4f79-ad10-6a82c487db55&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">def _normalize_symbol(symbol: str) -&gt; str:
    return &#8220;&#8221;.join(ch for ch in str(symbol).upper() if ch.isalnum())


def _base_symbol_from_ticker(ticker: str) -&gt; str:
    t = str(ticker).upper()
    suffix = &#8220;_USD_1DAY_COMPOSITE&#8221;
    if t.endswith(suffix):
        return t[:-len(suffix)]
    return t.split(&#8221;_&#8221;)[0]


STABLE_SYMBOLS_NORM = {_normalize_symbol(s) for s in STABLE_SYMBOLS}</code></pre></div><p>Whenever data isn&#8217;t available for a coin, we&#8217;ll be using synthetic data for demonstration purposes:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;f63a8b20-c774-4d6c-987c-a0ddb218e370&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># Synthetic fallback data.
def synthetic_crypto_like_returns(
    n_assets: int = 12,
    n_obs: int = 1200,
    seed: int = 42,
    df_t: float = 5.0,
    regime_switch_prob: float = 0.02,
) -&gt; pd.DataFrame:

    rng = np.random.default_rng(seed)
    dates = pd.date_range(&#8221;2020-01-01&#8221;, periods=n_obs, freq=&#8221;D&#8221;)

    # Build three correlation clusters.
    n_clusters = 3
    cluster_sizes = [n_assets // n_clusters] * n_clusters
    for i in range(n_assets % n_clusters):
        cluster_sizes[i] += 1
    clusters = np.concatenate([[k] * sz for k, sz in enumerate(cluster_sizes)])

    base_corr = np.eye(n_assets)
    for i in range(n_assets):
        for j in range(n_assets):
            if i == j:
                continue
            base_corr[i, j] = 0.55 if clusters[i] == clusters[j] else 0.15

    # Add symmetric jitter and keep the matrix positive definite.
    jitter = rng.normal(scale=0.03, size=(n_assets, n_assets))
    jitter = 0.5 * (jitter + jitter.T)
    corr = base_corr + jitter
    np.fill_diagonal(corr, 1.0)

    eig = np.linalg.eigvalsh(corr)
    if eig.min() &lt;= 1e-6:
        corr += (abs(eig.min()) + 1e-3) * np.eye(n_assets)

    # Give each asset a different daily volatility.
    base_vol = rng.uniform(0.02, 0.08, size=n_assets)
    cov = np.outer(base_vol, base_vol) * corr
    L = np.linalg.cholesky(cov)

    # Switch between low- and high-volatility regimes.
    vol_mult = np.ones(n_obs)
    state = 0
    for t in range(1, n_obs):
        if rng.random() &lt; regime_switch_prob:
            state = 1 - state
        vol_mult[t] = 1.0 if state == 0 else 2.0

    # Student-t shocks via normal / sqrt(chi2/df).
    Z = rng.standard_normal(size=(n_obs, n_assets))
    chi2 = rng.chisquare(df=df_t, size=n_obs) / df_t
    t_innov = Z / np.sqrt(chi2)[:, None]

    rets = (t_innov @ L.T) * vol_mult[:, None]
    cols = [f&#8221;Asset_{i:02d}&#8220; for i in range(n_assets)]
    return pd.DataFrame(rets, index=dates, columns=cols)</code></pre></div><p>The function for loading actual data (We are using CoinAPI):</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;76b92c84-b949-4414-a048-b4203fe0c749&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># Loader for real data files.
def load_crypto_dataset_from_dir(
    data_dir: str = &#8220;/Users/admin/Documents/Projects/PortfolioOptimization/data&#8221;,
    max_assets: int = 100,
    min_obs: int = 365,
    coverage_threshold: float = 0.98,
    selection_metric: str = &#8220;mean_volume&#8221;,  # &#8216;mean_volume&#8217; or &#8216;n_obs&#8217;
    verbose: bool = True,
):

    if not os.path.isdir(data_dir):
        raise FileNotFoundError(f&#8221;Directory not found: {data_dir}&#8220;)

    csv_files = sorted(glob.glob(os.path.join(data_dir, &#8220;*.csv&#8221;)))
    if len(csv_files) == 0:
        raise FileNotFoundError(f&#8221;No CSV files found in {data_dir}&#8220;)

    records = []
    price_series = {}
    excluded_stables = []

    for fp in csv_files:
        sym = os.path.splitext(os.path.basename(fp))[0].upper()
        base_sym = _base_symbol_from_ticker(sym)
        if _normalize_symbol(base_sym) in STABLE_SYMBOLS_NORM:
            excluded_stables.append(base_sym)
            continue
        try:
            df = pd.read_csv(fp)
        except Exception as e:
            if verbose:
                print(f&#8221;[WARN] Skipping {fp} (read error: {e})&#8221;)
            continue

        if &#8220;date&#8221; not in df.columns or &#8220;close&#8221; not in df.columns:
            if verbose:
                print(f&#8221;[WARN] Skipping {fp} (missing required columns &#8216;date&#8217;/&#8217;close&#8217;)&#8221;)
            continue

        keep_cols = [c for c in df.columns if c in (&#8221;date&#8221;, &#8220;close&#8221;, &#8220;volume_usd&#8221;)]
        df = df.loc[:, keep_cols].copy()

        df[&#8221;date&#8221;] = pd.to_datetime(df[&#8221;date&#8221;], errors=&#8221;coerce&#8221;)
        df[&#8221;close&#8221;] = pd.to_numeric(df[&#8221;close&#8221;], errors=&#8221;coerce&#8221;)
        df = df.dropna(subset=[&#8221;date&#8221;, &#8220;close&#8221;]).sort_values(&#8221;date&#8221;)
        df = df.drop_duplicates(subset=[&#8221;date&#8221;], keep=&#8221;last&#8221;)

        if df.shape[0] &lt; min_obs:
            continue

        s = df.set_index(&#8221;date&#8221;)[&#8221;close&#8221;].astype(float)
        price_series[sym] = s

        mean_volume = float(df[&#8221;volume_usd&#8221;].astype(float).mean()) if &#8220;volume_usd&#8221; in df.columns else np.nan
        records.append(
            {
                &#8220;symbol&#8221;: sym,
                &#8220;n_obs&#8221;: int(df.shape[0]),
                &#8220;start&#8221;: df[&#8221;date&#8221;].min(),
                &#8220;end&#8221;: df[&#8221;date&#8221;].max(),
                &#8220;mean_volume_usd&#8221;: mean_volume,
                &#8220;file&#8221;: fp,
            }
        )

    if len(price_series) &lt; 2:
        raise ValueError(f&#8221;Insufficient usable assets in {data_dir} after filtering (min_obs={min_obs}).&#8221;)

    info = pd.DataFrame(records).set_index(&#8221;symbol&#8221;)

    # Pick the sorting column.
    if selection_metric == &#8220;mean_volume&#8221; and info[&#8221;mean_volume_usd&#8221;].notna().any():
        sort_by = &#8220;mean_volume_usd&#8221;
    else:
        sort_by = &#8220;n_obs&#8221;

    info = info.sort_values(by=sort_by, ascending=False, na_position=&#8221;last&#8221;)
    selected = list(info.index[:max_assets])

    prices = pd.concat({sym: price_series[sym] for sym in selected}, axis=1).sort_index()
    rets = np.log(prices).diff()

    # Filter assets again after return coverage is computed.
    coverage = rets.notna().mean()
    keep_cols = coverage[coverage &gt;= coverage_threshold].index.tolist()
    prices = prices[keep_cols]
    rets = rets[keep_cols]
    info = info.loc[keep_cols]

    before_rows = rets.shape[0]
    rets = rets.dropna(how=&#8221;any&#8221;)  # intersection of dates
    prices = prices.loc[rets.index]
    after_rows = rets.shape[0]

    if verbose:
        if excluded_stables:
            print(f&#8221;[DATA] Excluded {len(set(excluded_stables))} stable symbols before selection.&#8221;)
        print(f&#8221;[DATA] Loaded {len(keep_cols)} assets from {data_dir} (sorted by {sort_by}).&#8221;)
        print(f&#8221;[DATA] Date range: {rets.index.min().date()} &#8594; {rets.index.max().date()} ({after_rows} daily obs).&#8221;)
        print(
            &#8220;[DATA] Missing-data policy: drop any date with any missing return across selected assets &#8220;
            f&#8221;(kept {after_rows}/{before_rows} rows after alignment).&#8221;
        )

    if after_rows &lt; 120:
        raise ValueError(&#8221;Not enough aligned observations after missing-data handling.&#8221;)

    return prices, rets, info</code></pre></div><p>The following function computes returns from price data:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;ad1757ed-67d5-4c87-8cb7-026864b6f501&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">def get_crypto_returns(
    data_dir: str = &#8220;/Users/admin/Documents/Projects/PortfolioOptimization/data&#8221;,
    max_assets: int = 100,
    min_obs: int = 365,
    coverage_threshold: float = 0.98,
    seed_fallback: int = 42,
    verbose: bool = True,
):

    try:
        prices, rets, info = load_crypto_dataset_from_dir(
            data_dir=data_dir,
            max_assets=max_assets,
            min_obs=min_obs,
            coverage_threshold=coverage_threshold,
            verbose=verbose,
        )
        source = &#8220;real&#8221;
    except Exception as e:
        if verbose:
            print(f&#8221;[FALLBACK] Using synthetic data because real /Users/admin/Documents/Projects/PortfolioOptimization/data load failed: {e}&#8220;)
        prices = None
        rets = synthetic_crypto_like_returns(n_assets=max_assets, n_obs=1200, seed=seed_fallback)
        info = pd.DataFrame({&#8221;symbol&#8221;: rets.columns, &#8220;n_obs&#8221;: len(rets), &#8220;mean_volume_usd&#8221;: np.nan}).set_index(&#8221;symbol&#8221;)
        source = &#8220;synthetic&#8221;
    return prices, rets, info, source</code></pre></div><p>Next, some helpful mathematical helper functions:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;cb549ce8-1521-4a0b-9789-95883a33ae8c&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># Basic math helpers.
def regularize_cov(S: np.ndarray, eps: float = 1e-8) -&gt; np.ndarray:
    &#8220;&#8221;&#8220;Symmetrize and add a small diagonal jitter for numerical stability.&#8221;&#8220;&#8221;
    S = np.asarray(S)
    S = 0.5 * (S + S.T)
    return S + eps * np.eye(S.shape[0])

def annualized_return(log_r: pd.Series, periods_per_year: int = 365) -&gt; float:
    &#8220;&#8221;&#8220;Geometric annualized return from log returns.&#8221;&#8220;&#8221;
    years = len(log_r) / periods_per_year
    return float(np.exp(log_r.sum() / years) - 1.0) if years &gt; 0 else np.nan

def annualized_vol(log_r: pd.Series, periods_per_year: int = 365) -&gt; float:
    return float(log_r.std(ddof=1) * np.sqrt(periods_per_year))

def sharpe_ratio(log_r: pd.Series, rf_annual: float = 0.0, periods_per_year: int = 365) -&gt; float:
    rf_log = np.log1p(rf_annual) / periods_per_year
    ex = log_r - rf_log
    vol = ex.std(ddof=1) * np.sqrt(periods_per_year)
    mean = ex.mean() * periods_per_year
    return float(mean / vol) if vol &gt; 0 else np.nan

def max_drawdown(log_r: pd.Series) -&gt; float:
    equity = np.exp(log_r.cumsum())
    peak = equity.cummax()
    dd = equity / peak - 1.0
    return float(dd.min())

def empirical_cvar(log_r: np.ndarray, alpha: float = 0.95) -&gt; float:
    &#8220;&#8221;&#8220;
    Empirical CVaR of *losses* using simple returns:
      loss = - (exp(log_r) - 1)
    &#8220;&#8221;&#8220;
    simple = np.expm1(log_r)
    losses = -simple
    k = max(1, int(np.ceil((1 - alpha) * len(losses))))
    tail = np.sort(losses)[-k:]
    return float(tail.mean())</code></pre></div><p>The following data loads our data and does some quick diagnostics:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;ebcfe3d4-a41a-4621-b131-e7031520b1b8&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># Load real data if available, otherwise use synthetic data.
crypto_prices, crypto_returns, asset_info, DATA_SOURCE = get_crypto_returns(
    data_dir=&#8221;/Users/admin/Documents/Projects/PortfolioOptimization/data&#8221;,
    max_assets=40,
    min_obs=365,
    coverage_threshold=0.98,
    seed_fallback=42,
    verbose=True,
)

print(f&#8221;\n[INFO] Data source: {DATA_SOURCE}&#8220;)
print(f&#8221;[INFO] Returns shape: {crypto_returns.shape[0]} dates &#215; {crypto_returns.shape[1]} assets&#8221;)
print(f&#8221;[INFO] Assets: {list(crypto_returns.columns)}&#8220;)
print(&#8221;\n[INFO] Asset info (head):&#8221;)
print(asset_info.head())

# Quick diagnostics before the experiments.
pooled = crypto_returns.stack()
print(f&#8221;\n[DIAGNOSTIC] Pooled daily log-return mean: {pooled.mean():.6f}&#8220;)
print(f&#8221;[DIAGNOSTIC] Pooled daily log-return std : {pooled.std(ddof=1):.6f}&#8220;)
print(f&#8221;[DIAGNOSTIC] Pooled excess kurtosis      : {pooled.kurt():.2f}&#8220;)

# Plot pooled return histogram and correlation heatmap.
fig, ax = plt.subplots()
ax.hist(pooled.values, bins=80, density=True)
ax.set_title(&#8221;Pooled daily log returns (all assets)&#8221;)
ax.set_xlabel(&#8221;log return&#8221;)
ax.set_ylabel(&#8221;density&#8221;)
plt.tight_layout()
plt.show()

corr = crypto_returns.corr().values
fig, ax = plt.subplots()
im = ax.imshow(corr, aspect=&#8221;auto&#8221;)
ax.set_title(&#8221;Correlation matrix (aligned returns)&#8221;)
ax.set_xticks(range(crypto_returns.shape[1]))
ax.set_yticks(range(crypto_returns.shape[1]))
ax.set_xticklabels(crypto_returns.columns, rotation=90)
ax.set_yticklabels(crypto_returns.columns)
plt.colorbar(im, ax=ax, fraction=0.046, pad=0.04)
plt.tight_layout()
plt.show()
</code></pre></div><pre><code>[DATA] Excluded 17 stable symbols before selection.
[DATA] Loaded 18 assets from /Users/admin/Documents/Projects/PortfolioOptimization/data (sorted by mean_volume_usd).
[DATA] Date range: 2022-01-04 &#8594; 2026-01-16 (1472 daily obs).
[DATA] Missing-data policy: drop any date with any missing return across selected assets (kept 1472/1477 rows after alignment).

[INFO] Data source: real
[INFO] Returns shape: 1472 dates &#215; 18 assets
[INFO] Assets: [&#8217;BTC_USD_1DAY_COMPOSITE&#8217;, &#8216;ETH_USD_1DAY_COMPOSITE&#8217;, &#8216;SOL_USD_1DAY_COMPOSITE&#8217;, &#8216;XRP_USD_1DAY_COMPOSITE&#8217;, &#8216;DOGE_USD_1DAY_COMPOSITE&#8217;, &#8216;ADA_USD_1DAY_COMPOSITE&#8217;, &#8216;FTM_USD_1DAY_COMPOSITE&#8217;, &#8216;RUNE_USD_1DAY_COMPOSITE&#8217;, &#8216;LINK_USD_1DAY_COMPOSITE&#8217;, &#8216;AVAX_USD_1DAY_COMPOSITE&#8217;, &#8216;SHIB_USD_1DAY_COMPOSITE&#8217;, &#8216;CFX_USD_1DAY_COMPOSITE&#8217;, &#8216;LTC_USD_1DAY_COMPOSITE&#8217;, &#8216;XLM_USD_1DAY_COMPOSITE&#8217;, &#8216;HBAR_USD_1DAY_COMPOSITE&#8217;, &#8216;CAKE_USD_1DAY_COMPOSITE&#8217;, &#8216;DYDX_USD_1DAY_COMPOSITE&#8217;, &#8216;XMR_USD_1DAY_COMPOSITE&#8217;]

[INFO] Asset info (head):
                         n_obs      start        end  mean_volume_usd  \
symbol                                                                  
BTC_USD_1DAY_COMPOSITE    1477 2022-01-01 2026-01-16     1.168389e+09   
ETH_USD_1DAY_COMPOSITE    1477 2022-01-01 2026-01-16     6.636419e+08   
SOL_USD_1DAY_COMPOSITE    1477 2022-01-01 2026-01-16     2.891621e+08   
XRP_USD_1DAY_COMPOSITE    1477 2022-01-01 2026-01-16     2.603798e+08   
DOGE_USD_1DAY_COMPOSITE   1477 2022-01-01 2026-01-16     1.068017e+08   

                                                                      file  
symbol                                                                      
BTC_USD_1DAY_COMPOSITE   /Users/admin/Documents/Projects/PortfolioOptim...  
ETH_USD_1DAY_COMPOSITE   /Users/admin/Documents/Projects/PortfolioOptim...  
SOL_USD_1DAY_COMPOSITE   /Users/admin/Documents/Projects/PortfolioOptim...  
XRP_USD_1DAY_COMPOSITE   /Users/admin/Documents/Projects/PortfolioOptim...  
DOGE_USD_1DAY_COMPOSITE  /Users/admin/Documents/Projects/PortfolioOptim...  

[DIAGNOSTIC] Pooled daily log-return mean: -0.000667
[DIAGNOSTIC] Pooled daily log-return std : 0.049747
[DIAGNOSTIC] Pooled excess kurtosis      : 13.75
</code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Un4E!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaeda4cb-8fe6-4d0a-a3c8-4dfc19c89331_989x590.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Un4E!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaeda4cb-8fe6-4d0a-a3c8-4dfc19c89331_989x590.png 424w, https://substackcdn.com/image/fetch/$s_!Un4E!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaeda4cb-8fe6-4d0a-a3c8-4dfc19c89331_989x590.png 848w, https://substackcdn.com/image/fetch/$s_!Un4E!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaeda4cb-8fe6-4d0a-a3c8-4dfc19c89331_989x590.png 1272w, https://substackcdn.com/image/fetch/$s_!Un4E!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaeda4cb-8fe6-4d0a-a3c8-4dfc19c89331_989x590.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Un4E!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaeda4cb-8fe6-4d0a-a3c8-4dfc19c89331_989x590.png" width="989" height="590" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/daeda4cb-8fe6-4d0a-a3c8-4dfc19c89331_989x590.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:590,&quot;width&quot;:989,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;plot&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="plot" title="plot" srcset="https://substackcdn.com/image/fetch/$s_!Un4E!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaeda4cb-8fe6-4d0a-a3c8-4dfc19c89331_989x590.png 424w, https://substackcdn.com/image/fetch/$s_!Un4E!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaeda4cb-8fe6-4d0a-a3c8-4dfc19c89331_989x590.png 848w, https://substackcdn.com/image/fetch/$s_!Un4E!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaeda4cb-8fe6-4d0a-a3c8-4dfc19c89331_989x590.png 1272w, https://substackcdn.com/image/fetch/$s_!Un4E!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaeda4cb-8fe6-4d0a-a3c8-4dfc19c89331_989x590.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9wcG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ee54e3f-fc96-4eea-98a7-357bed22da4a_985x590.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9wcG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ee54e3f-fc96-4eea-98a7-357bed22da4a_985x590.png 424w, https://substackcdn.com/image/fetch/$s_!9wcG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ee54e3f-fc96-4eea-98a7-357bed22da4a_985x590.png 848w, https://substackcdn.com/image/fetch/$s_!9wcG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ee54e3f-fc96-4eea-98a7-357bed22da4a_985x590.png 1272w, https://substackcdn.com/image/fetch/$s_!9wcG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ee54e3f-fc96-4eea-98a7-357bed22da4a_985x590.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9wcG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ee54e3f-fc96-4eea-98a7-357bed22da4a_985x590.png" width="985" height="590" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8ee54e3f-fc96-4eea-98a7-357bed22da4a_985x590.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:590,&quot;width&quot;:985,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;plot&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="plot" title="plot" srcset="https://substackcdn.com/image/fetch/$s_!9wcG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ee54e3f-fc96-4eea-98a7-357bed22da4a_985x590.png 424w, https://substackcdn.com/image/fetch/$s_!9wcG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ee54e3f-fc96-4eea-98a7-357bed22da4a_985x590.png 848w, https://substackcdn.com/image/fetch/$s_!9wcG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ee54e3f-fc96-4eea-98a7-357bed22da4a_985x590.png 1272w, https://substackcdn.com/image/fetch/$s_!9wcG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ee54e3f-fc96-4eea-98a7-357bed22da4a_985x590.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h1><strong>1. Baseline: MVO Recap</strong></h1><p>We use MVO as the reference point for the rest of this notebook. For full derivations and numerical examples, see the following article:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;8ce370f7-cba0-4d5a-a9fe-f0228fc09474&quot;,&quot;caption&quot;:&quot;Introduction&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;md&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Why Mean-Variance Optimization Breaks Down&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:128680675,&quot;name&quot;:&quot;Vertox&quot;,&quot;bio&quot;:&quot;Quantitative Researcher in Digital Asset Markets | Market Making | Statistical Arbitrage | Options &quot;,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!HGUA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bf3fd86-d46a-4caa-969a-d80059b72cb9_128x128.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2026-02-03T23:01:54.857Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!aB9w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc64a161-9abb-481e-b211-33545c699a4d_824x464.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.vertoxquant.com/p/why-mean-variance-optimization-breaks&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:186718680,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:16,&quot;comment_count&quot;:0,&quot;publication_id&quot;:1726874,&quot;publication_name&quot;:&quot;VertoxQuant&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!ufaQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb77b39-424b-4665-b2a7-7db519ff9e11_128x128.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><h2><strong>1.1 Canonical formulations</strong></h2><p>(MVO-1) <strong>Minimum variance at target return</strong>: </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\begin{aligned}\n\\min_{w}\\quad &amp; w^\\top \\Sigma w \\\\\n\\text{s.t.}\\quad &amp; w^\\top \\mu = \\mu_p, \\\\\n&amp; \\mathbf{1}^\\top w = 1, \\\\\n&amp; w \\in \\mathcal{W}.\n\\end{aligned}&quot;,&quot;id&quot;:&quot;DKFEHPXKGB&quot;}" data-component-name="LatexBlockToDOM"></div><p>(MVO-2) <strong>Penalized mean&#8211;variance utility</strong>:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\begin{aligned}\n\\max_{w}\\quad &amp; w^\\top \\mu - \\frac{\\gamma}{2} w^\\top \\Sigma w \\\\\n\\text{s.t.}\\quad &amp; \\mathbf{1}^\\top w = 1, \\\\\n&amp; w \\in \\mathcal{W}.\n\\end{aligned}&quot;,&quot;id&quot;:&quot;BUHODLRPRS&quot;}" data-component-name="LatexBlockToDOM"></div><p>Varying &#956;_p in (MVO-1) or &#947; in (MVO-2) traces the (constraint-dependent) efficient frontier: the set of portfolios that are not dominated in (&#963;, E[r]) space.</p><h2><strong>1.2 Two anchor portfolios</strong></h2><p><strong>Global minimum variance (GMV)</strong> (unconstrained): </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;w_{\\mathrm{GMV}} = \\frac{\\Sigma^{-1}\\mathbf{1}}{\\mathbf{1}^\\top \\Sigma^{-1}\\mathbf{1}}.&quot;,&quot;id&quot;:&quot;YGPLHYEHAI&quot;}" data-component-name="LatexBlockToDOM"></div><p>With a risk-free rate r_f and excess returns &#956;_e = &#956; - r_f 1, the <strong>tangency / maximum Sharpe</strong> portfolio (unconstrained) is: </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;w_{\\mathrm{tan}} = \\frac{\\Sigma^{-1}\\mu_e}{\\mathbf{1}^\\top \\Sigma^{-1}\\mu_e}.&quot;,&quot;id&quot;:&quot;SITJLZNIAU&quot;}" data-component-name="LatexBlockToDOM"></div><p>We construct a simple synthetic market with a random covariance matrix and expected returns, allowing us to study the geometry of mean&#8211;variance optimization in a controlled setting.</p><p>Using closed-form solutions, we compute the <strong>global minimum variance (GMV)</strong> portfolio and the <strong>tangency portfolio</strong> (maximum Sharpe ratio). We then sweep across target returns to trace out the <strong>efficient frontier</strong>, which shows the best achievable return for each level of risk.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;95b8e122-212c-4853-8d82-d657b98a95ca&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># Synthetic efficient frontier example.
rng = np.random.default_rng(0)

n = 6
A = rng.normal(size=(n, n))
Sigma = A @ A.T  # SPD covariance
mu = rng.normal(loc=0.0005, scale=0.0010, size=n)  # daily expected log returns

ones = np.ones(n)
Sigma = regularize_cov(Sigma, eps=1e-10)
Sigma_inv = linalg.inv(Sigma)

# GMV portfolio.
w_gmv = Sigma_inv @ ones / (ones @ Sigma_inv @ ones)
mu_gmv = float(w_gmv @ mu)
vol_gmv = float(np.sqrt(w_gmv @ Sigma @ w_gmv))

# Tangency portfolio (rf=0).
w_tan_unnorm = Sigma_inv @ mu
w_tan = w_tan_unnorm / (ones @ w_tan_unnorm)
mu_tan = float(w_tan @ mu)
vol_tan = float(np.sqrt(w_tan @ Sigma @ w_tan))

# Closed-form frontier with budget and target-return constraints.
A_ = mu @ Sigma_inv @ mu
B_ = mu @ Sigma_inv @ ones
C_ = ones @ Sigma_inv @ ones
D_ = A_ * C_ - B_**2

# Sweep target returns around GMV.
targets = np.linspace(mu_gmv - 1.5 * np.std(mu), mu_gmv + 1.5 * np.std(mu), 80)
frontier_vol = []
for mu_p in targets:
    # Frontier variance at target return mu_p.
    var = (C_ * mu_p**2 - 2.0 * B_ * mu_p + A_) / D_
    frontier_vol.append(np.sqrt(var))

frontier_vol = np.array(frontier_vol)

# Plot volatility vs expected return.
fig, ax = plt.subplots()
ax.plot(frontier_vol, targets, label=&#8221;Efficient frontier (unconstrained)&#8221;)
ax.scatter([vol_gmv], [mu_gmv], label=&#8221;GMV&#8221;, zorder=3)
ax.scatter([vol_tan], [mu_tan], label=&#8221;Tangency (rf=0)&#8221;, zorder=3)

ax.set_title(&#8221;Markowitz efficient frontier geometry (synthetic &#956;, &#931;)&#8221;)
ax.set_xlabel(&#8221;Portfolio volatility  (&#963;)&#8221;)
ax.set_ylabel(&#8221;Expected portfolio return  (E[r])&#8221;)
ax.legend()
plt.tight_layout()
plt.show()

print(&#8221;[SYNTHETIC SUMMARY]&#8221;)
print(f&#8221;GMV:     E[r]={mu_gmv:.6f},  &#963;={vol_gmv:.6f},  sum(w)={w_gmv.sum():.3f}&#8220;)
print(f&#8221;Tangency E[r]={mu_tan:.6f},  &#963;={vol_tan:.6f},  sum(w)={w_tan.sum():.3f}&#8220;)
print(&#8221;\nGMV weights:&#8221;, np.round(w_gmv, 4))
print(&#8221;Tan weights:&#8221;, np.round(w_tan, 4))
</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8y-j!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f29f164-4563-45a5-9786-37a711aef071_990x590.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8y-j!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f29f164-4563-45a5-9786-37a711aef071_990x590.png 424w, https://substackcdn.com/image/fetch/$s_!8y-j!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f29f164-4563-45a5-9786-37a711aef071_990x590.png 848w, https://substackcdn.com/image/fetch/$s_!8y-j!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f29f164-4563-45a5-9786-37a711aef071_990x590.png 1272w, https://substackcdn.com/image/fetch/$s_!8y-j!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f29f164-4563-45a5-9786-37a711aef071_990x590.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8y-j!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f29f164-4563-45a5-9786-37a711aef071_990x590.png" width="990" height="590" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9f29f164-4563-45a5-9786-37a711aef071_990x590.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:590,&quot;width&quot;:990,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;plot&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="plot" title="plot" srcset="https://substackcdn.com/image/fetch/$s_!8y-j!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f29f164-4563-45a5-9786-37a711aef071_990x590.png 424w, https://substackcdn.com/image/fetch/$s_!8y-j!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f29f164-4563-45a5-9786-37a711aef071_990x590.png 848w, https://substackcdn.com/image/fetch/$s_!8y-j!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f29f164-4563-45a5-9786-37a711aef071_990x590.png 1272w, https://substackcdn.com/image/fetch/$s_!8y-j!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f29f164-4563-45a5-9786-37a711aef071_990x590.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><pre><code>[SYNTHETIC SUMMARY]
GMV:     E[r]=0.001123,  &#963;=0.344942,  sum(w)=1.000
Tangency E[r]=0.002090,  &#963;=0.470481,  sum(w)=1.000

GMV weights: [ 0.2473  0.3281 -0.0938 -0.0937 -0.0412  0.6533]
Tan weights: [ 0.1141  0.7469 -0.174  -0.1761 -0.512   1.0012]
</code></pre><h2><strong>1.3 Assumptions (why the baseline is clean, and why it breaks)</strong></h2><p>MVO is exact under normality or quadratic utility (more generally, elliptical return families) in a single-period setting with known (&#956;,&#931;). In practice, (&#956;,&#931;) are estimated, markets are non-stationary, and constraints/transaction costs are unavoidable. The rest of this notebook is largely about methods that either (i) reduce dependence on fragile estimates, (ii) change the risk objective, or (iii) impose structure to improve out-of-sample stability.</p><div><hr></div><h1><strong>2. How We&#8217;ll Compare Portfolio Optimization Methods in Practice</strong></h1><p>I write about quantitative trading the way it&#8217;s actually practiced:<br>Robust models and portfolios, combining signals and strategies, understanding the assumptions behind your models.</p><p>More broadly, I write about:</p><ul><li><p>Statistical and cross-sectional arbitrage</p></li><li><p>Managing multiple strategies and signals</p></li><li><p>Risk and capital allocation</p></li><li><p>Research tooling and methodology</p></li><li><p>In-depth model assumptions and derivations</p></li></ul><p>If this way of thinking resonates, you&#8217;ll probably like what I publish.</p>
      <p>
          <a href="https://www.vertoxquant.com/p/finding-the-best-portfolio-optimization">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[95% of Stat Arb Strategies Are Built Wrong]]></title><description><![CDATA[Learning to Rank for Cross-Sectional Strategies]]></description><link>https://www.vertoxquant.com/p/learning-to-rank</link><guid isPermaLink="false">https://www.vertoxquant.com/p/learning-to-rank</guid><dc:creator><![CDATA[Vertox]]></dc:creator><pubDate>Thu, 05 Mar 2026 21:10:16 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!_7Je!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6c99df1-af88-4fff-96da-0945290cbab8_1995x670.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>Introduction</h1><p>Most models are trained to predict individual asset returns.</p><p>That seems reasonable. But for cross-sectional strategies, prediction accuracy is often the wrong objective.</p><p>Cross-sectional portfolios turn model outputs into trades by <strong>ranking assets at each rebalance date</strong> and going long the top names while shorting the bottom. Once trades are determined by rank, the absolute level of forecasts often becomes irrelevant: any monotone transformation of model scores produces the same portfolio.</p><p>In other words, <strong>getting the ordering right matters more than predicting returns precisely</strong>.</p><p>This creates a subtle but important mismatch. A model can achieve excellent pointwise accuracy (low RMSE) while producing a weak, or even negative, long&#8211;short spread. Conversely, a model with poor regression metrics may generate strong cross-sectional performance.</p><p>However, ranking is not always all that matters. When position sizing, risk budgeting, transaction cost models, or portfolio optimizers depend on forecast magnitudes and calibration, pointwise accuracy becomes important again.</p><p>In this article, we develop <strong>Learning to Rank (LTR)</strong> as a principled framework for cross-sectional strategies.</p><p>The argument proceeds in three steps:</p><ol><li><p>We formalize the cross-sectional decision problem and show how the score-to-weight mapping determines which properties of model output actually affect PnL.</p></li><li><p>We demonstrate with numerical examples how low RMSE can coexist with negative long&#8211;short spreads, and vice versa.</p></li><li><p>We derive practical LTR objectives for statistical arbitrage, including label engineering, pair weighting, neutralization, and cost-aware evaluation.</p></li></ol><div><hr></div><p>I write about quantitative trading the way it&#8217;s actually practiced:<br>Robust models and portfolios, combining signals and strategies, understanding the assumptions behind your models.</p><p>More broadly, I write about:</p><ul><li><p>Statistical and cross-sectional arbitrage</p></li><li><p>Managing multiple strategies and signals</p></li><li><p>Risk and capital allocation</p></li><li><p>Research tooling and methodology</p></li><li><p>In-depth model assumptions and derivations</p></li></ul><p>If this way of thinking resonates, you&#8217;ll probably like what I publish.</p>
      <p>
          <a href="https://www.vertoxquant.com/p/learning-to-rank">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Discrete Market Making]]></title><description><![CDATA[What every research paper ignores]]></description><link>https://www.vertoxquant.com/p/discrete-market-making</link><guid isPermaLink="false">https://www.vertoxquant.com/p/discrete-market-making</guid><dc:creator><![CDATA[Vertox]]></dc:creator><pubDate>Sat, 28 Feb 2026 14:24:12 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!UTSt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F250b12de-ebfd-440e-ad9c-1d3599bed66e_1349x677.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Classical market-making theory is often developed in a continuous-price setting where quotes can be adjusted by arbitrarily small amounts and fill intensities depend smoothly on the distance to a reference price. </p><p>Real limit order books are discrete: all displayed prices lie on a grid with tick size &gt; 0, and, especially in &#8220;large-tick&#8221; assets, the bid&#8211;ask spread is frequently pinned at one tick. <br>This changes the economics of liquidity provision (where rents come from, how they are competed away, and how adverse selection manifests) and it changes the mathematics of optimal control (from smooth optimization to discrete choice, hybrid/impulse control, and state augmentation for queue position). </p><p>This article provides a rigorous, pedagogical deep-dive that starts from the canonical continuous-time market-making framework and then explains, in detail, why and how tick size and queue priority alter optimal quoting. <br>We then survey the spectrum of modeling and control approaches used in practice: exact discrete-state dynamic programming, queue-aware Markov models, continuous relaxations with discrete corrections, and pragmatic heuristics used when the exact discrete control problem is computationally intractable.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.vertoxquant.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">VertoxQuant is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>I write about quantitative trading the way it&#8217;s actually practiced:<br>Robust models and portfolios, combining signals and strategies, understanding the assumptions behind your models.</p><p>More broadly, I write about:</p><ul><li><p>Statistical and cross-sectional arbitrage</p></li><li><p>Managing multiple strategies and signals</p></li><li><p>Risk and capital allocation</p></li><li><p>Research tooling and methodology</p></li><li><p>In-depth model assumptions and derivations</p></li></ul><p>If this way of thinking resonates, you&#8217;ll probably like what I publish.</p>
      <p>
          <a href="https://www.vertoxquant.com/p/discrete-market-making">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Advanced Regime Algorithms]]></title><description><![CDATA[Final Part of the Regime Series]]></description><link>https://www.vertoxquant.com/p/advanced-regime-algorithms</link><guid isPermaLink="false">https://www.vertoxquant.com/p/advanced-regime-algorithms</guid><dc:creator><![CDATA[Vertox]]></dc:creator><pubDate>Sun, 15 Feb 2026 17:52:35 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!KMs0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffbce0297-f708-47f5-8fde-bd933e7bef19_630x470.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the previous 2 parts of this series, we&#8217;ve looked at all the math behind regime switching models and how you can fit them to real data.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;e090f01e-40bd-4fc5-baf8-c877d7d4682d&quot;,&quot;caption&quot;:&quot;Introduction&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Regime Switching Models for Microstructure Features&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:128680675,&quot;name&quot;:&quot;Vertox&quot;,&quot;bio&quot;:&quot;Quantitative Researcher in Digital Asset Markets | Market Making | Statistical Arbitrage | Options &quot;,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!HGUA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bf3fd86-d46a-4caa-969a-d80059b72cb9_128x128.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2026-01-16T10:19:54.829Z&quot;,&quot;cover_image&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/55b4c663-1e6f-4679-9526-16d93f2985ec_607x392.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.vertoxquant.com/p/regime-switching-models-for-microstructure&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:184740440,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:7,&quot;comment_count&quot;:2,&quot;publication_id&quot;:1726874,&quot;publication_name&quot;:&quot;VertoxQuant&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!ufaQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb77b39-424b-4665-b2a7-7db519ff9e11_128x128.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;3282af87-fe37-44df-ab71-da3830168c54&quot;,&quot;caption&quot;:&quot;Introduction&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Fitting Regime Switching Models to High-Frequency Data&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:128680675,&quot;name&quot;:&quot;Vertox&quot;,&quot;bio&quot;:&quot;Quantitative Researcher in Digital Asset Markets | Market Making | Statistical Arbitrage | Options &quot;,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!HGUA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bf3fd86-d46a-4caa-969a-d80059b72cb9_128x128.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:100}],&quot;post_date&quot;:&quot;2026-01-22T11:54:30.506Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!wRfA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa704e37a-e30a-405e-961f-ed8a5c020d80_627x470.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.vertoxquant.com/p/fitting-regime-switching-models&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:185342697,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:8,&quot;comment_count&quot;:0,&quot;publication_id&quot;:1726874,&quot;publication_name&quot;:&quot;VertoxQuant&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!ufaQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fb77b39-424b-4665-b2a7-7db519ff9e11_128x128.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>In this article, we&#8217;re gonna be covering more advanced regime detection and regime switching algorithms that go beyond HMM, which nobody talks about.</p>
      <p>
          <a href="https://www.vertoxquant.com/p/advanced-regime-algorithms">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Why Mean-Variance Optimization Breaks Down]]></title><description><![CDATA[And how to make it actually work]]></description><link>https://www.vertoxquant.com/p/why-mean-variance-optimization-breaks</link><guid isPermaLink="false">https://www.vertoxquant.com/p/why-mean-variance-optimization-breaks</guid><dc:creator><![CDATA[Vertox]]></dc:creator><pubDate>Tue, 03 Feb 2026 23:01:54 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!YSLy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89f1c92b-a219-4a6b-afc1-7a900bc204d7_925x675.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>Introduction</h1><p>Mean&#8211;Variance Optimization (MVO) is a central framework for portfolio construction: choose weights that balance expected return against risk as measured by variance. </p><p>In its classical form, MVO is elegant, convex (under mild conditions), and analytically tractable. Yet practitioners quickly encounter a paradox: the mathematically &#8220;optimal&#8221; portfolio built from estimated inputs is often unstable, highly leveraged (explicitly or implicitly), and disappoints out-of-sample. </p><p>This is not a minor implementation detail; it is a structural consequence of combining a high-dimensional optimizer with noisy estimates of expected returns and covariances.</p><p>This article develops MVO from first principles and then explains, in a mathematically explicit way, why raw MVO tends to <em>maximize estimation error</em>. </p><p>Finally, it surveys the spectrum of practical fixes, organized around two levers: (i) improving or regularizing the <em>inputs</em> (expected returns and covariances), and (ii) constraining or regularizing the <em>optimizer</em> (the feasible set and the objective). </p><p>The unifying theme is that almost every successful &#8220;fix&#8221; works by injecting <em>bias</em> in exchange for a large reduction in <em>variance</em> of the resulting portfolio weights, thereby improving out-of-sample performance and implementability.</p><h1>The Classical Framework</h1><h3>Notation</h3><p>Consider N risky assets. Let the random vector of (excess) returns over a single period be</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;r \\in \\mathbb{R}^N&quot;,&quot;id&quot;:&quot;DXJEASSNKD&quot;}" data-component-name="LatexBlockToDOM"></div><p>Define the (unknown) population mean and covariance</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mu = \\mathbb{E}[r] \\in \\mathbb{R}^N, \\quad \\Sigma = \\text{Cov}(r) = \\mathbb{E}[(r-\\mu)(r-\\mu)^T] \\in \\mathbb{R}^{N \\times N}&quot;,&quot;id&quot;:&quot;OQAZGOEAXF&quot;}" data-component-name="LatexBlockToDOM"></div><p>A portfolio is a weight vector interpreted as a fraction of capital invested in each asset.</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;w \\in \\mathbb{R}^N&quot;,&quot;id&quot;:&quot;VTRUQWXCRE&quot;}" data-component-name="LatexBlockToDOM"></div><p>The basic budget constraint is </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\textbf{1}^T w = 1&quot;,&quot;id&quot;:&quot;ILZQVLJPCJ&quot;}" data-component-name="LatexBlockToDOM"></div><p>where 1 denotes the all-ones vector in R^N. In other words, the weights should sum up to 1. Additional constraints like no-short, leverage limits, or sector bounds will be presented in the following chapters.</p><p>Under this setup, the portfolio return is linear in weights:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;r_p = w^T r&quot;,&quot;id&quot;:&quot;IZUDEUJGGR&quot;}" data-component-name="LatexBlockToDOM"></div><p>The expected portfolio return and variance are</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathbb{E}[r_p] = w^T \\mu,\\quad \\text{Var}(r_p) = w^T \\Sigma w&quot;,&quot;id&quot;:&quot;OKCVBDGETX&quot;}" data-component-name="LatexBlockToDOM"></div><p>Two foundational facts are worth stating explicitly because they explain why MVO becomes a quadratic program:</p><p>1. <strong>Expected return is linear in weights.</strong> This makes the &#8220;reward&#8221; side easy to compute but also extremely sensitive to errors in mu, because the optimizer can exploit tiny differences in mu via large weight changes.</p><p>2. <strong>Variance is quadratic in weights.</strong> The covariance matrix Sigma couples assets through correlations: diversification is precisely the exploitation of off-diagonal terms in Sigma. The quadratic form w^T Sigma w is convex in w if Sigma is positive semidefinite, and strictly convex if Sigma is positive definite, which ensures the uniqueness of the minimum-variance solution under typical linear constraints.</p><h3>The Markowitz Problem in Matrix Form</h3><p>Markowitz&#8217;s original formulation can be stated as: <strong>among all portfolios with a given expected return, choose the one with minimum variance.</strong> Fix a target expected return m. The constrained optimization is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\begin{aligned}\n\\min_{w \\in \\mathbb{R}^N} \\quad &amp; w^\\top \\Sigma w \\\\\n\\text{s.t.} \\quad &amp; w^\\top \\mu = m, \\\\\n&amp; \\mathbf{1}^\\top w = 1.\n\\end{aligned}\n\\tag{MVO-1}&quot;,&quot;id&quot;:&quot;GYRGSOBCBD&quot;}" data-component-name="LatexBlockToDOM"></div><p>If short-selling is disallowed, one adds w &gt;= 0 componentwise. If leverage is limited, one might add |w|_1 &lt;= L, where |.| denotes the L1 norm, and so on.</p><p>Why is the covariance matrix central here? Because for any two assets i and j,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;w^\\top \\Sigma w = \\sum_{i=1}^N \\sum_{j=1}^N w_i w_j \\Sigma_{ij}.&quot;,&quot;id&quot;:&quot;JQJAZPFYMX&quot;}" data-component-name="LatexBlockToDOM"></div><p>The diagonal terms w_i^2 Sigma_{ii} represent contributions from each asset&#8217;s variance; the off-diagonal terms w_i w_j Sigma_{ij} represent interaction through co-movement. Diversification is not &#8220;holding many assets&#8221; per se; it is selecting weights so that positive and negative interactions among returns reduce overall variance.</p><p>A subtle but important point: variance is a <em>second-moment</em> object. It treats positive and negative deviations symmetrically and is fully described by Sigma. This makes MVO analytically convenient, but it also means the framework inherits all limitations of second-moment risk measures; non-normality, fat tails, and asymmetry are not captured unless the distribution is (approximately) elliptical. In many institutional contexts, however, variance remains a useful proxy because it aligns with tracking error, volatility targets, and risk budgeting infrastructure.</p><h3>The penalized (risk-aversion) form and its equivalence</h3><p>An equivalent way to pose the trade-off is to maximize a mean-variance utility function:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\begin{aligned}\n\\max_{w \\in \\mathbb{R}^N}\n&amp;\\quad w^\\top \\mu - \\frac{\\gamma}{2} w^\\top \\Sigma w \\\\\n\\text{s.t.}\n&amp;\\quad \\mathbf{1}^\\top w = 1,\n\\end{aligned}\n\\tag{MVO-2}&quot;,&quot;id&quot;:&quot;AFACIPTTPD&quot;}" data-component-name="LatexBlockToDOM"></div><p>where gamma &gt; 0 is the risk-aversion parameter. Larger gamma penalized variance more heavily, shifting the solution toward lower-risk portfolios.</p><p>The equivalence between (MVO-1) and (MVO-2) is practically important. The constrained form (MVO-1) traces the <em>efficient frontier</em> by varying m. The penalized form (MVO-2) traces it by varying gamma. In many production systems, gamma is tuned to meet a risk target or tracking error budget.</p><h3>Solving the classical problem: Lagrangian and closed-form structure</h3><p>To make mechanics concrete, consider (MVO-2) without additional constraints beyond the budget constraint. Form the Lagrangian</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathcal{L}(w,\\eta) = w^\\top \\mu - \\frac{\\gamma}{2} w^\\top \\Sigma w - \\eta(\\mathbf{1}^\\top w - 1)&quot;,&quot;id&quot;:&quot;AXGVJDEVCW&quot;}" data-component-name="LatexBlockToDOM"></div><p>with Lagrange multiplier eta enforcing 1^T w = 1.</p><p>First-order optimality (assuming Sigma is positive definite) gives</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\nabla_w \\mathcal{L} = \\mu - \\gamma \\Sigma w - \\eta \\mathbf{1} = 0&quot;,&quot;id&quot;:&quot;HGECWVLMCG&quot;}" data-component-name="LatexBlockToDOM"></div><p>hence</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;w = \\frac{1}{\\gamma}\\Sigma^{-1}(\\mu - \\eta \\mathbf{1}).\n\\tag{1.1}&quot;,&quot;id&quot;:&quot;VFWLAWWKYZ&quot;}" data-component-name="LatexBlockToDOM"></div><p>Imposing the budget constraint 1^T w = 1 yields</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathbf{1}^\\top \\left(\\frac{1}{\\gamma}\\Sigma^{-1}(\\mu - \\eta \\mathbf{1})\\right) = 1&quot;,&quot;id&quot;:&quot;DNHOOPRQVN&quot;}" data-component-name="LatexBlockToDOM"></div><p>so</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\eta = \\frac{\\mathbf{1}^\\top \\Sigma^{-1}\\mu - \\gamma}{\\mathbf{1}^\\top \\Sigma^{-1}\\mathbf{1}}.\n\\tag{1.2}&quot;,&quot;id&quot;:&quot;QTGAPENBDF&quot;}" data-component-name="LatexBlockToDOM"></div><p>Substituting (1.2) into (1.1) gives the explicit optimizer.</p><p>This expression reveals a key structural fact that will matter later: the optimal weights are built from Sigma^{-1} mu and Sigma^{-1} 1. In other words, the inverse covariance matrix is the central operator transforming expected returns into weights. When Sigma^{-1} is unstable (ill-conditioned or poorly estimated), the entire solution becomes unstable.</p><p>For the return-target form (MVO-1), the Lagrangian with multiplies lambda, eta is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathcal{L}(w,\\lambda,\\eta) = w^\\top \\Sigma w - \\lambda(w^\\top \\mu - m) - \\eta(\\mathbf{1}^\\top w - 1)&quot;,&quot;id&quot;:&quot;WLXKGLWZBC&quot;}" data-component-name="LatexBlockToDOM"></div><p>The first-order condition is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\nabla_w \\mathcal{L} = 2\\Sigma w - \\lambda \\mu - \\eta \\mathbf{1} = 0\n\\quad\\Rightarrow\\quad\nw = \\frac{1}{2}\\Sigma^{-1}(\\lambda \\mu + \\eta \\mathbf{1}).\n\\tag{1.3}&quot;,&quot;id&quot;:&quot;PAEDPEDVSD&quot;}" data-component-name="LatexBlockToDOM"></div><p>Define the classical scalars</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;A \\equiv \\mathbf{1}^\\top \\Sigma^{-1}\\mathbf{1},\n\\qquad\nB \\equiv \\mathbf{1}^\\top \\Sigma^{-1}\\mu,\n\\qquad\nC \\equiv \\mu^\\top \\Sigma^{-1}\\mu,\n\\qquad\n\\Delta \\equiv AC - B^2.\n\\tag{1.4}&quot;,&quot;id&quot;:&quot;CCMMOQGFXH&quot;}" data-component-name="LatexBlockToDOM"></div><p>Assuming Sigma is positive definite and mu is not collinear with 1 under Sigma^{-1}, one has Delta &gt; 0. Solving for lambda, eta yields a closed-form frontier, and the efficient frontier in (sigma^2, m) space is a parabola:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\sigma^2(m) = \\frac{1}{\\Delta}\\left(A m^2 - 2 B m + C\\right).\n\\tag{1.5}&quot;,&quot;id&quot;:&quot;OZARCSAANG&quot;}" data-component-name="LatexBlockToDOM"></div><p>The frontier&#8217;s curvature and location are completely determined by (A,B,C), i.e., by Sigma^{-1} and mu. This already hints at the practical challenge: <em>every point</em> on the frontier depends on inverting Sigma and multiplying by mu, precisely the operations most vulnerable to estimation noise.</p><p>Let&#8217;s implement this in Python and look at the resulting efficient frontier. We will also compare our closed-form solution of (MVO-1) to a numerical solution to verify that we did everything right.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!y1i8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4abd3aa2-d2c4-4f74-aaad-2cab602bc66d_636x714.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!y1i8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4abd3aa2-d2c4-4f74-aaad-2cab602bc66d_636x714.png 424w, https://substackcdn.com/image/fetch/$s_!y1i8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4abd3aa2-d2c4-4f74-aaad-2cab602bc66d_636x714.png 848w, https://substackcdn.com/image/fetch/$s_!y1i8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4abd3aa2-d2c4-4f74-aaad-2cab602bc66d_636x714.png 1272w, https://substackcdn.com/image/fetch/$s_!y1i8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4abd3aa2-d2c4-4f74-aaad-2cab602bc66d_636x714.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!y1i8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4abd3aa2-d2c4-4f74-aaad-2cab602bc66d_636x714.png" width="346" height="388.4339622641509" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4abd3aa2-d2c4-4f74-aaad-2cab602bc66d_636x714.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:714,&quot;width&quot;:636,&quot;resizeWidth&quot;:346,&quot;bytes&quot;:100899,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4abd3aa2-d2c4-4f74-aaad-2cab602bc66d_636x714.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!y1i8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4abd3aa2-d2c4-4f74-aaad-2cab602bc66d_636x714.png 424w, https://substackcdn.com/image/fetch/$s_!y1i8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4abd3aa2-d2c4-4f74-aaad-2cab602bc66d_636x714.png 848w, https://substackcdn.com/image/fetch/$s_!y1i8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4abd3aa2-d2c4-4f74-aaad-2cab602bc66d_636x714.png 1272w, https://substackcdn.com/image/fetch/$s_!y1i8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4abd3aa2-d2c4-4f74-aaad-2cab602bc66d_636x714.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Import Libraries</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZKMb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2925178-dbf8-4ad9-a78c-e0deac3a6d60_1664x4178.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZKMb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2925178-dbf8-4ad9-a78c-e0deac3a6d60_1664x4178.png 424w, https://substackcdn.com/image/fetch/$s_!ZKMb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2925178-dbf8-4ad9-a78c-e0deac3a6d60_1664x4178.png 848w, https://substackcdn.com/image/fetch/$s_!ZKMb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2925178-dbf8-4ad9-a78c-e0deac3a6d60_1664x4178.png 1272w, https://substackcdn.com/image/fetch/$s_!ZKMb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2925178-dbf8-4ad9-a78c-e0deac3a6d60_1664x4178.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZKMb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2925178-dbf8-4ad9-a78c-e0deac3a6d60_1664x4178.png" width="1456" height="3656" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b2925178-dbf8-4ad9-a78c-e0deac3a6d60_1664x4178.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:3656,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1021950,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2925178-dbf8-4ad9-a78c-e0deac3a6d60_1664x4178.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ZKMb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2925178-dbf8-4ad9-a78c-e0deac3a6d60_1664x4178.png 424w, https://substackcdn.com/image/fetch/$s_!ZKMb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2925178-dbf8-4ad9-a78c-e0deac3a6d60_1664x4178.png 848w, https://substackcdn.com/image/fetch/$s_!ZKMb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2925178-dbf8-4ad9-a78c-e0deac3a6d60_1664x4178.png 1272w, https://substackcdn.com/image/fetch/$s_!ZKMb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2925178-dbf8-4ad9-a78c-e0deac3a6d60_1664x4178.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gwOY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F119cf744-dd09-4003-b9a7-27ee00b23847_862x731.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gwOY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F119cf744-dd09-4003-b9a7-27ee00b23847_862x731.png 424w, https://substackcdn.com/image/fetch/$s_!gwOY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F119cf744-dd09-4003-b9a7-27ee00b23847_862x731.png 848w, https://substackcdn.com/image/fetch/$s_!gwOY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F119cf744-dd09-4003-b9a7-27ee00b23847_862x731.png 1272w, https://substackcdn.com/image/fetch/$s_!gwOY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F119cf744-dd09-4003-b9a7-27ee00b23847_862x731.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gwOY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F119cf744-dd09-4003-b9a7-27ee00b23847_862x731.png" width="862" height="731" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/119cf744-dd09-4003-b9a7-27ee00b23847_862x731.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:731,&quot;width&quot;:862,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:100442,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F119cf744-dd09-4003-b9a7-27ee00b23847_862x731.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!gwOY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F119cf744-dd09-4003-b9a7-27ee00b23847_862x731.png 424w, https://substackcdn.com/image/fetch/$s_!gwOY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F119cf744-dd09-4003-b9a7-27ee00b23847_862x731.png 848w, https://substackcdn.com/image/fetch/$s_!gwOY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F119cf744-dd09-4003-b9a7-27ee00b23847_862x731.png 1272w, https://substackcdn.com/image/fetch/$s_!gwOY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F119cf744-dd09-4003-b9a7-27ee00b23847_862x731.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>As you can see, our closed-form solution and numerical solution are pretty much identical, and the (MVO-2) solutions lie on the efficient frontier traced by the (MVO-1) solution, so they are indeed equivalent.</p><h3>Interpreting Sigma: Risk Geometry and Diversification</h3><p>It is useful to interpret the quadratic form geometrically. If Sigma is positive definite, then the set of portfolios with equal variance sigma^2,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;w : w^T \\Sigma w = \\sigma^2&quot;,&quot;id&quot;:&quot;TPCBCBSCAV&quot;}" data-component-name="LatexBlockToDOM"></div><p>is an ellipsoid in weight space. The optimizer in (MVO-2) chooses the point on the budget hyperplane {1^T w = 1} that maximizes a linear functional w^T mu minus a quadratic penalty. The optimum balances moving &#8220;up&#8221; in the direction of mu while staying within low-risk ellipsoids determined by Sigma.</p><p>This picture is clean when mu and Sigma are known. The moment we replace them with estimates, the ellipsoids tilt and stretch unpredictably, and the direction of &#8220;up&#8221; becomes noisy. The optimizer, being deterministic, will still choose an extreme point, often an extreme point <em>of the wrong geometry</em>. That is the beginning of the &#8220;error maximization&#8221; story.</p><p>Here is an example using two assets:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UFnE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ed8ab27-157a-45d1-b663-8dc219b9dea5_1460x2502.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UFnE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ed8ab27-157a-45d1-b663-8dc219b9dea5_1460x2502.png 424w, https://substackcdn.com/image/fetch/$s_!UFnE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ed8ab27-157a-45d1-b663-8dc219b9dea5_1460x2502.png 848w, https://substackcdn.com/image/fetch/$s_!UFnE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ed8ab27-157a-45d1-b663-8dc219b9dea5_1460x2502.png 1272w, https://substackcdn.com/image/fetch/$s_!UFnE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ed8ab27-157a-45d1-b663-8dc219b9dea5_1460x2502.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UFnE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ed8ab27-157a-45d1-b663-8dc219b9dea5_1460x2502.png" width="1456" height="2495" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1ed8ab27-157a-45d1-b663-8dc219b9dea5_1460x2502.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2495,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:585130,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ed8ab27-157a-45d1-b663-8dc219b9dea5_1460x2502.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!UFnE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ed8ab27-157a-45d1-b663-8dc219b9dea5_1460x2502.png 424w, https://substackcdn.com/image/fetch/$s_!UFnE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ed8ab27-157a-45d1-b663-8dc219b9dea5_1460x2502.png 848w, https://substackcdn.com/image/fetch/$s_!UFnE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ed8ab27-157a-45d1-b663-8dc219b9dea5_1460x2502.png 1272w, https://substackcdn.com/image/fetch/$s_!UFnE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ed8ab27-157a-45d1-b663-8dc219b9dea5_1460x2502.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Io61!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd63bea25-aa77-43d6-8593-9d99ccf93dbf_835x714.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Io61!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd63bea25-aa77-43d6-8593-9d99ccf93dbf_835x714.png 424w, https://substackcdn.com/image/fetch/$s_!Io61!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd63bea25-aa77-43d6-8593-9d99ccf93dbf_835x714.png 848w, https://substackcdn.com/image/fetch/$s_!Io61!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd63bea25-aa77-43d6-8593-9d99ccf93dbf_835x714.png 1272w, https://substackcdn.com/image/fetch/$s_!Io61!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd63bea25-aa77-43d6-8593-9d99ccf93dbf_835x714.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Io61!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd63bea25-aa77-43d6-8593-9d99ccf93dbf_835x714.png" width="835" height="714" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d63bea25-aa77-43d6-8593-9d99ccf93dbf_835x714.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:714,&quot;width&quot;:835,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:163769,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd63bea25-aa77-43d6-8593-9d99ccf93dbf_835x714.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Io61!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd63bea25-aa77-43d6-8593-9d99ccf93dbf_835x714.png 424w, https://substackcdn.com/image/fetch/$s_!Io61!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd63bea25-aa77-43d6-8593-9d99ccf93dbf_835x714.png 848w, https://substackcdn.com/image/fetch/$s_!Io61!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd63bea25-aa77-43d6-8593-9d99ccf93dbf_835x714.png 1272w, https://substackcdn.com/image/fetch/$s_!Io61!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd63bea25-aa77-43d6-8593-9d99ccf93dbf_835x714.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Each ellipse here corresponds to portfolios with equal variance. As you can see, our optimal portfolio just barely touches the 0.03 variance ellipsoid, and any other portfolio on the line (that satisfies the budget constraint) results in a higher variance.</p><h1>The &#8220;Error Maximization&#8221; Problem</h1><p>Raw MVO is often described informally as &#8220;garbage in, garbage out.&#8221; That statement is true, but it understates the severity: MVO does not merely <em>propagate</em> input error; it can <em>amplify</em> it. In high dimensions, the amplification can be dramatic enough that the optimizer effectively learns the noise in the estimated inputs.</p><p>This section makes that mechanism explicit.</p><h3>MVO is not an optimization problem; it is a statistical decision problem</h3><p>In theory, (mu, Sigma) are population quantities. In practice, we never observe mu or Sigma. We observe a finite time series </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\{r_t\\}_{t=1}^T&quot;,&quot;id&quot;:&quot;UECBRRYTXX&quot;}" data-component-name="LatexBlockToDOM"></div><p>and produce estimators hat{mu} and hat{Sigma}. The most common &#8220;plug-in&#8221; estimators are the sample mean and covariance</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\hat{\\mu} = \\frac{1}{T} \\sum_{t=1}^T r_t,\n\\qquad\n\\hat{\\Sigma} = \\frac{1}{T-1} \\sum_{t=1}^T (r_t - \\hat{\\mu})(r_t - \\hat{\\mu})^\\top.\n\\tag{2.1}&quot;,&quot;id&quot;:&quot;WXOPRVJYJN&quot;}" data-component-name="LatexBlockToDOM"></div><p>Then the raw MVO portfolio is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\hat{w} = \\arg\\max_{w:\\mathbf{1}^\\top w=1} \\left(w^\\top \\hat{\\mu} - \\frac{\\gamma}{2} w^\\top \\hat{\\Sigma} w\\right)&quot;,&quot;id&quot;:&quot;RLOFYECSIB&quot;}" data-component-name="LatexBlockToDOM"></div><p>or its return-target equivalent.</p><p>Crucially, hat{w} is a function of the random sample; it is itself random. The &#8220;true&#8221; objective we actually care about is out-of-sample performance under the <em>true </em>distribution, e.g., maximizing</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;U(w) \\equiv w^\\top \\mu - \\frac{\\gamma}{2} w^\\top \\Sigma w.\n\n\\tag{2.2}&quot;,&quot;id&quot;:&quot;XQSDDTKVYM&quot;}" data-component-name="LatexBlockToDOM"></div><p>But plug-in MVO maximizes a different random objective,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\hat{U}(w) \\equiv w^\\top \\hat{\\mu} - \\frac{\\gamma}{2} w^\\top \\hat{\\Sigma} w.\n\n\\tag{2.3}&quot;,&quot;id&quot;:&quot;YKBBLRIQSR&quot;}" data-component-name="LatexBlockToDOM"></div><p>The practical question is not &#8220;is hat{w} optimal for hat{U}?&#8221; (it is, by construction), but &#8220;how does U(hat{w}) compare to U(w^\star), where w^\star maximizes U?&#8221; That gap is the cost of estimation error and model uncertainty.</p><h3>Why expected return estimation is the Achilles&#8217; heel</h3><p>Start with expected returns. For each asset i, the sample mean hat{mu}_i has a standard error on the order of</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathrm{SE}(\\hat{\\mu}_i) \\approx \\frac{\\sigma_i}{\\sqrt{T}},\n\n\\tag{2.4}&quot;,&quot;id&quot;:&quot;QBCUWBOKMX&quot;}" data-component-name="LatexBlockToDOM"></div><p>where </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\sigma_i^2 = \\Sigma_{ii}&quot;,&quot;id&quot;:&quot;ESACLAECCV&quot;}" data-component-name="LatexBlockToDOM"></div><p>In many liquid asset classes, annualized volatilities might be 10% - 30% while annualized expected excess returns might be 2% - 8%. Translating to a monthly scale, the noise in the sample mean can be comparable to, or larger than, the signal. This is a fundamental signal-to-noise limitation, not an implementation defect.</p><p>Now multiply that limitation by dimensionality. MVO compares assets and tries to exploit differences in mu. When mu is noisy, the differences the optimizer sees are often dominated by noise. The optimizer is then rewarded (in-sample) for taking large positions in the assets that happened to have high realized returns in the estimation window, even if that was random luck.</p><p>Because the expected return term w^T mu is linear, <em>any </em>error in mu shifts the gradient of the objective directly. In contrast, the covariance term is quadratic and tends to act as a smoothness penalty. This asymmetry is why MVO is particularly fragile to errors in mu. </p><p>Here is a simple numerical simulation of how much noise can affect our estimate of mu:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oPBm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7be7643d-c3d2-4624-ac66-26c22a86b3cb_1378x1682.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oPBm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7be7643d-c3d2-4624-ac66-26c22a86b3cb_1378x1682.png 424w, https://substackcdn.com/image/fetch/$s_!oPBm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7be7643d-c3d2-4624-ac66-26c22a86b3cb_1378x1682.png 848w, https://substackcdn.com/image/fetch/$s_!oPBm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7be7643d-c3d2-4624-ac66-26c22a86b3cb_1378x1682.png 1272w, https://substackcdn.com/image/fetch/$s_!oPBm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7be7643d-c3d2-4624-ac66-26c22a86b3cb_1378x1682.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oPBm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7be7643d-c3d2-4624-ac66-26c22a86b3cb_1378x1682.png" width="1378" height="1682" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7be7643d-c3d2-4624-ac66-26c22a86b3cb_1378x1682.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1682,&quot;width&quot;:1378,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:417844,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7be7643d-c3d2-4624-ac66-26c22a86b3cb_1378x1682.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!oPBm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7be7643d-c3d2-4624-ac66-26c22a86b3cb_1378x1682.png 424w, https://substackcdn.com/image/fetch/$s_!oPBm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7be7643d-c3d2-4624-ac66-26c22a86b3cb_1378x1682.png 848w, https://substackcdn.com/image/fetch/$s_!oPBm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7be7643d-c3d2-4624-ac66-26c22a86b3cb_1378x1682.png 1272w, https://substackcdn.com/image/fetch/$s_!oPBm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7be7643d-c3d2-4624-ac66-26c22a86b3cb_1378x1682.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5ATM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8441174-4f4c-43d9-a982-d81dade42684_834x596.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5ATM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8441174-4f4c-43d9-a982-d81dade42684_834x596.png 424w, https://substackcdn.com/image/fetch/$s_!5ATM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8441174-4f4c-43d9-a982-d81dade42684_834x596.png 848w, https://substackcdn.com/image/fetch/$s_!5ATM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8441174-4f4c-43d9-a982-d81dade42684_834x596.png 1272w, https://substackcdn.com/image/fetch/$s_!5ATM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8441174-4f4c-43d9-a982-d81dade42684_834x596.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5ATM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8441174-4f4c-43d9-a982-d81dade42684_834x596.png" width="834" height="596" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a8441174-4f4c-43d9-a982-d81dade42684_834x596.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:596,&quot;width&quot;:834,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:45358,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8441174-4f4c-43d9-a982-d81dade42684_834x596.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5ATM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8441174-4f4c-43d9-a982-d81dade42684_834x596.png 424w, https://substackcdn.com/image/fetch/$s_!5ATM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8441174-4f4c-43d9-a982-d81dade42684_834x596.png 848w, https://substackcdn.com/image/fetch/$s_!5ATM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8441174-4f4c-43d9-a982-d81dade42684_834x596.png 1272w, https://substackcdn.com/image/fetch/$s_!5ATM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8441174-4f4c-43d9-a982-d81dade42684_834x596.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>And now the impact on our portfolio weights from MVO. We assume 20 assets with identical true means, so any variation in mu is pure noise.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Dyjw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfadaa02-cddd-41f6-85dc-7802cfb18328_1546x1980.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Dyjw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfadaa02-cddd-41f6-85dc-7802cfb18328_1546x1980.png 424w, https://substackcdn.com/image/fetch/$s_!Dyjw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfadaa02-cddd-41f6-85dc-7802cfb18328_1546x1980.png 848w, https://substackcdn.com/image/fetch/$s_!Dyjw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfadaa02-cddd-41f6-85dc-7802cfb18328_1546x1980.png 1272w, https://substackcdn.com/image/fetch/$s_!Dyjw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfadaa02-cddd-41f6-85dc-7802cfb18328_1546x1980.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Dyjw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfadaa02-cddd-41f6-85dc-7802cfb18328_1546x1980.png" width="1456" height="1865" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dfadaa02-cddd-41f6-85dc-7802cfb18328_1546x1980.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1865,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:553274,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfadaa02-cddd-41f6-85dc-7802cfb18328_1546x1980.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Dyjw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfadaa02-cddd-41f6-85dc-7802cfb18328_1546x1980.png 424w, https://substackcdn.com/image/fetch/$s_!Dyjw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfadaa02-cddd-41f6-85dc-7802cfb18328_1546x1980.png 848w, https://substackcdn.com/image/fetch/$s_!Dyjw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfadaa02-cddd-41f6-85dc-7802cfb18328_1546x1980.png 1272w, https://substackcdn.com/image/fetch/$s_!Dyjw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfadaa02-cddd-41f6-85dc-7802cfb18328_1546x1980.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zLAC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F714d518e-04be-4c8c-9084-c29078ed0ed5_834x576.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zLAC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F714d518e-04be-4c8c-9084-c29078ed0ed5_834x576.png 424w, https://substackcdn.com/image/fetch/$s_!zLAC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F714d518e-04be-4c8c-9084-c29078ed0ed5_834x576.png 848w, https://substackcdn.com/image/fetch/$s_!zLAC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F714d518e-04be-4c8c-9084-c29078ed0ed5_834x576.png 1272w, https://substackcdn.com/image/fetch/$s_!zLAC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F714d518e-04be-4c8c-9084-c29078ed0ed5_834x576.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zLAC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F714d518e-04be-4c8c-9084-c29078ed0ed5_834x576.png" width="834" height="576" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/714d518e-04be-4c8c-9084-c29078ed0ed5_834x576.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:576,&quot;width&quot;:834,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:49704,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F714d518e-04be-4c8c-9084-c29078ed0ed5_834x576.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!zLAC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F714d518e-04be-4c8c-9084-c29078ed0ed5_834x576.png 424w, https://substackcdn.com/image/fetch/$s_!zLAC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F714d518e-04be-4c8c-9084-c29078ed0ed5_834x576.png 848w, https://substackcdn.com/image/fetch/$s_!zLAC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F714d518e-04be-4c8c-9084-c29078ed0ed5_834x576.png 1272w, https://substackcdn.com/image/fetch/$s_!zLAC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F714d518e-04be-4c8c-9084-c29078ed0ed5_834x576.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Our gross exposure is through the roof! A typical MVO portfolio here is equivalent to 200% long and 200% short, 4x leverage. Our right tail on Gross Exposure is also huge, so the portfolio sometimes ends up being 6x levered. The largest single position is also 54% of the portfolio, even though we have 20 assets. </p><p>This shows just how much of an extreme impact estimation noise in mu has on MVO.</p><h3>Why covariance estimation becomes dangerous when inverted</h3><p>The second failure mode is subtler: even if covariance estimates are &#8220;more stable&#8221; than mean estimates, the optimizer requires hat{Sigma}^{-1}. Inversion is the mathematical operation that turns moderate estimation noise into potentially huge weight noise.</p><p>To see why, consider the eigen-decomposition of the true covariance matrix:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\Sigma = Q \\Lambda Q^\\top,&quot;,&quot;id&quot;:&quot;CXNAYUWXTW&quot;}" data-component-name="LatexBlockToDOM"></div><p>where Q is orthonormal and </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\Lambda = \\mathrm{diag}(\\lambda_1,\\dots,\\lambda_N)&quot;,&quot;id&quot;:&quot;WGXCYPVHLX&quot;}" data-component-name="LatexBlockToDOM"></div><p>with lambda_i &gt; 0$ if Sigma is positive definite. Then</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\Sigma^{-1} = Q \\Lambda^{-1} Q^\\top\n\n\\quad\\text{with}\\quad\n\n\\Lambda^{-1} = \\mathrm{diag}\\left(\\frac{1}{\\lambda_1},\\dots,\\frac{1}{\\lambda_N}\\right).\n\n\\tag{2.5}&quot;,&quot;id&quot;:&quot;CVMINHPAJE&quot;}" data-component-name="LatexBlockToDOM"></div><p>Small eigenvalues become large eigenvalues after inversion. In portfolio terms, eigenvectors associated with small variance directions are precisely the directions the optimizer finds attractive: they offer &#8220;cheap risk.&#8221; But in finite samples, the smallest eigenvalues of hat{Sigma} are often dominated by noise (especially when T is not much larger than N). When the optimizer leans on these noisy low-variance directions, it produces extreme, unstable weights.</p><p>This is not hypothetical. A basic dimensionality fact already creates a hard boundary: if T &lt; N, the sample covariance hat{Sigma} is singular (rank at most T-1), so hat{Sigma}^{-1} does not exist. Even if T is only moderately larger than N, hat{Sigma} can be ill-conditioned, making numerical inversion unstable and conceptually unreliable.</p><p>Let&#8217;s consider three cases: T &lt; N, T &#8776; N, and T &gt; N, and look at the impact that T has on the estimated eigenvalues:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HU4y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1231b88-9651-4502-b7fd-6261a961bcbf_1662x2428.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HU4y!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1231b88-9651-4502-b7fd-6261a961bcbf_1662x2428.png 424w, https://substackcdn.com/image/fetch/$s_!HU4y!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1231b88-9651-4502-b7fd-6261a961bcbf_1662x2428.png 848w, https://substackcdn.com/image/fetch/$s_!HU4y!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1231b88-9651-4502-b7fd-6261a961bcbf_1662x2428.png 1272w, https://substackcdn.com/image/fetch/$s_!HU4y!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1231b88-9651-4502-b7fd-6261a961bcbf_1662x2428.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HU4y!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1231b88-9651-4502-b7fd-6261a961bcbf_1662x2428.png" width="1456" height="2127" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e1231b88-9651-4502-b7fd-6261a961bcbf_1662x2428.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2127,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:602660,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1231b88-9651-4502-b7fd-6261a961bcbf_1662x2428.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!HU4y!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1231b88-9651-4502-b7fd-6261a961bcbf_1662x2428.png 424w, https://substackcdn.com/image/fetch/$s_!HU4y!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1231b88-9651-4502-b7fd-6261a961bcbf_1662x2428.png 848w, https://substackcdn.com/image/fetch/$s_!HU4y!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1231b88-9651-4502-b7fd-6261a961bcbf_1662x2428.png 1272w, https://substackcdn.com/image/fetch/$s_!HU4y!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1231b88-9651-4502-b7fd-6261a961bcbf_1662x2428.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Wm1P!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68f5a8b2-f9b5-468b-925a-fcdd0da41f4b_881x685.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Wm1P!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68f5a8b2-f9b5-468b-925a-fcdd0da41f4b_881x685.png 424w, https://substackcdn.com/image/fetch/$s_!Wm1P!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68f5a8b2-f9b5-468b-925a-fcdd0da41f4b_881x685.png 848w, https://substackcdn.com/image/fetch/$s_!Wm1P!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68f5a8b2-f9b5-468b-925a-fcdd0da41f4b_881x685.png 1272w, https://substackcdn.com/image/fetch/$s_!Wm1P!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68f5a8b2-f9b5-468b-925a-fcdd0da41f4b_881x685.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Wm1P!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68f5a8b2-f9b5-468b-925a-fcdd0da41f4b_881x685.png" width="881" height="685" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/68f5a8b2-f9b5-468b-925a-fcdd0da41f4b_881x685.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:685,&quot;width&quot;:881,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:95156,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68f5a8b2-f9b5-468b-925a-fcdd0da41f4b_881x685.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Wm1P!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68f5a8b2-f9b5-468b-925a-fcdd0da41f4b_881x685.png 424w, https://substackcdn.com/image/fetch/$s_!Wm1P!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68f5a8b2-f9b5-468b-925a-fcdd0da41f4b_881x685.png 848w, https://substackcdn.com/image/fetch/$s_!Wm1P!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68f5a8b2-f9b5-468b-925a-fcdd0da41f4b_881x685.png 1272w, https://substackcdn.com/image/fetch/$s_!Wm1P!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68f5a8b2-f9b5-468b-925a-fcdd0da41f4b_881x685.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>You can clearly see one thing: For the estimates where T = 30, Sigma becomes singular, and the 30th and further smallest eigenvalues just become 0. For T = 80, we can still see that the smaller eigenvalues are systematically underestimated. The estimates become better as we increase T to 300.</p><p>Now, let&#8217;s look at estiamted eigenvalues of Sigma and Sigma^{-1} for T=300:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FSWx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F141d26e2-0907-493a-a140-3aa9c2fa1ed6_1396x676.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FSWx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F141d26e2-0907-493a-a140-3aa9c2fa1ed6_1396x676.png 424w, https://substackcdn.com/image/fetch/$s_!FSWx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F141d26e2-0907-493a-a140-3aa9c2fa1ed6_1396x676.png 848w, https://substackcdn.com/image/fetch/$s_!FSWx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F141d26e2-0907-493a-a140-3aa9c2fa1ed6_1396x676.png 1272w, https://substackcdn.com/image/fetch/$s_!FSWx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F141d26e2-0907-493a-a140-3aa9c2fa1ed6_1396x676.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FSWx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F141d26e2-0907-493a-a140-3aa9c2fa1ed6_1396x676.png" width="1396" height="676" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/141d26e2-0907-493a-a140-3aa9c2fa1ed6_1396x676.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:676,&quot;width&quot;:1396,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:179242,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F141d26e2-0907-493a-a140-3aa9c2fa1ed6_1396x676.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!FSWx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F141d26e2-0907-493a-a140-3aa9c2fa1ed6_1396x676.png 424w, https://substackcdn.com/image/fetch/$s_!FSWx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F141d26e2-0907-493a-a140-3aa9c2fa1ed6_1396x676.png 848w, https://substackcdn.com/image/fetch/$s_!FSWx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F141d26e2-0907-493a-a140-3aa9c2fa1ed6_1396x676.png 1272w, https://substackcdn.com/image/fetch/$s_!FSWx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F141d26e2-0907-493a-a140-3aa9c2fa1ed6_1396x676.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sEAN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0abc3b1-0dbc-41a3-870a-d7a33a9d4d1d_872x536.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sEAN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0abc3b1-0dbc-41a3-870a-d7a33a9d4d1d_872x536.png 424w, https://substackcdn.com/image/fetch/$s_!sEAN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0abc3b1-0dbc-41a3-870a-d7a33a9d4d1d_872x536.png 848w, https://substackcdn.com/image/fetch/$s_!sEAN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0abc3b1-0dbc-41a3-870a-d7a33a9d4d1d_872x536.png 1272w, https://substackcdn.com/image/fetch/$s_!sEAN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0abc3b1-0dbc-41a3-870a-d7a33a9d4d1d_872x536.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sEAN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0abc3b1-0dbc-41a3-870a-d7a33a9d4d1d_872x536.png" width="872" height="536" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d0abc3b1-0dbc-41a3-870a-d7a33a9d4d1d_872x536.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:536,&quot;width&quot;:872,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:52836,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0abc3b1-0dbc-41a3-870a-d7a33a9d4d1d_872x536.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!sEAN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0abc3b1-0dbc-41a3-870a-d7a33a9d4d1d_872x536.png 424w, https://substackcdn.com/image/fetch/$s_!sEAN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0abc3b1-0dbc-41a3-870a-d7a33a9d4d1d_872x536.png 848w, https://substackcdn.com/image/fetch/$s_!sEAN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0abc3b1-0dbc-41a3-870a-d7a33a9d4d1d_872x536.png 1272w, https://substackcdn.com/image/fetch/$s_!sEAN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0abc3b1-0dbc-41a3-870a-d7a33a9d4d1d_872x536.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The smaller the estimated eigenvalues, the larger the estimated eigenvalues of the inverse of Sigma. </p><p>Note: The y-axis is logarithmic on both plots, so linear &#8594; exponential!</p><h3>Sensitivity Analysis: How estimation errors translate into weight errors</h3><p>A useful way to formalize &#8220;error maximization&#8221; is to compute how small perturbations in mu and Sigma affect the optimizer.</p><p>Consider the unconstrained (besides budget) mean&#8211;variance utility maximization (MVO-2). The population optimum satisfies</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;w^\\star = \\frac{1}{\\gamma}\\Sigma^{-1}(\\mu - \\eta^\\star \\mathbf{1})&quot;,&quot;id&quot;:&quot;VFXNRSUXOK&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><p>with eta^\star chosen to enforce 1^T w^\star = 1. The plug-in estimate is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\hat{w} = \\frac{1}{\\gamma}\\hat{\\Sigma}^{-1}(\\hat{\\mu} - \\hat{\\eta}\\mathbf{1})&quot;,&quot;id&quot;:&quot;GDXWMHMOZL&quot;}" data-component-name="LatexBlockToDOM"></div><p>Write estimation errors as</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\hat{\\mu} = \\mu + \\delta\\mu,\n\n\\qquad\n\n\\hat{\\Sigma} = \\Sigma + \\delta\\Sigma.\n\n\\tag{2.6}&quot;,&quot;id&quot;:&quot;LFUVSFZICN&quot;}" data-component-name="LatexBlockToDOM"></div><p>A first-order expansion (informally, a matrix Taylor approximation) uses</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;(\\Sigma + \\delta\\Sigma)^{-1} \\approx \\Sigma^{-1} - \\Sigma^{-1}\\delta\\Sigma\\,\\Sigma^{-1}\n\n\\quad\\text{for small }\\delta\\Sigma.\n\n\\tag{2.7}&quot;,&quot;id&quot;:&quot;TLHPIQVRMV&quot;}" data-component-name="LatexBlockToDOM"></div><p>A first-order perturbation of the optimizer gives</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\delta w \\equiv \\hat{w} - w^\\star\n\n\\approx \\frac{1}{\\gamma}\\Sigma^{-1}\\delta\\mu - \\Sigma^{-1}\\delta\\Sigma\\, w^\\star\n\n- \\frac{\\delta\\eta}{\\gamma}\\Sigma^{-1}\\mathbf{1},\n\n\\qquad \\mathbf{1}^\\top \\delta w = 0.\n\n\\tag{2.8}&quot;,&quot;id&quot;:&quot;ZVNQMGQMTJ&quot;}" data-component-name="LatexBlockToDOM"></div><p>The last term enforces the budget constraint (with delta eta the perturbation in the multiplier); dropping it isolates the two main channels.</p><p>Several qualitative conclusions drop out of (2.8):</p><p>1. <strong>Mean error passes through Sigma^{-1}.</strong> Even if delta mu is moderate, multiplying by Sigma^{-1} can produce large changes in w, especially in directions corresponding to small eigenvalues of Sigma (or hat{Sigma}).</p><p>2. <strong>Covariance error enters as a &#8220;sandwich&#8221; with Sigma^{-1}.</strong> The term Sigma^{-1} * delta Sigma, w^\star has Sigma^{-1} on the left; if w^\star already has large exposures along unstable directions, covariance errors further distort them.</p><p>3. <strong>Budget adjustment can amplify instability.</strong> The multiplier eta is computed using 1^T Sigma^{-1} mu and 1^T \Sigma^{-1} 1$. If either of these scalars is unstable due to \Sigma^{-1}, the adjustment needed to enforce 1^T w=1 can itself swing drastically.</p><p>The key is not that delta mu and delta Sigma exist&#8212;of course they do&#8212;but that MVO <em>transforms</em> them with Sigma^{-1}, a potentially high-gain operator.</p><p>Let&#8217;s see how a badly conditioned Sigma affects delta w. We&#8217;ll drop the budget constraint so eta doesn&#8217;t influence the analysis:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ppLK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa98dbee3-740e-4670-a92b-4bc76830655f_1648x3024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ppLK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa98dbee3-740e-4670-a92b-4bc76830655f_1648x3024.png 424w, https://substackcdn.com/image/fetch/$s_!ppLK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa98dbee3-740e-4670-a92b-4bc76830655f_1648x3024.png 848w, https://substackcdn.com/image/fetch/$s_!ppLK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa98dbee3-740e-4670-a92b-4bc76830655f_1648x3024.png 1272w, https://substackcdn.com/image/fetch/$s_!ppLK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa98dbee3-740e-4670-a92b-4bc76830655f_1648x3024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ppLK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa98dbee3-740e-4670-a92b-4bc76830655f_1648x3024.png" width="1456" height="2672" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a98dbee3-740e-4670-a92b-4bc76830655f_1648x3024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2672,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:764905,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa98dbee3-740e-4670-a92b-4bc76830655f_1648x3024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ppLK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa98dbee3-740e-4670-a92b-4bc76830655f_1648x3024.png 424w, https://substackcdn.com/image/fetch/$s_!ppLK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa98dbee3-740e-4670-a92b-4bc76830655f_1648x3024.png 848w, https://substackcdn.com/image/fetch/$s_!ppLK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa98dbee3-740e-4670-a92b-4bc76830655f_1648x3024.png 1272w, https://substackcdn.com/image/fetch/$s_!ppLK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa98dbee3-740e-4670-a92b-4bc76830655f_1648x3024.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QduU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8aa51d0b-0849-45e6-9f27-7ef92e27d4ce_885x575.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QduU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8aa51d0b-0849-45e6-9f27-7ef92e27d4ce_885x575.png 424w, https://substackcdn.com/image/fetch/$s_!QduU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8aa51d0b-0849-45e6-9f27-7ef92e27d4ce_885x575.png 848w, https://substackcdn.com/image/fetch/$s_!QduU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8aa51d0b-0849-45e6-9f27-7ef92e27d4ce_885x575.png 1272w, https://substackcdn.com/image/fetch/$s_!QduU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8aa51d0b-0849-45e6-9f27-7ef92e27d4ce_885x575.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QduU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8aa51d0b-0849-45e6-9f27-7ef92e27d4ce_885x575.png" width="885" height="575" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8aa51d0b-0849-45e6-9f27-7ef92e27d4ce_885x575.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:575,&quot;width&quot;:885,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:61946,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8aa51d0b-0849-45e6-9f27-7ef92e27d4ce_885x575.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!QduU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8aa51d0b-0849-45e6-9f27-7ef92e27d4ce_885x575.png 424w, https://substackcdn.com/image/fetch/$s_!QduU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8aa51d0b-0849-45e6-9f27-7ef92e27d4ce_885x575.png 848w, https://substackcdn.com/image/fetch/$s_!QduU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8aa51d0b-0849-45e6-9f27-7ef92e27d4ce_885x575.png 1272w, https://substackcdn.com/image/fetch/$s_!QduU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8aa51d0b-0849-45e6-9f27-7ef92e27d4ce_885x575.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>You can see clearly that as Sigma becomes ill-conditioned, the error in w grows.</p><h3>Optimizer&#8217;s curse</h3><p>Another lens is the optimizer&#8217;s curse, a general phenomenon in statistical decision-making: if you choose the argmax of a noisy objective, the achieved value is biased upward <em>in-sample</em>, and the chosen decision is biased toward noise.</p><p>Formally, because hat{w} maximizes hat{U}(w),</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\hat{U}(\\hat{w}) \\ge \\hat{U}(w^\\star)&quot;,&quot;id&quot;:&quot;WWAFGHMNUS&quot;}" data-component-name="LatexBlockToDOM"></div><p>but what matters is U(hat{w}). The difference</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;U(w^\\star) - U(\\hat{w})&quot;,&quot;id&quot;:&quot;OTBBIUBGMP&quot;}" data-component-name="LatexBlockToDOM"></div><p>is typically positive and can be large in high dimensions. Intuitively, among many portfolios, some will look exceptionally good in-sample purely due to noise in hat{mu} and hat{Sigma}. MVO systematically selects those portfolios and then &#8220;locks in&#8221; their noisy characteristics via extreme weights.</p><p>This selection effect is strongest when:</p><ul><li><p>The number of assets N is large relative to the sample size T</p></li><li><p>Expected return estimates are weak (low signal-to-noise);</p></li><li><p>Shorting/leverage is permitted (large feasible set);</p></li><li><p>Constraints are loose (optimizer can chase small estimated edges);</p></li><li><p>The covariance matrix has near-collinear assets (ill-conditioning).</p></li></ul><p>Let&#8217;s demonstrate the optimizer&#8217;s curse via Monte-Carlo.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sFf6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f7e87dc-5f8e-4b72-a56a-df99179b760a_1648x3248.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sFf6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f7e87dc-5f8e-4b72-a56a-df99179b760a_1648x3248.png 424w, https://substackcdn.com/image/fetch/$s_!sFf6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f7e87dc-5f8e-4b72-a56a-df99179b760a_1648x3248.png 848w, https://substackcdn.com/image/fetch/$s_!sFf6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f7e87dc-5f8e-4b72-a56a-df99179b760a_1648x3248.png 1272w, https://substackcdn.com/image/fetch/$s_!sFf6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f7e87dc-5f8e-4b72-a56a-df99179b760a_1648x3248.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sFf6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f7e87dc-5f8e-4b72-a56a-df99179b760a_1648x3248.png" width="1456" height="2870" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7f7e87dc-5f8e-4b72-a56a-df99179b760a_1648x3248.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2870,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:836711,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f7e87dc-5f8e-4b72-a56a-df99179b760a_1648x3248.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!sFf6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f7e87dc-5f8e-4b72-a56a-df99179b760a_1648x3248.png 424w, https://substackcdn.com/image/fetch/$s_!sFf6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f7e87dc-5f8e-4b72-a56a-df99179b760a_1648x3248.png 848w, https://substackcdn.com/image/fetch/$s_!sFf6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f7e87dc-5f8e-4b72-a56a-df99179b760a_1648x3248.png 1272w, https://substackcdn.com/image/fetch/$s_!sFf6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f7e87dc-5f8e-4b72-a56a-df99179b760a_1648x3248.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!w7iO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb86af9c5-2f20-40f6-8b21-79471b465d99_797x672.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!w7iO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb86af9c5-2f20-40f6-8b21-79471b465d99_797x672.png 424w, https://substackcdn.com/image/fetch/$s_!w7iO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb86af9c5-2f20-40f6-8b21-79471b465d99_797x672.png 848w, https://substackcdn.com/image/fetch/$s_!w7iO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb86af9c5-2f20-40f6-8b21-79471b465d99_797x672.png 1272w, https://substackcdn.com/image/fetch/$s_!w7iO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb86af9c5-2f20-40f6-8b21-79471b465d99_797x672.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!w7iO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb86af9c5-2f20-40f6-8b21-79471b465d99_797x672.png" width="797" height="672" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b86af9c5-2f20-40f6-8b21-79471b465d99_797x672.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:672,&quot;width&quot;:797,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:72334,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb86af9c5-2f20-40f6-8b21-79471b465d99_797x672.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!w7iO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb86af9c5-2f20-40f6-8b21-79471b465d99_797x672.png 424w, https://substackcdn.com/image/fetch/$s_!w7iO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb86af9c5-2f20-40f6-8b21-79471b465d99_797x672.png 848w, https://substackcdn.com/image/fetch/$s_!w7iO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb86af9c5-2f20-40f6-8b21-79471b465d99_797x672.png 1272w, https://substackcdn.com/image/fetch/$s_!w7iO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb86af9c5-2f20-40f6-8b21-79471b465d99_797x672.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uri_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1f53245-cbd6-433e-931b-718a9e97b2bd_775x464.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uri_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1f53245-cbd6-433e-931b-718a9e97b2bd_775x464.png 424w, https://substackcdn.com/image/fetch/$s_!uri_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1f53245-cbd6-433e-931b-718a9e97b2bd_775x464.png 848w, https://substackcdn.com/image/fetch/$s_!uri_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1f53245-cbd6-433e-931b-718a9e97b2bd_775x464.png 1272w, https://substackcdn.com/image/fetch/$s_!uri_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1f53245-cbd6-433e-931b-718a9e97b2bd_775x464.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uri_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1f53245-cbd6-433e-931b-718a9e97b2bd_775x464.png" width="775" height="464" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a1f53245-cbd6-433e-931b-718a9e97b2bd_775x464.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:464,&quot;width&quot;:775,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:21218,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1f53245-cbd6-433e-931b-718a9e97b2bd_775x464.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!uri_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1f53245-cbd6-433e-931b-718a9e97b2bd_775x464.png 424w, https://substackcdn.com/image/fetch/$s_!uri_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1f53245-cbd6-433e-931b-718a9e97b2bd_775x464.png 848w, https://substackcdn.com/image/fetch/$s_!uri_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1f53245-cbd6-433e-931b-718a9e97b2bd_775x464.png 1272w, https://substackcdn.com/image/fetch/$s_!uri_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1f53245-cbd6-433e-931b-718a9e97b2bd_775x464.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>You can see that even in an environment with equal true in- and out-of-sample mu and Sigma, due to estimation error, we vastly overestimate our utility in the in-sample.</p><h3>Practical Symptoms: Instability, extreme positions, turnover, and disappointment</h3><p>When raw MVO meets real data, the mathematical mechanisms above manifest in operational ways:</p><ul><li><p><strong>Extreme weights and implicit leverage.</strong> Even with the budget constraint 1^T w = 1, weights can be large positive and large negative (if shorting is allowed), producing large gross exposure |w|_1. Even with no-short constraints, solutions often sit on corners of the feasible region (many weights at bounds), because linear return objectives push to extremes.</p></li><li><p><strong>High sensitivity to small input changes.</strong> Updating the estimation window by one month can materially change hat{mu} and hat{Sigma}, leading to large changes in hat{w}. This is not merely &#8220;rebalancing&#8221;; it is <em>model instability</em>.</p></li><li><p><strong>High turnover and transaction cost drag.</strong> If weights change drastically, realized performance is dominated by trading costs and market impact, neither of which exists in the clean Markowitz formulation unless explicitly modeled.</p></li><li><p><strong>Out-of-sample underperformance relative to naive allocations. </strong>A simple equal-weight or risk-parity portfolio can outperform a naive MVO portfolio after costs, not because those heuristics are theoretically superior, but because they are robust to estimation error.</p></li></ul><p>These observations motivate the central practical conclusion: <strong>raw plug-in MVO is a high-variance estimator of portfolio weights.</strong> In modern terms, it is an overfit model.</p><h1>The Spectrum of Solutions</h1><p><strong>This concludes the theoretical foundation.</strong></p><p>The remaining 40 pages implement and test 11 robust portfolio construction techniques.</p><p>Each technique includes: Mathematical derivation &#8594; Clean implementation &#8594; Parameter tuning &#8594; Comparative results </p><p>Plus: Full research notebook (1250+ lines) with production-ready code. If you've made it this far through the theory, the implementations are where it pays off.</p><p>If raw MVO is fragile because it optimizes a noisy objective with unstable operators, then fixes must do one (or both) of the following:</p><p>1. <strong>Fix the inputs</strong>: replace (hat{mu}, hat{Sigma}) with estimators that have lower estimation error, better conditioning, or an economically grounded structure.</p><p>2. <strong>Constrain or regularize the optimizer</strong>: modify the optimization problem so that it cannot translate small input errors into extreme weight changes.</p><p>These approaches are complementary. Many production-grade systems use both: structured/shrunk inputs and a constrained, regularized optimization.</p><h2>Fixing the inputs</h2><h3>Covariance Shrinkage: Stabilizing \hat{Sigma} and its inverse</h3><p>The sample covariance hat{Sigma} is unbiased under idealized assumptions, but it can have high variance in finite samples, especially for off-diagonal elements. Shrinkage addresses this by pulling the estimate toward a structured target F that is lower variance but potentially biased.</p><p>A canonical shrinkage estimator is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\tilde{\\Sigma} = (1-\\delta)\\hat{\\Sigma} + \\delta F,\n\n\\qquad \\delta \\in [0,1].\n\n\\tag{3.1}&quot;,&quot;id&quot;:&quot;DNICFUKHSH&quot;}" data-component-name="LatexBlockToDOM"></div><p>Common choices for F include:</p><ul><li><p> a diagonal matrix (imposing zero correlations),</p></li><li><p> a constant-correlation model,</p></li><li><p> a factor-based covariance (discussed next),</p></li><li><p> an identity-scaled matrix (equal variance, no correlation).</p></li></ul><p>Why does shrinkage help? Because it increases the smallest eigenvalues of hat{Sigma} (or, more precisely, it reduces eigenvalue dispersion), improving the condition number and stabilizing inversion. In terms of Sigma^{-1} mu, shrinkage reduces the optimizer&#8217;s ability to exploit noisy &#8220;cheap-risk&#8221; directions created by small sample eigenvalues.</p><p>A useful way to view this is that shrinkage imposes a prior belief: extreme correlation structures are unlikely unless supported by strong data. By nudging the estimate toward a simpler structure, you reduce estimation variance more than you increase bias, improving out-of-sample performance.</p><p><strong>Oracle note:</strong> In the sweep below, the &#8220;best delta&#8221; is chosen by maximizing utility computed with the true (mu, Sigma) to isolate the mechanism. In practice, delta must be selected via an analytic estimator (e.g., Ledoit&#8211;Wolf/OAS) or via walk-forward / nested cross-validation. We also report a held-out test-sample utility proxy for evaluation, not for selection.</p><p>Let&#8217;s look at the effect of choosing different values of delta. We will let F be</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;F = \\frac{\\text{tr}(\\hat{\\Sigma})}{N} I&quot;,&quot;id&quot;:&quot;OYHQPMXZDI&quot;}" data-component-name="LatexBlockToDOM"></div><p>which has the average estimated variance among all assets as its diagonal entries.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BJvA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b937609-b684-4169-9ba1-7cda4815023f_1716x4252.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BJvA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b937609-b684-4169-9ba1-7cda4815023f_1716x4252.png 424w, https://substackcdn.com/image/fetch/$s_!BJvA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b937609-b684-4169-9ba1-7cda4815023f_1716x4252.png 848w, https://substackcdn.com/image/fetch/$s_!BJvA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b937609-b684-4169-9ba1-7cda4815023f_1716x4252.png 1272w, https://substackcdn.com/image/fetch/$s_!BJvA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b937609-b684-4169-9ba1-7cda4815023f_1716x4252.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BJvA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b937609-b684-4169-9ba1-7cda4815023f_1716x4252.png" width="1456" height="3608" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6b937609-b684-4169-9ba1-7cda4815023f_1716x4252.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:3608,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1179285,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b937609-b684-4169-9ba1-7cda4815023f_1716x4252.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!BJvA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b937609-b684-4169-9ba1-7cda4815023f_1716x4252.png 424w, https://substackcdn.com/image/fetch/$s_!BJvA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b937609-b684-4169-9ba1-7cda4815023f_1716x4252.png 848w, https://substackcdn.com/image/fetch/$s_!BJvA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b937609-b684-4169-9ba1-7cda4815023f_1716x4252.png 1272w, https://substackcdn.com/image/fetch/$s_!BJvA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b937609-b684-4169-9ba1-7cda4815023f_1716x4252.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zSMs!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F342d039d-a32a-4aaa-8e24-13af62b46e07_839x595.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zSMs!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F342d039d-a32a-4aaa-8e24-13af62b46e07_839x595.png 424w, https://substackcdn.com/image/fetch/$s_!zSMs!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F342d039d-a32a-4aaa-8e24-13af62b46e07_839x595.png 848w, https://substackcdn.com/image/fetch/$s_!zSMs!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F342d039d-a32a-4aaa-8e24-13af62b46e07_839x595.png 1272w, https://substackcdn.com/image/fetch/$s_!zSMs!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F342d039d-a32a-4aaa-8e24-13af62b46e07_839x595.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zSMs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F342d039d-a32a-4aaa-8e24-13af62b46e07_839x595.png" width="839" height="595" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/342d039d-a32a-4aaa-8e24-13af62b46e07_839x595.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:595,&quot;width&quot;:839,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:58007,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F342d039d-a32a-4aaa-8e24-13af62b46e07_839x595.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!zSMs!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F342d039d-a32a-4aaa-8e24-13af62b46e07_839x595.png 424w, https://substackcdn.com/image/fetch/$s_!zSMs!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F342d039d-a32a-4aaa-8e24-13af62b46e07_839x595.png 848w, https://substackcdn.com/image/fetch/$s_!zSMs!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F342d039d-a32a-4aaa-8e24-13af62b46e07_839x595.png 1272w, https://substackcdn.com/image/fetch/$s_!zSMs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F342d039d-a32a-4aaa-8e24-13af62b46e07_839x595.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>As you can see, the condition number of our estimated covariance matrix reduces pretty greatly as we increase delta.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!B02s!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F246de843-78dc-4ff1-a6e8-112001957cf4_824x464.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!B02s!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F246de843-78dc-4ff1-a6e8-112001957cf4_824x464.png 424w, https://substackcdn.com/image/fetch/$s_!B02s!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F246de843-78dc-4ff1-a6e8-112001957cf4_824x464.png 848w, https://substackcdn.com/image/fetch/$s_!B02s!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F246de843-78dc-4ff1-a6e8-112001957cf4_824x464.png 1272w, https://substackcdn.com/image/fetch/$s_!B02s!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F246de843-78dc-4ff1-a6e8-112001957cf4_824x464.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!B02s!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F246de843-78dc-4ff1-a6e8-112001957cf4_824x464.png" width="824" height="464" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/246de843-78dc-4ff1-a6e8-112001957cf4_824x464.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:464,&quot;width&quot;:824,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:46385,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F246de843-78dc-4ff1-a6e8-112001957cf4_824x464.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!B02s!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F246de843-78dc-4ff1-a6e8-112001957cf4_824x464.png 424w, https://substackcdn.com/image/fetch/$s_!B02s!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F246de843-78dc-4ff1-a6e8-112001957cf4_824x464.png 848w, https://substackcdn.com/image/fetch/$s_!B02s!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F246de843-78dc-4ff1-a6e8-112001957cf4_824x464.png 1272w, https://substackcdn.com/image/fetch/$s_!B02s!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F246de843-78dc-4ff1-a6e8-112001957cf4_824x464.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Utility increases out of sample as we increase delta (This is what we REALLY care about!)</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!p5HU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78e2e413-a93d-4bfe-9599-4d7d5246ee4f_848x536.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!p5HU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78e2e413-a93d-4bfe-9599-4d7d5246ee4f_848x536.png 424w, https://substackcdn.com/image/fetch/$s_!p5HU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78e2e413-a93d-4bfe-9599-4d7d5246ee4f_848x536.png 848w, https://substackcdn.com/image/fetch/$s_!p5HU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78e2e413-a93d-4bfe-9599-4d7d5246ee4f_848x536.png 1272w, https://substackcdn.com/image/fetch/$s_!p5HU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78e2e413-a93d-4bfe-9599-4d7d5246ee4f_848x536.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!p5HU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78e2e413-a93d-4bfe-9599-4d7d5246ee4f_848x536.png" width="848" height="536" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/78e2e413-a93d-4bfe-9599-4d7d5246ee4f_848x536.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:536,&quot;width&quot;:848,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:52607,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78e2e413-a93d-4bfe-9599-4d7d5246ee4f_848x536.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!p5HU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78e2e413-a93d-4bfe-9599-4d7d5246ee4f_848x536.png 424w, https://substackcdn.com/image/fetch/$s_!p5HU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78e2e413-a93d-4bfe-9599-4d7d5246ee4f_848x536.png 848w, https://substackcdn.com/image/fetch/$s_!p5HU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78e2e413-a93d-4bfe-9599-4d7d5246ee4f_848x536.png 1272w, https://substackcdn.com/image/fetch/$s_!p5HU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78e2e413-a93d-4bfe-9599-4d7d5246ee4f_848x536.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Small eigenvalues are inflated instead of dropping to extremely low values, which in turn causes the eigenvalues of Sigma^{-1} to not explode.</p><h3>Factor Models</h3><p>A deeper way to control covariance noise is to assume returns are driven by a small number of common factors. A standard linear factor model is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;r = B f + \\varepsilon,\n\n\\tag{3.2}&quot;,&quot;id&quot;:&quot;XJWUHXHUCF&quot;}" data-component-name="LatexBlockToDOM"></div><p>where</p><ul><li><p>f in R^K are factor returns with K &lt;&lt; N</p></li><li><p>B in R^{N x K} are factor loadings</p></li><li><p>epsilon in R^N are idiosyncratic returns.</p></li></ul><p>Assuming epsilon is uncorrelated with f and has diagonal covariance D, the covariance of r becomes</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\Sigma = B \\Sigma_f B^\\top + D,\n\n\\tag{3.3}&quot;,&quot;id&quot;:&quot;YLBBFIQYTM&quot;}" data-component-name="LatexBlockToDOM"></div><p>where Sigma_f = Cov(f) and D = Cov(epsilon) is typically diagonal.</p><p>The parameter-count reduction is dramatic. A full covariance matrix has N(N+1)/2 unique parameters. A factor model estimates:</p><ul><li><p>NK loadings (often constrained/regularized)</p></li><li><p>K(K+1)/2 factor covariances</p></li><li><p>N idiosyncratic variances.</p></li></ul><p>When K &lt;&lt; N, this is a much lower-dimensional estimation problem, leading to more stable covariance estimates and more stable inverses. Economically, factors capture persistent co-movement structure (industries, styles, macro exposures), while idiosyncratic risk captures asset-specific variance.</p><p>For optimization, (3.3) has another advantage: it makes risk decomposition interpretable and enables direct factor exposure constraints, a major practical tool for controlling unintended bets.</p><p>To test this method, we are gonna assume assets follow some &#8220;true&#8221; factor model, and then we will estimate this factor model to obtain an estimate for Sigma by plugging the estimates into (3.3):</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Qveg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d6cabcd-2c81-499e-aafe-540cb4c437c5_1548x4514.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Qveg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d6cabcd-2c81-499e-aafe-540cb4c437c5_1548x4514.png 424w, https://substackcdn.com/image/fetch/$s_!Qveg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d6cabcd-2c81-499e-aafe-540cb4c437c5_1548x4514.png 848w, https://substackcdn.com/image/fetch/$s_!Qveg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d6cabcd-2c81-499e-aafe-540cb4c437c5_1548x4514.png 1272w, https://substackcdn.com/image/fetch/$s_!Qveg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d6cabcd-2c81-499e-aafe-540cb4c437c5_1548x4514.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Qveg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d6cabcd-2c81-499e-aafe-540cb4c437c5_1548x4514.png" width="1456" height="4246" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4d6cabcd-2c81-499e-aafe-540cb4c437c5_1548x4514.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:4246,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1173035,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d6cabcd-2c81-499e-aafe-540cb4c437c5_1548x4514.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Qveg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d6cabcd-2c81-499e-aafe-540cb4c437c5_1548x4514.png 424w, https://substackcdn.com/image/fetch/$s_!Qveg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d6cabcd-2c81-499e-aafe-540cb4c437c5_1548x4514.png 848w, https://substackcdn.com/image/fetch/$s_!Qveg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d6cabcd-2c81-499e-aafe-540cb4c437c5_1548x4514.png 1272w, https://substackcdn.com/image/fetch/$s_!Qveg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d6cabcd-2c81-499e-aafe-540cb4c437c5_1548x4514.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ziKq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F326ef1b1-9a53-4bf7-a43b-f48f0867f258_858x709.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ziKq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F326ef1b1-9a53-4bf7-a43b-f48f0867f258_858x709.png 424w, https://substackcdn.com/image/fetch/$s_!ziKq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F326ef1b1-9a53-4bf7-a43b-f48f0867f258_858x709.png 848w, https://substackcdn.com/image/fetch/$s_!ziKq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F326ef1b1-9a53-4bf7-a43b-f48f0867f258_858x709.png 1272w, https://substackcdn.com/image/fetch/$s_!ziKq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F326ef1b1-9a53-4bf7-a43b-f48f0867f258_858x709.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ziKq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F326ef1b1-9a53-4bf7-a43b-f48f0867f258_858x709.png" width="858" height="709" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/326ef1b1-9a53-4bf7-a43b-f48f0867f258_858x709.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:709,&quot;width&quot;:858,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:59292,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F326ef1b1-9a53-4bf7-a43b-f48f0867f258_858x709.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ziKq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F326ef1b1-9a53-4bf7-a43b-f48f0867f258_858x709.png 424w, https://substackcdn.com/image/fetch/$s_!ziKq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F326ef1b1-9a53-4bf7-a43b-f48f0867f258_858x709.png 848w, https://substackcdn.com/image/fetch/$s_!ziKq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F326ef1b1-9a53-4bf7-a43b-f48f0867f258_858x709.png 1272w, https://substackcdn.com/image/fetch/$s_!ziKq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F326ef1b1-9a53-4bf7-a43b-f48f0867f258_858x709.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>As you can see, our median condition went from 4327 for the naive sample covariance to only 259.3 for the factor-informed covariance. Utility improved 100% of the time out of sample!</p><h3>Time-varying covariance</h3><p>Covariances evolve over time. Using very long histories can reduce sampling error but introduce <em>model error </em>if the distribution is non-stationary. Using short histories reduces model error but increases estimation noise.</p><p>A common compromise is an exponentially weighted covariance estimator. For a finite window, a normalized form is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\tilde{\\Sigma} = \\frac{1-\\lambda}{1-\\lambda^T}\\sum_{t=1}^{T} \\lambda^{T-t} (r_t - \\bar{r})(r_t - \\bar{r})^\\top,\n\n\\qquad \\lambda \\in (0,1).\n\n\\tag{3.4}&quot;,&quot;id&quot;:&quot;ALUZNROZQC&quot;}" data-component-name="LatexBlockToDOM"></div><p>This places more weight on recent observations, adapting to changing regimes, while keeping the weights normalized for finite T.</p><p>An equivalent way to write the estimator is the recursive form</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\Sigma_t = \\lambda \\Sigma_{t-1} + (1-\\lambda)(r_{t-1}-\\mu_t)(r_{t-1}-\\mu_t)^\\top&quot;,&quot;id&quot;:&quot;WNHONWUOVX&quot;}" data-component-name="LatexBlockToDOM"></div><p>which implicitly normalizes and becomes equivalent to the sum as T &#8594; infinity (since lambda^T &#8594; 0).</p><p>But note: exponential weighting alone does not solve ill-conditioning in high dimensions; it is often combined with shrinkage or factor models.</p><p>The practical point is that &#8220;better covariance&#8221; means balancing <em>estimation variance </em>against <em>non-stationarity</em>. MVO fails when either error dominates, and real markets usually give you both.</p><h3>Expected Returns</h3><p>If covariance estimation is difficult, expected return estimation is usually worse. Many practical systems, therefore, treat mu not as a directly estimated sample mean, but as a <em>forecast </em>that must be heavily regularized.</p><p>A basic shrinkage approach is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\tilde{\\mu} = (1-\\alpha)\\hat{\\mu} + \\alpha \\mu_0,\n\n\\qquad \\alpha \\in [0,1],\n\n\\tag{3.5}&quot;,&quot;id&quot;:&quot;VUCOPGZURA&quot;}" data-component-name="LatexBlockToDOM"></div><p>where mu_0 is a prior mean. Choices for mu_0 include:</p><ul><li><p>zero (implying no predictability in excess returns),</p></li><li><p>a cross-sectional average (implying mean reversion across assets),</p></li><li><p>factor-model-implied returns,</p></li><li><p>equilibrium-implied returns from a benchmark portfolio.</p></li></ul><p>The key is the logic: because hat{mu} is high-variance, we deliberately introduce bias by shrinking toward a stable prior. This reduces the variance of the resulting weights, which is often the dominant out-of-sample benefit.</p><p>A particularly influential equilibrium anchoring method is to infer implied expected returns pi from an observed &#8220;market&#8221; or benchmark portfolio w_m.</p><p>Before invoking the next equation, it helps to distinguish between two regimes:</p><ul><li><p><strong>Risk-free asset (tangency portfolio).</strong> If a risk-free asset is available and w_m is the tangency portfolio, then pi are excess returns and reverse optimization yields pi = lambda Sigma w_m.</p></li><li><p><strong>Risky-only, fully invested.</strong> If we remain in the 1^T w = 1 setting, the KKT condition is mu = gamma Sigma w_m + eta 1. The intercept term is economically irrelevant under the budget constraint, so one can normalize it away or interpret eta as the baseline rate.</p></li></ul><p>In a mean&#8211;variance world, if w_m is optimal for some representative investor with risk aversion lambda, then</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;w_m \\propto \\Sigma^{-1}\\pi\n\n\\quad\\Rightarrow\\quad\n\n\\pi = \\lambda \\Sigma w_m\n\n\\tag{3.6}&quot;,&quot;id&quot;:&quot;AWTWNJUYPD&quot;}" data-component-name="LatexBlockToDOM"></div><p>This produces a return vector pi consistent with the covariance structure and observed holdings. Even if the exact assumptions are stylized, pi has a crucial practical advantage: it is <em>anchored</em> to a diversified, implementable portfolio, which prevents the optimizer from forming extreme views unsupported by the market&#8217;s aggregate positioning.</p><h3>Black-Litterman as a canonical &#8220;fix-the-inputs&#8221; framework</h3><p>Black&#8211;Litterman formalizes the idea that expected returns should be a blend of (i) equilibrium returns and (ii) investor views. While many variants exist, the classical setup can be summarized as follows.</p><p>Let pi be equilibrium implied returns (e.g., from (3.6)). Model the prior as</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mu \\sim \\mathcal{N}(\\pi, \\tau \\Sigma),\n\n\\tag{3.7}&quot;,&quot;id&quot;:&quot;TIZZVGBVHE&quot;}" data-component-name="LatexBlockToDOM"></div><p>where tau &gt; 0 scales uncertainty in the prior. Investor views are expressed as</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;P\\mu = q + \\text{noise},\n\n\\tag{3.8}&quot;,&quot;id&quot;:&quot;LLXWXPMXWS&quot;}" data-component-name="LatexBlockToDOM"></div><p>where P in R^{M x N} selects linear combinations of returns, q in R^M are view returns, and view noise has covariance Omega in R^{M x M}$ (often diagonal).</p><p>The posterior mean under Gaussian assumptions is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mu_{\\mathrm{BL}}\n\n= \\left( (\\tau \\Sigma)^{-1} + P^\\top \\Omega^{-1} P \\right)^{-1}\n\n\\left( (\\tau \\Sigma)^{-1}\\pi + P^\\top \\Omega^{-1} q \\right).\n\n\\tag{3.9}&quot;,&quot;id&quot;:&quot;OXSWVUEZTB&quot;}" data-component-name="LatexBlockToDOM"></div><p>Why does this help MVO?</p><ul><li><p>It shrinks noisy, unconstrained return estimates toward an equilibrium anchor.</p></li><li><p>It expresses uncertainty explicitly via tau and Omega, preventing overconfidence.</p></li><li><p>It ensures that when views are weak or absent, the optimizer defaults to a diversified baseline rather than a noisy corner solution.</p></li></ul><p>Black&#8211;Litterman is not magic; it is a disciplined way of injecting structure and uncertainty into mu, which is exactly what raw MVO lacks.</p><h3>Resampling and Bayesian Averaging: Stabilizing weights instead of moments</h3><p>Another approach is to accept that inputs are noisy and average over that uncertainty. A simple version is bootstrap resampling:</p><p>1. Generate many synthetic datasets by resampling {r_t}.</p><p>2. For each dataset b, compute hat{mu}^(b), hat{Sigma}^(b) and solve MVO to get hat{w}^(b).</p><p>3. Average weights: </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\bar{w} = \\frac{1}{B}\\sum_{b=1}^B \\hat{w}^{(b)}&quot;,&quot;id&quot;:&quot;WLVLJORHAL&quot;}" data-component-name="LatexBlockToDOM"></div><p>The intuition is that extreme positions caused by noise tend not to be stable across resamples; averaging dampens them. In decision-theoretic language, this approximates integrating over parameter uncertainty rather than conditioning on a single plug-in estimate.</p><p>This class of methods &#8220;fixes&#8221; MVO not by producing perfect estimates, but by reducing the variance of the <em>decision</em> w.</p><p>Let&#8217;s compare the weights generated by this method with those of MVO using just the sample estimates. We will also enforce long only to make the weights more comparable.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UPgJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13d5b95a-4871-4f26-b19e-524d163a5734_1782x2986.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UPgJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13d5b95a-4871-4f26-b19e-524d163a5734_1782x2986.png 424w, https://substackcdn.com/image/fetch/$s_!UPgJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13d5b95a-4871-4f26-b19e-524d163a5734_1782x2986.png 848w, https://substackcdn.com/image/fetch/$s_!UPgJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13d5b95a-4871-4f26-b19e-524d163a5734_1782x2986.png 1272w, https://substackcdn.com/image/fetch/$s_!UPgJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13d5b95a-4871-4f26-b19e-524d163a5734_1782x2986.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UPgJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13d5b95a-4871-4f26-b19e-524d163a5734_1782x2986.png" width="1456" height="2440" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/13d5b95a-4871-4f26-b19e-524d163a5734_1782x2986.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2440,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:785711,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13d5b95a-4871-4f26-b19e-524d163a5734_1782x2986.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!UPgJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13d5b95a-4871-4f26-b19e-524d163a5734_1782x2986.png 424w, https://substackcdn.com/image/fetch/$s_!UPgJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13d5b95a-4871-4f26-b19e-524d163a5734_1782x2986.png 848w, https://substackcdn.com/image/fetch/$s_!UPgJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13d5b95a-4871-4f26-b19e-524d163a5734_1782x2986.png 1272w, https://substackcdn.com/image/fetch/$s_!UPgJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13d5b95a-4871-4f26-b19e-524d163a5734_1782x2986.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!owaT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a9668c3-5a09-41ac-879c-5378e3e965eb_910x599.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!owaT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a9668c3-5a09-41ac-879c-5378e3e965eb_910x599.png 424w, https://substackcdn.com/image/fetch/$s_!owaT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a9668c3-5a09-41ac-879c-5378e3e965eb_910x599.png 848w, https://substackcdn.com/image/fetch/$s_!owaT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a9668c3-5a09-41ac-879c-5378e3e965eb_910x599.png 1272w, https://substackcdn.com/image/fetch/$s_!owaT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a9668c3-5a09-41ac-879c-5378e3e965eb_910x599.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!owaT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a9668c3-5a09-41ac-879c-5378e3e965eb_910x599.png" width="910" height="599" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7a9668c3-5a09-41ac-879c-5378e3e965eb_910x599.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:599,&quot;width&quot;:910,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:77237,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a9668c3-5a09-41ac-879c-5378e3e965eb_910x599.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!owaT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a9668c3-5a09-41ac-879c-5378e3e965eb_910x599.png 424w, https://substackcdn.com/image/fetch/$s_!owaT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a9668c3-5a09-41ac-879c-5378e3e965eb_910x599.png 848w, https://substackcdn.com/image/fetch/$s_!owaT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a9668c3-5a09-41ac-879c-5378e3e965eb_910x599.png 1272w, https://substackcdn.com/image/fetch/$s_!owaT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a9668c3-5a09-41ac-879c-5378e3e965eb_910x599.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>As you can see, half of the weights generated by the plug-in MVO are exactly zero, whereas with the bootstrap-averaged method, we have no zero weights. Those weights that are non-zero are also larger for the plug-in MVO. We are therefore better diversified using the bootstrap-averaged weights method.</p><h2>Constraining and Regularizing the Optimizer</h2><p>Even with improved inputs, the optimizer can still overreact. Constraining the optimization problem is therefore the second major lever. The guiding principle is simple: <strong>if you restrict the feasible set or penalize extreme solutions, the optimizer has fewer degrees of freedom to express estimation noise.</strong></p><h3>Box constraints, no-short constraints, and leverage limits</h3><p>A basic set of implementability constraints is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;l_i \\le w_i \\le u_i \\quad \\text{for all } i,\n\n\\tag{3.10}&quot;,&quot;id&quot;:&quot;VQJCNBLNPJ&quot;}" data-component-name="LatexBlockToDOM"></div><p>along with the budget constraint 1^T w = 1. The no-short constraint is the special case (l_i = 0). A leverage constraint can be expressed as</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\|w\\|_1 \\le L,\n\n\\tag{3.11}&quot;,&quot;id&quot;:&quot;AHSOKUKJIZ&quot;}" data-component-name="LatexBlockToDOM"></div><p>When shorts are allowed, |w|_1 measures gross exposure; limiting it prevents the optimizer from creating offsetting long/short positions that are highly sensitive to small covariance or mean differences.</p><p>Why do these constraints work? They impose a <em>cap on sensitivity</em>. If the optimizer cannot push weights arbitrarily far, then errors in hat{mu} and hat{Sigma} cannot translate into arbitrarily extreme positions.</p><p>A common misconception is that constraints only reflect operational needs. In practice, they often serve a dual purpose: implementability <em>and </em>robustness.</p><h3>Regularization Penalties: Making MVO behave like a well-posed estimation problem</h3><p>Instead of hard constraints, one can add penalties to the objective. Consider augmenting (MVO-2) with an l2 (ridge) penalty:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\max_{w:\\mathbf{1}^\\top w=1} \\left( w^\\top \\mu - \\frac{\\gamma}{2} w^\\top \\Sigma w - \\frac{\\lambda}{2} \\|w\\|_2^2 \\right), \\qquad \\lambda \\ge 0.\n\n\\tag{3.12}&quot;,&quot;id&quot;:&quot;FGZYUOEEDM&quot;}" data-component-name="LatexBlockToDOM"></div><p>  Because |w|_2^2 = w^T I w, the risk term becomes</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\frac{\\gamma}{2} w^\\top \\Sigma w + \\frac{\\lambda}{2} w^\\top I w\n\n  = \\frac{\\gamma}{2} w^\\top \\left(\\Sigma + \\frac{\\lambda}{\\gamma}I\\right) w.\n\n\\tag{3.13}&quot;,&quot;id&quot;:&quot;RAGBZNJVPM&quot;}" data-component-name="LatexBlockToDOM"></div><p>  So ridge-regularized MVO is equivalent to replacing Sigma with</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\Sigma_{\\text{eff}} = \\Sigma + \\frac{\\lambda}{\\gamma} I\n\n\\tag{3.14}&quot;,&quot;id&quot;:&quot;BCZCIKUDRH&quot;}" data-component-name="LatexBlockToDOM"></div><p>  This is a profound and practical insight: <strong>a simple weight penalty is mathematically identical to eigenvalue inflation of the covariance matrix.</strong> It improves conditioning by pushing all eigenvalues away from zero, directly addressing the instability of Sigma^{-1}. In effect, it says: &#8220;do not trust low-variance directions too much; treat them as riskier than the raw estimate suggests.&#8221;</p><p>One can also use an l1 (lasso) penalty:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\max_{w:\\mathbf{1}^\\top w=1} \\left( w^\\top \\mu - \\frac{\\gamma}{2} w^\\top \\Sigma w - \\lambda \\|w\\|_1 \\right).\n\n\\tag{3.15}&quot;,&quot;id&quot;:&quot;MWJMIQUSTO&quot;}" data-component-name="LatexBlockToDOM"></div><p>  The l1 penalty encourages sparsity (many weights exactly zero) and discourages large gross exposure, especially when shorts are allowed. It is closely related to constraining |w|_1 as in (3.11). Sparse portfolios can be easier to implement and often exhibit lower turnover.</p><p>  Note: if w &gt;= 0 and 1^T w = 1, then |w|_1 = 1 is constant, so an l1 penalty on weights has no effect. l1 becomes meaningful when shorting is allowed (gross exposure varies), when applied to active weights a = w - w_b, or when penalizing turnover |w_t - w_{t-1}|_1.</p><p>Both l1 and l2 regularization can be understood as injecting a preference for &#8220;simple&#8221; portfolios, portfolios that do not require precise estimates to justify intricate long/short structures.</p><p>The following code demonstrates what happens if you adjust the ridge parameter lambda:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!g7A-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25f4bc49-73e3-497b-967e-c18b7287dd7e_1732x2912.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!g7A-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25f4bc49-73e3-497b-967e-c18b7287dd7e_1732x2912.png 424w, https://substackcdn.com/image/fetch/$s_!g7A-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25f4bc49-73e3-497b-967e-c18b7287dd7e_1732x2912.png 848w, https://substackcdn.com/image/fetch/$s_!g7A-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25f4bc49-73e3-497b-967e-c18b7287dd7e_1732x2912.png 1272w, https://substackcdn.com/image/fetch/$s_!g7A-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25f4bc49-73e3-497b-967e-c18b7287dd7e_1732x2912.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!g7A-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25f4bc49-73e3-497b-967e-c18b7287dd7e_1732x2912.png" width="1456" height="2448" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/25f4bc49-73e3-497b-967e-c18b7287dd7e_1732x2912.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2448,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:747931,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25f4bc49-73e3-497b-967e-c18b7287dd7e_1732x2912.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!g7A-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25f4bc49-73e3-497b-967e-c18b7287dd7e_1732x2912.png 424w, https://substackcdn.com/image/fetch/$s_!g7A-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25f4bc49-73e3-497b-967e-c18b7287dd7e_1732x2912.png 848w, https://substackcdn.com/image/fetch/$s_!g7A-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25f4bc49-73e3-497b-967e-c18b7287dd7e_1732x2912.png 1272w, https://substackcdn.com/image/fetch/$s_!g7A-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25f4bc49-73e3-497b-967e-c18b7287dd7e_1732x2912.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aB9w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc64a161-9abb-481e-b211-33545c699a4d_824x464.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aB9w!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc64a161-9abb-481e-b211-33545c699a4d_824x464.png 424w, https://substackcdn.com/image/fetch/$s_!aB9w!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc64a161-9abb-481e-b211-33545c699a4d_824x464.png 848w, https://substackcdn.com/image/fetch/$s_!aB9w!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc64a161-9abb-481e-b211-33545c699a4d_824x464.png 1272w, https://substackcdn.com/image/fetch/$s_!aB9w!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc64a161-9abb-481e-b211-33545c699a4d_824x464.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aB9w!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc64a161-9abb-481e-b211-33545c699a4d_824x464.png" width="824" height="464" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bc64a161-9abb-481e-b211-33545c699a4d_824x464.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:464,&quot;width&quot;:824,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:39536,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc64a161-9abb-481e-b211-33545c699a4d_824x464.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!aB9w!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc64a161-9abb-481e-b211-33545c699a4d_824x464.png 424w, https://substackcdn.com/image/fetch/$s_!aB9w!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc64a161-9abb-481e-b211-33545c699a4d_824x464.png 848w, https://substackcdn.com/image/fetch/$s_!aB9w!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc64a161-9abb-481e-b211-33545c699a4d_824x464.png 1272w, https://substackcdn.com/image/fetch/$s_!aB9w!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc64a161-9abb-481e-b211-33545c699a4d_824x464.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Higher lambda results in better conditioned Sigma.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!o2ei!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e0ca8bf-a8b3-4463-a556-270fdae2a530_824x464.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!o2ei!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e0ca8bf-a8b3-4463-a556-270fdae2a530_824x464.png 424w, https://substackcdn.com/image/fetch/$s_!o2ei!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e0ca8bf-a8b3-4463-a556-270fdae2a530_824x464.png 848w, https://substackcdn.com/image/fetch/$s_!o2ei!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e0ca8bf-a8b3-4463-a556-270fdae2a530_824x464.png 1272w, https://substackcdn.com/image/fetch/$s_!o2ei!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e0ca8bf-a8b3-4463-a556-270fdae2a530_824x464.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!o2ei!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e0ca8bf-a8b3-4463-a556-270fdae2a530_824x464.png" width="824" height="464" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7e0ca8bf-a8b3-4463-a556-270fdae2a530_824x464.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:464,&quot;width&quot;:824,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:41253,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e0ca8bf-a8b3-4463-a556-270fdae2a530_824x464.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!o2ei!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e0ca8bf-a8b3-4463-a556-270fdae2a530_824x464.png 424w, https://substackcdn.com/image/fetch/$s_!o2ei!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e0ca8bf-a8b3-4463-a556-270fdae2a530_824x464.png 848w, https://substackcdn.com/image/fetch/$s_!o2ei!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e0ca8bf-a8b3-4463-a556-270fdae2a530_824x464.png 1272w, https://substackcdn.com/image/fetch/$s_!o2ei!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e0ca8bf-a8b3-4463-a556-270fdae2a530_824x464.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Higher lambda results in lower L1 and L2 norm of w (The portfolios become &#8220;simpler&#8221;).</p><h3>Turnover and Transaction Costs: Regularizing changes the weights</h3><p>A portfolio is rarely optimized once. In practice, we solve a sequence of problems over time. Estimation noise then manifests as unstable <em>changes</em> in weights, i.e., turnover.</p><p>A common fix is to add trading costs or turnover penalties. Let w_{t-1} be current holdings and w_t the new decision. A quadratic turnover penalty gives</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\max_{w_t:\\mathbf{1}^\\top w_t = 1} \\left( w_t^\\top \\mu_t - \\frac{\\gamma}{2} w_t^\\top \\Sigma_t w_t - \\frac{\\kappa}{2} \\|w_t - w_{t-1}\\|_2^2 \\right), \\qquad \\kappa > 0.\n\n\\tag{3.16}&quot;,&quot;id&quot;:&quot;SVJROJSZNR&quot;}" data-component-name="LatexBlockToDOM"></div><p>  This makes the optimizer &#8220;reluctant&#8221; to move unless the gain in mean&#8211;variance utility is large enough to justify the change. Importantly, this is also a robustness device: it prevents the optimizer from chasing small, noisy changes in hat{mu} or hat{Sigma}.</p><p>Linear cost models use |w_t - w_{t-1}|_1 instead, which can better capture proportional costs and induce sparse trading (only a subset of names trade each period).</p><p>The deeper point is that multi-period implementation turns MVO into a control problem. Regularizing the control (weight changes) is often more impactful than regularizing the state (weights) alone.</p><p>Let&#8217;s compare the evolution of two portfolios: One via regular MVO and one with the L1 penalty for weight changes. Let&#8217;s also see how changing kappa affects our portfolio.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!e1Uq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F917d1ea0-3719-4a98-9a14-99e657e78697_1548x4328.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!e1Uq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F917d1ea0-3719-4a98-9a14-99e657e78697_1548x4328.png 424w, https://substackcdn.com/image/fetch/$s_!e1Uq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F917d1ea0-3719-4a98-9a14-99e657e78697_1548x4328.png 848w, https://substackcdn.com/image/fetch/$s_!e1Uq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F917d1ea0-3719-4a98-9a14-99e657e78697_1548x4328.png 1272w, https://substackcdn.com/image/fetch/$s_!e1Uq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F917d1ea0-3719-4a98-9a14-99e657e78697_1548x4328.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!e1Uq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F917d1ea0-3719-4a98-9a14-99e657e78697_1548x4328.png" width="1456" height="4071" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/917d1ea0-3719-4a98-9a14-99e657e78697_1548x4328.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:4071,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1092399,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F917d1ea0-3719-4a98-9a14-99e657e78697_1548x4328.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!e1Uq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F917d1ea0-3719-4a98-9a14-99e657e78697_1548x4328.png 424w, https://substackcdn.com/image/fetch/$s_!e1Uq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F917d1ea0-3719-4a98-9a14-99e657e78697_1548x4328.png 848w, https://substackcdn.com/image/fetch/$s_!e1Uq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F917d1ea0-3719-4a98-9a14-99e657e78697_1548x4328.png 1272w, https://substackcdn.com/image/fetch/$s_!e1Uq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F917d1ea0-3719-4a98-9a14-99e657e78697_1548x4328.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7OBR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69f319a-cded-4751-b993-647affdbe943_905x582.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7OBR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69f319a-cded-4751-b993-647affdbe943_905x582.png 424w, https://substackcdn.com/image/fetch/$s_!7OBR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69f319a-cded-4751-b993-647affdbe943_905x582.png 848w, https://substackcdn.com/image/fetch/$s_!7OBR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69f319a-cded-4751-b993-647affdbe943_905x582.png 1272w, https://substackcdn.com/image/fetch/$s_!7OBR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69f319a-cded-4751-b993-647affdbe943_905x582.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7OBR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69f319a-cded-4751-b993-647affdbe943_905x582.png" width="905" height="582" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b69f319a-cded-4751-b993-647affdbe943_905x582.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:582,&quot;width&quot;:905,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:77779,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69f319a-cded-4751-b993-647affdbe943_905x582.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!7OBR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69f319a-cded-4751-b993-647affdbe943_905x582.png 424w, https://substackcdn.com/image/fetch/$s_!7OBR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69f319a-cded-4751-b993-647affdbe943_905x582.png 848w, https://substackcdn.com/image/fetch/$s_!7OBR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69f319a-cded-4751-b993-647affdbe943_905x582.png 1272w, https://substackcdn.com/image/fetch/$s_!7OBR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb69f319a-cded-4751-b993-647affdbe943_905x582.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Above, we&#8217;ve used a kappa of 50. As you can see, turnover is very heavily reduced.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!bqIP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e407acb-9d3c-4a81-8d38-c8e0b3d49f3e_775x488.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bqIP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e407acb-9d3c-4a81-8d38-c8e0b3d49f3e_775x488.png 424w, https://substackcdn.com/image/fetch/$s_!bqIP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e407acb-9d3c-4a81-8d38-c8e0b3d49f3e_775x488.png 848w, https://substackcdn.com/image/fetch/$s_!bqIP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e407acb-9d3c-4a81-8d38-c8e0b3d49f3e_775x488.png 1272w, https://substackcdn.com/image/fetch/$s_!bqIP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e407acb-9d3c-4a81-8d38-c8e0b3d49f3e_775x488.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bqIP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e407acb-9d3c-4a81-8d38-c8e0b3d49f3e_775x488.png" width="775" height="488" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0e407acb-9d3c-4a81-8d38-c8e0b3d49f3e_775x488.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:488,&quot;width&quot;:775,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:41515,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e407acb-9d3c-4a81-8d38-c8e0b3d49f3e_775x488.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!bqIP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e407acb-9d3c-4a81-8d38-c8e0b3d49f3e_775x488.png 424w, https://substackcdn.com/image/fetch/$s_!bqIP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e407acb-9d3c-4a81-8d38-c8e0b3d49f3e_775x488.png 848w, https://substackcdn.com/image/fetch/$s_!bqIP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e407acb-9d3c-4a81-8d38-c8e0b3d49f3e_775x488.png 1272w, https://substackcdn.com/image/fetch/$s_!bqIP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e407acb-9d3c-4a81-8d38-c8e0b3d49f3e_775x488.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Here you can see that as you increase your turnover penalty kappa, your improvement vs an unpenalized portfolio becomes better and better, but returns are becoming diminishing with values &gt;= 30.</p><p>In a real market that can change more abruptly, you may want to pick kappa slightly lower to be able to adapt more quickly.</p><h3>Benchmark-relative optimization</h3><p>Many institutional mandates are benchmark-relative. Let w_b be benchmark weights. Define active weights a = w - w_b. Then tracking error variance is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathrm{TE}^2 = a^\\top \\Sigma a.\n\n\\tag{3.17}&quot;,&quot;id&quot;:&quot;ZOUHVKQQPD&quot;}" data-component-name="LatexBlockToDOM"></div><p>A common optimization is to maximize expected active return subject to tracking error:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\begin{aligned}\n\n\\max_{a}\n\n&amp;\\quad a^\\top \\alpha \\\\\n\n\\text{s.t.}\n\n&amp;\\quad a^\\top \\Sigma a \\le \\sigma_{\\mathrm{TE}}^2, \\\\\n\n&amp;\\quad \\mathbf{1}^\\top a = 0,\n\n\\end{aligned}\n\n\\tag{3.18}&quot;,&quot;id&quot;:&quot;ILCPQLZDWD&quot;}" data-component-name="LatexBlockToDOM"></div><p>where alpha represents expected alphas (expected excess returns relative to benchmark). This formulation has an important robustness advantage: it anchors the portfolio near a diversified benchmark, limiting the optimizer&#8217;s ability to create extreme positions driven by noise. In effect, the benchmark provides a strong prior on the weight vector.</p><p>Even if one is not formally benchmarked, this insight generalizes: anchoring optimization around a reference portfolio (market, equal weight, risk parity) often improves stability.</p><h3>Robust Optimization: Optimizing against parameter uncertainty directly</h3><p>A conceptually clean way to address estimation error is to incorporate uncertainty sets for mu and/or Sigma, then optimize a worst-case objective. This approach turns &#8220;garbage in, garbage out&#8221; into &#8220;uncertainty in, robustness out.&#8221;</p><p>One standard robust mean model assumes mu lies in an ellipsoid around hat{mu}:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\mathcal{U}_\\mu = \\left\\{ \\mu: (\\mu - \\hat{\\mu})^\\top \\hat{\\Sigma}^{-1} (\\mu - \\hat{\\mu}) \\le \\kappa^2 \\right\\}\n\n\\tag{3.19}&quot;,&quot;id&quot;:&quot;QHVOHJQZVS&quot;}" data-component-name="LatexBlockToDOM"></div><p>Consider the robust counterpart of maximizing expected return minus risk, taking the worst-case mean:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\max_{w:\\mathbf{1}^\\top w=1} \\left( \\min_{\\mu \\in \\mathcal{U}_\\mu} w^\\top \\mu - \\frac{\\gamma}{2} w^\\top \\hat{\\Sigma} w \\right).\n\n\\tag{3.20}&quot;,&quot;id&quot;:&quot;MCCEVFZQQL&quot;}" data-component-name="LatexBlockToDOM"></div><p>The inner minimization has a closed form:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\min_{\\mu \\in \\mathcal{U}_\\mu} w^\\top \\mu = w^\\top \\hat{\\mu} - \\kappa \\sqrt{w^\\top \\hat{\\Sigma} w}.\n\n\\tag{3.21}&quot;,&quot;id&quot;:&quot;TLEJWZWLRJ&quot;}" data-component-name="LatexBlockToDOM"></div><p>So the robust problem becomes</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\max_{w:\\mathbf{1}^\\top w=1} \\left( w^\\top \\hat{\\mu} - \\kappa \\sqrt{w^\\top \\hat{\\Sigma} w} - \\frac{\\gamma}{2} w^\\top \\hat{\\Sigma} w \\right).\n\n\\tag{3.22}&quot;,&quot;id&quot;:&quot;KXMWSSTEHA&quot;}" data-component-name="LatexBlockToDOM"></div><p>  This is illuminating. The robust adjustment subtracts a term proportional to portfolio volatility, effectively reducing the attractiveness of portfolios whose expected return advantage might be explained by estimation error. The optimizer is forced to find portfolios whose expected return is high <em>relative to uncertainty</em>.</p><p>Robust covariance uncertainty sets lead to related regularization effects, often inflating risk in uncertain directions; again echoing the intuition behind shrinkage and ridge penalties. Robust optimization provides a principled bridge between statistical uncertainty and optimization regularization.</p><p>Let&#8217;s compare this to standard MVO:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!RwHk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8331ae8f-c7d0-4b74-b73b-1dde0c5cc95c_1732x3546.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!RwHk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8331ae8f-c7d0-4b74-b73b-1dde0c5cc95c_1732x3546.png 424w, https://substackcdn.com/image/fetch/$s_!RwHk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8331ae8f-c7d0-4b74-b73b-1dde0c5cc95c_1732x3546.png 848w, https://substackcdn.com/image/fetch/$s_!RwHk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8331ae8f-c7d0-4b74-b73b-1dde0c5cc95c_1732x3546.png 1272w, https://substackcdn.com/image/fetch/$s_!RwHk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8331ae8f-c7d0-4b74-b73b-1dde0c5cc95c_1732x3546.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!RwHk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8331ae8f-c7d0-4b74-b73b-1dde0c5cc95c_1732x3546.png" width="1456" height="2981" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8331ae8f-c7d0-4b74-b73b-1dde0c5cc95c_1732x3546.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2981,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:961128,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8331ae8f-c7d0-4b74-b73b-1dde0c5cc95c_1732x3546.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!RwHk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8331ae8f-c7d0-4b74-b73b-1dde0c5cc95c_1732x3546.png 424w, https://substackcdn.com/image/fetch/$s_!RwHk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8331ae8f-c7d0-4b74-b73b-1dde0c5cc95c_1732x3546.png 848w, https://substackcdn.com/image/fetch/$s_!RwHk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8331ae8f-c7d0-4b74-b73b-1dde0c5cc95c_1732x3546.png 1272w, https://substackcdn.com/image/fetch/$s_!RwHk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8331ae8f-c7d0-4b74-b73b-1dde0c5cc95c_1732x3546.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!YSLy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89f1c92b-a219-4a6b-afc1-7a900bc204d7_925x675.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!YSLy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89f1c92b-a219-4a6b-afc1-7a900bc204d7_925x675.png 424w, https://substackcdn.com/image/fetch/$s_!YSLy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89f1c92b-a219-4a6b-afc1-7a900bc204d7_925x675.png 848w, https://substackcdn.com/image/fetch/$s_!YSLy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89f1c92b-a219-4a6b-afc1-7a900bc204d7_925x675.png 1272w, https://substackcdn.com/image/fetch/$s_!YSLy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89f1c92b-a219-4a6b-afc1-7a900bc204d7_925x675.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!YSLy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89f1c92b-a219-4a6b-afc1-7a900bc204d7_925x675.png" width="925" height="675" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/89f1c92b-a219-4a6b-afc1-7a900bc204d7_925x675.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:675,&quot;width&quot;:925,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:88163,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.vertoxquant.com/i/186718680?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89f1c92b-a219-4a6b-afc1-7a900bc204d7_925x675.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!YSLy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89f1c92b-a219-4a6b-afc1-7a900bc204d7_925x675.png 424w, https://substackcdn.com/image/fetch/$s_!YSLy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89f1c92b-a219-4a6b-afc1-7a900bc204d7_925x675.png 848w, https://substackcdn.com/image/fetch/$s_!YSLy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89f1c92b-a219-4a6b-afc1-7a900bc204d7_925x675.png 1272w, https://substackcdn.com/image/fetch/$s_!YSLy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89f1c92b-a219-4a6b-afc1-7a900bc204d7_925x675.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Our Robust MVO weights are a lot more &#8220;clean&#8221; compared to the standard MVO weights.</p><h1>Conclusion</h1><p>It is tempting to treat the practical modifications above as an ad hoc toolbox: shrinkage here, constraints there, turnover penalties elsewhere. A more coherent view is that these methods all solve the same underlying problem:</p><p><strong>The plug-in MVO portfolio is a high-variance estimator of the optimal weights.</strong></p><p>Reducing that variance requires injecting structure, equivalently, adding bias.</p><ul><li><p>Shrinkage of Sigma reduces the variance of covariance estimates (and stabilizes inversion) at the cost of bias toward the target structure.</p></li><li><p>Factor models impose a low-rank structure that may be misspecified but dramatically reduces estimation noise.</p></li><li><p>Shrinkage and Bayesian methods for mu explicitly acknowledge that sample means are too noisy to trust fully.</p></li><li><p>Constraints and penalties reduce the effective degrees of freedom of the portfolio, preventing the optimizer from encoding noise into intricate weight patterns.</p></li><li><p>Turnover penalties reduce the variance of <em>changes</em> in weights, which is often the real operational pain point.</p></li><li><p>Robust optimization is an explicit uncertainty-aware form of regularization.</p></li></ul><p>From this perspective, the &#8220;right&#8221; portfolio is not the one that is optimal for the estimated parameters; it is the one that is optimal for the <em>decision problem under uncertainty</em>, including estimation error, non-stationarity, and implementability constraints.</p><p>Quant Corner: <a href="https://discord.gg/X7TsxKNbXg">https://discord.gg/X7TsxKNbXg</a></p><p>Code: <a href="https://gist.github.com/vertoxquant/e417b8afd2abe0e15ae0ff486813842a">https://gist.github.com/vertoxquant/e417b8afd2abe0e15ae0ff486813842a</a></p>]]></content:encoded></item><item><title><![CDATA[The Myth of Factor-Free Crypto]]></title><description><![CDATA[Applying equity-style factors to digital assets]]></description><link>https://www.vertoxquant.com/p/the-myth-of-factor-free-crypto</link><guid isPermaLink="false">https://www.vertoxquant.com/p/the-myth-of-factor-free-crypto</guid><dc:creator><![CDATA[Vertox]]></dc:creator><pubDate>Tue, 27 Jan 2026 11:58:38 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!XkCB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34bf8966-164f-4e82-b241-c63702a902d9_1189x390.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>People keep telling you to take what works in equities and apply it to crypto.<br>Those same people then claim that factors don&#8217;t exist in crypto at all.</p><p>At first glance, that contradiction seems justified. Crypto markets look nothing like equities: trading is continuous, liquidity is fragmented across venues, listings and delistings are frequent, and returns are dominated by a long tail of illiquid tokens.</p><p>Let&#8217;s answer once and for all if equity factors exist in crypto and if you can profit from them.</p><p>By the end of this article, you&#8217;ll have a framework for answering that question yourself. You&#8217;ll see how to test new factors and alphas in a way that is robust to listings and delistings, a changing universe, and the realities of trading crypto markets. The full research notebook used in the analysis is available for download at the end of the article for paid subscribers.</p>
      <p>
          <a href="https://www.vertoxquant.com/p/the-myth-of-factor-free-crypto">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Fitting Regime Switching Models to High-Frequency Data]]></title><description><![CDATA[With derivations]]></description><link>https://www.vertoxquant.com/p/fitting-regime-switching-models</link><guid isPermaLink="false">https://www.vertoxquant.com/p/fitting-regime-switching-models</guid><dc:creator><![CDATA[Vertox]]></dc:creator><pubDate>Thu, 22 Jan 2026 11:54:30 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!wRfA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa704e37a-e30a-405e-961f-ed8a5c020d80_627x470.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>Introduction</h1><p>In the previous article, we built all of the theory behind HMMs for microstructural data. This article is where it finally gets real, and we fit those models to actual market data efficiently.</p><p>We are going to take something that is completely infeasible in practice, on the order of 10^430 computations. To put that in perspective, if you took every atom in our universe, put a new universe inside each atom, and repeated that process five times, you would reach a number around that size. Then we collapse it down to roughly 9000 computations that you can actually run.</p><p>By the end of this article, you will be able to take real market data, fit an HMM to it, and identify which market regime you are most likely in</p>
      <p>
          <a href="https://www.vertoxquant.com/p/fitting-regime-switching-models">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[The Birth of a Quant Community]]></title><description><![CDATA[Quant Corner]]></description><link>https://www.vertoxquant.com/p/the-birth-of-a-quant-community</link><guid isPermaLink="false">https://www.vertoxquant.com/p/the-birth-of-a-quant-community</guid><dc:creator><![CDATA[Vertox]]></dc:creator><pubDate>Wed, 21 Jan 2026 07:29:57 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/9fa63885-94bf-478b-9908-29f319b0b115_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I&#8217;ve been around on quant discord servers for 6 years now and have always noticed the same trends:</p><ul><li><p>Small communities that are invite only just tend to die down eventually.</p></li><li><p>Big servers don&#8217;t really offer much value or do anything fun.</p></li></ul><p>That&#8217;s exactly what I want to change with <strong><a href="https://discord.gg/X7TsxKNbXg">Quant Corner</a></strong>!</p><p>The goal is simple: build a community that actually <em>does things</em>.<br>Think tournaments, live Q&amp;As, useful resource giveaways, and open discussions where your feedback genuinely shapes what we build next.</p><p>Quant Corner is also the best place to engage directly with me, share ideas, suggest events, and help steer the direction of the community.</p><p>We&#8217;re currently at <strong>~440 members</strong>, and once we hit <strong>800</strong>, I&#8217;ll be hosting something <em><strong>big.</strong></em></p><p>If this sounds like something you&#8217;d want to be part of, join us here:<br><a href="https://discord.gg/X7TsxKNbXg">https://discord.gg/X7TsxKNbXg</a></p>]]></content:encoded></item><item><title><![CDATA[Regime Switching Models for Microstructure Features]]></title><description><![CDATA[Understanding State Dependence in Market Microstructure]]></description><link>https://www.vertoxquant.com/p/regime-switching-models-for-microstructure</link><guid isPermaLink="false">https://www.vertoxquant.com/p/regime-switching-models-for-microstructure</guid><dc:creator><![CDATA[Vertox]]></dc:creator><pubDate>Fri, 16 Jan 2026 10:19:54 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/55b4c663-1e6f-4679-9526-16d93f2985ec_607x392.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>Introduction</h1><p>Many financial features exhibit regime behavior: low vs. high volatility, choppy vs. trending markets, liquid vs. illiquid conditions.</p><p>These regimes are not directly observable. Instead, we only see their manifestations in market data such as prices, returns, volumes, and spreads.</p><p>As a result, microstructure features may exhibit different statistical behaviour depending on the underlying market state, raising the question of how they should be analysed in practice.</p>
      <p>
          <a href="https://www.vertoxquant.com/p/regime-switching-models-for-microstructure">
              Read more
          </a>
      </p>
   ]]></content:encoded></item></channel></rss>