heiner.ai
https://heiner.ai/
Thu, 17 Sep 2020 16:29:55 +0000Thu, 17 Sep 2020 16:29:55 +0000Jekyll v3.9.0More on linear regression: Capital asset pricing models<p>This is the long-awaited second part of February’s post on <a href="/blog/2020/02/19/linear-regression.html">Linear
Regression</a>. This time,
without the needlessly abstract math, but with some classic portfolio
theory as an example of “applied linear regression”.</p>
<p>We’ll be discussing two papers: <a href="https://onlinelibrary.wiley.com/doi/full/10.1111/j.1540-6261.1968.tb00815.x" target="_blank"><em>The performance of mutual funds in
the period 1945-1964</em> (1968) by Michael
Jensen</a>
and <a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.139.5892" target="_blank"><em>Common Risk
Factors in the Returns On Stocks And Bonds</em> (1993) by Eugene Fama
and Kenneth French</a>.</p>
<p>Some disclaimers:</p>
<ul>
<li>I am by no means an expert on this topic. I learned about these
investing concepts on the <a href="https://rationalreminder.ca" target="_blank">Rational Reminder
podcast</a> by the
excellent Benjamin Felix and Cameron Passmore.</li>
<li>There’s many more results on this, both classic and
recent. The two papers discussed here added some delta at the time,
but previous results by others were essential too, and get no
mention here. I chose these two papers because they are relatively easy to
follow and their main message can be explained well in a blog post.</li>
<li>All of this is just for fun. Capital at risk.</li>
</ul>
<h2 id="jensen-1968-standard-stuff">Jensen (1968): Standard stuff.</h2>
<h4 id="on-models">On models</h4>
<p>The papers we discuss present <em>models</em>. Models have assumptions as
well as domains in which they are valid and domains in which they are
not. We are not going to make precise statements about either of
these, but it’s useful to not confuse models with reality. ‘Whereof one
has no model thereof one must be silent’ (otherwise, <em>philosophus
mansisses</em>). This is also known as <a href="https://en.wikipedia.org/wiki/Streetlight_effect" target="_blank">searching under the
streetlights</a>.</p>
<p>The <em>aim</em> of our model will be to evaluate, or assess, the performance
of any given portfolio. Specifically, the model should evaluate
a portfolio manager’s ability to increase returns by successfully
predicting future prices for a <em>given level of riskiness</em>. For
instance, if stock market returns are positive in expectation, a
leveraged portfolio could outperform an unleveraged portfolio without
any special forecasting ability on the manager’s part. Conversely, a
classical <a href="https://www.investopedia.com/articles/financial-advisors/011916/why-6040-portfolio-no-longer-good-enough.asp" target="_blank">60/40 mix of stocks and
bonds</a>
would likely do worse than a 100% equity portfolio in this case, but
may still be preferable due to its reduced risk. We won’t go into
detail how risk is measured, but we should mention that under certain
assumptions, it is precisely its riskiness that causes a given asset
to yield higher returns (<em>ceteris paribus</em>, and on average): If
investors are risk-averse, they will need to be compensated for
taking on the additional risk of a specific asset compared to some
other asset, and higher expected future returns (expected future
prices relative to its current price) are the way that
compensation happens in a liquid market. Of course, the actual
expectation of any given investor may also just be wrong, but over
time one may expect the worst investors to drop out, improving the
accuracy of the average investor’s expectations.</p>
<h4 id="time-series-regressions">Time series regressions</h4>
<p>The specific models here do linear regression on time series. Suppose
we have one data point per time interval, e.g. per trading day:</p>
<table>
<thead>
<tr>
<th style="text-align: left">day</th>
<th> </th>
<th style="text-align: right">value</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">5 January 1970</td>
<td> </td>
<td style="text-align: right">388.8K</td>
</tr>
<tr>
<td style="text-align: left">6 January 1970</td>
<td> </td>
<td style="text-align: right">475.2K</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td>⋮</td>
<td style="text-align: right"> </td>
</tr>
</tbody>
</table>
<p>We will use this data as an \(n\)-dimensional feature vector (aka explanatory
variable). Think of it as coming from the value of an index,
specifically from the capitalization-weighted value of the
whole stock market on that trading day. We will call this the <em>market
portfolio</em>.</p>
<p>The portfolio (or individual stock) we want to assess will also have a
value each trading day. This puts us in a situation in which we could
try to use linear regression to express our assessed portfolio as a
linear combination of the market value and a constant intercept
vector. However, little would be gained by just doing that – we’ll
have to at least normalize things a bit, otherwise this is what the
model will use its capacity (two numbers!) for. And while we are at
it, we remember that there used to be a time when the (almost, or by
definition) risk-free return offered by central banks was not
basically zero. To tease out the “risk factor”, we will use the market
return minus this risk-free rate as our feature vector. Our data thus
could look like this:</p>
<table>
<thead>
<tr>
<th style="text-align: left">day</th>
<th> </th>
<th style="text-align: right">market</th>
<th style="text-align: right">risk-free</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">5 January 1970</td>
<td> </td>
<td style="text-align: right">1.21%</td>
<td style="text-align: right">0.029%</td>
</tr>
<tr>
<td style="text-align: left">6 January 1970</td>
<td> </td>
<td style="text-align: right">0.62%</td>
<td style="text-align: right">0.029%</td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td>⋮</td>
<td style="text-align: right"> </td>
<td style="text-align: right"> </td>
</tr>
</tbody>
</table>
<p>For the risk-free rate, one could use the treasury bill rate. All these
numbers can in principle be retrieved from the historical
records (and in practice downloaded from <a href="https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html" target="_blank">Kenneth French’s
homepage</a>).</p>
<p>Let’s call the market return \(R_M\) and the risk-free return
\(R_F\). A sensible regression without an intercept term could then
read as</p>
\[R \approx R_F + \beta(R_M - R_F), \label{eq:1}\tag{1}\]
<p>where \(R\) is vector the observed returns of the portfolio or stock
we want to assess, and \(\beta\) is computed via the least-squares
condition of linear regression, i.e., \(\beta = \argmin\{\abs{R - R_F -
\beta(R_M - R_F)}_2\st \beta\in\R\}\), as in the <a href="/blog/2020/02/19/linear-regression.html" target="_blank">last blog post</a>. Notice that the \(R_F\)s
make sense here: It’s deviations from this risk-free return that we
want to model, and we want \(\beta\) to scale the non risk-free
portion of the market portfolio.</p>
<p><strong>Example.</strong> For a classic 60/40
portfolio with 60% whole market and 40% risk-free return (historically
not realistic for private investors, but easy to compute) we have</p>
\[R - R_F= 0.6R_M + 0.4R_F - R_F = 0.6(R_M - R_F)\in\R^{n\times 1}\]
<p>and therefore, by the <a href="/blog/2020/02/19/linear-regression.html" target="_blank">normal equation</a>,</p>
\[\beta = \bigl((R_M - R_F)^\top (R_M - R_F)\bigr)^{-1}
(R_M - R_F)^\top (R - R_F) = 0.6.\]
<p>That seems sensible in this case.</p>
<h4 id="finding-alpha">Finding Alpha</h4>
<p>However, \eqref{eq:1} isn’t quite good enough: More precisely, it
reads</p>
\[R = R_F + \beta(R_M - R_F) + e, \label{eq:2}\tag{2}\]
<p>with an error term \(e\in\R^n\). As Jensen (1968) argues,</p>
<blockquote>
<p>[W]e must be very careful when applying the equation to managed portfolios. If the manager is a superior forecaster (perhaps because of
special knowledge not available to others) he will tend to systematically select
securities which realize [\(e_j > 0\)].</p>
</blockquote>
<p>This touches on a subject glossed over in the last blog post: Most
statements about linear regression models depend on certain
statistical assumptions, among them that
the error terms are elementwise iid, ideally with a mean of zero. There’s
autocorrelation tests like
<a href="https://en.wikipedia.org/wiki/Durbin%E2%80%93Watson_statistic" target="_blank">Durbin-Watson</a>
to test if this is true for a particular dataset. In this
particular modeling exercise, we can do better by
adding the constant \(\1=(1,\ldots,1)\in\R^n\) intercept vector to the
subspace we project on, which turns \eqref{eq:2} into</p>
\[R - R_F = \alpha + \beta(R_M - R_F) + u, \label{eq:3}\tag{3}\]
<p>with an error term \(u\in\R^n\).</p>
<p><em>Ever wondered where the
“<a href="https://en.wikipedia.org/wiki/Alpha_(finance)" target="_blank">alpha</a>” in the
clickbait website <a href="https://seekingalpha.com/" target="_blank">Seeking Alpha</a> comes
from?</em> It is this \(\alpha\), the coefficient of the
\(\1\) intercept vector in \eqref{eq:3}. To quote
Jensen (1968) again:</p>
<blockquote>
<p>Thus if the portfolio manager has an ability to forecast security prices, the
intercept, [\(\alpha\), in eq. \eqref{eq:3}] will be positive. Indeed,
it represents the average incremental rate of return on the portfolio
per unit time which is due solely to
the manager’s ability to forecast future security prices. It is
interesting to
note that a naive random selection buy and hold policy can be expected to
yield a zero intercept. In addition if the manager is not doing as
well as a
random selection buy and hold policy, [\(\alpha\)] will be
negative. At first glance it
might seem difficult to do worse than a random selection policy, but such
results may very well be due to the generation of too many expenses in unsuccessful forecasting attempts.</p>
<p>However, given that we observe a positive intercept in any sample of returns on a portfolio we have the difficulty of judging whether or not this
observation was due to mere random chance or to the superior forecasting
ability of the portfolio manager. […]</p>
<p>It should be emphasized that in estimating [\(\alpha\)], the measure
of performance,
we are explicitly allowing for the effects of risk on return as implied by the
asset pricing model. Moreover, it should also be noted that if the model is
valid, the particular nature of general economic conditions or the particular
market conditions (the behavior of \(\pi\)) over the sample or evaluation period
has no effect whatsoever on the measure of performance. Thus our measure
of performance can be legitimately compared across funds of different risk
levels and across different time periods irrespective of general economic and
market condition.</p>
</blockquote>
<p>About the error term \(u\), first notice that thanks to the intercept
term we can expect it to have a mean of zero. Further, Jensen (1968)
argues it “should be serially [i.e., elementwise] independent” as
otherwise “the manager could increase his return even more by
taking account of the information contained in the serial dependence
and would therefore eliminate it.”</p>
<h3 id="just-show-me-the-code">Just show me the code!</h3>
<p>After introducing this model, Jensen (1968) continues with “the data
and empirical results”. In ca. 2015 AI parlance, this part could be
called “Experiments”. Take a look at Table 1 in the paper to get a
list of quaint mutual fund names. Notice too that it’s not immediately
obvious how to get the market portfolio’s returns from historical
trading data, as companies enter and leave the stock market, and how
they leave will play a huge role. (Bankruptcy? Taken private at
$420?)</p>
<p>For our purposes though, all of this has been taken care of and
<a href="https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html" target="_blank">Kenneth French’s
homepage</a>
has the data, including data for each trading day, in usable
formats.</p>
<p>Let’s start by getting the data and sanity-checking our 60/40 example
above. All of the code in this post can also be <a href="/src/ff3f.py">downloaded
separately</a> or
run in a <a href="https://colab.research.google.com/drive/1iqpYDgpElizyAWW-6xXHMTpatw0Hqm1c?usp=sharing" target="_blank">Google Colab</a>.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">re</span>
<span class="kn">import</span> <span class="nn">urllib.request</span>
<span class="kn">import</span> <span class="nn">zipfile</span>
<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="n">FF3F</span> <span class="o">=</span> <span class="p">(</span> <span class="c1"># Monthly data.
</span> <span class="s">"https://mba.tuck.dartmouth.edu/pages/faculty/"</span>
<span class="s">"ken.french/ftp/F-F_Research_Data_Factors_TXT.zip"</span>
<span class="p">)</span>
<span class="k">def</span> <span class="nf">download</span><span class="p">(</span><span class="n">url</span><span class="o">=</span><span class="n">FF3F</span><span class="p">):</span>
<span class="n">archive</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">basename</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">exists</span><span class="p">(</span><span class="n">archive</span><span class="p">):</span>
<span class="k">print</span><span class="p">(</span><span class="s">"Retrieving"</span><span class="p">,</span> <span class="n">url</span><span class="p">)</span>
<span class="n">urllib</span><span class="p">.</span><span class="n">request</span><span class="p">.</span><span class="n">urlretrieve</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">archive</span><span class="p">)</span>
<span class="k">return</span> <span class="n">archive</span>
<span class="k">def</span> <span class="nf">extract</span><span class="p">(</span><span class="n">archive</span><span class="p">,</span> <span class="n">match</span><span class="o">=</span><span class="n">re</span><span class="p">.</span><span class="nb">compile</span><span class="p">(</span><span class="s">rb"\d"</span> <span class="o">*</span> <span class="mi">6</span><span class="p">)):</span>
<span class="k">with</span> <span class="n">zipfile</span><span class="p">.</span><span class="n">ZipFile</span><span class="p">(</span><span class="n">archive</span><span class="p">)</span> <span class="k">as</span> <span class="n">z</span><span class="p">:</span>
<span class="n">name</span><span class="p">,</span> <span class="o">*</span><span class="n">rest</span> <span class="o">=</span> <span class="n">z</span><span class="p">.</span><span class="n">namelist</span><span class="p">()</span>
<span class="k">assert</span> <span class="ow">not</span> <span class="n">rest</span>
<span class="k">with</span> <span class="n">z</span><span class="p">.</span><span class="nb">open</span><span class="p">(</span><span class="n">name</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="c1"># Filter for the actual data lines in the file.
</span> <span class="k">return</span> <span class="n">np</span><span class="p">.</span><span class="n">loadtxt</span><span class="p">((</span><span class="n">line</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">f</span> <span class="k">if</span> <span class="n">match</span><span class="p">.</span><span class="n">match</span><span class="p">(</span><span class="n">line</span><span class="p">)),</span> <span class="n">unpack</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">date</span><span class="p">,</span> <span class="n">mktmrf</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">rf</span> <span class="o">=</span> <span class="n">extract</span><span class="p">(</span><span class="n">download</span><span class="p">())</span>
<span class="n">mkt</span> <span class="o">=</span> <span class="n">mktmrf</span> <span class="o">+</span> <span class="n">rf</span>
<span class="c1"># Linear regression using the normal equation.
</span><span class="n">A</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">stack</span><span class="p">([</span><span class="n">np</span><span class="p">.</span><span class="n">ones_like</span><span class="p">(</span><span class="n">mktmrf</span><span class="p">),</span> <span class="n">mktmrf</span><span class="p">],</span> <span class="n">axis</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="n">alpha</span><span class="p">,</span> <span class="n">beta</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">inv</span><span class="p">(</span><span class="n">A</span><span class="p">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">A</span><span class="p">)</span> <span class="o">@</span> <span class="n">A</span><span class="p">.</span><span class="n">T</span> <span class="o">@</span> <span class="p">(</span><span class="mf">0.6</span> <span class="o">*</span> <span class="n">mkt</span> <span class="o">+</span> <span class="mf">0.4</span> <span class="o">*</span> <span class="n">rf</span> <span class="o">-</span> <span class="n">rf</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"alpha=%f; beta=%f"</span> <span class="o">%</span> <span class="p">(</span><span class="n">alpha</span><span class="p">,</span> <span class="n">beta</span><span class="p">))</span>
</code></pre></div></div>
<p>As expected, this prints</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>alpha=0.000000; beta=0.600000
</code></pre></div></div>
<p>If we are seeking \(\alpha\), we’ll have to look elsewhere.</p>
<p>Let’s try some real data. The biggest issue is getting hold of
the daily returns of real portfolios. Real researchers use data
sources like the <a href="http://www.crsp.org/" target="_blank">Center for Research in Security Prices
(CRSP)</a>, but their data isn’t available for
free. Instead, let’s the data for iShares S&P Small-Cap 600 Value ETF
(IJS) from <a href="https://finance.yahoo.com/quote/IJS/history?period1=964742400&period2=1599350400&interval=1mo&filter=history&frequency=1mo" target="_blank">Yahoo
finance</a>.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Continuing from above.
</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="n">IJS</span> <span class="o">=</span> <span class="p">(</span>
<span class="s">"https://gist.githubusercontent.com/heiner/b222d0985cbebfdfc77288404e6b2735/"</span>
<span class="s">"raw/08c1cacecbcfcd9e30ce28ee6d3fe3d96c07115c/IJS.csv"</span>
<span class="p">)</span>
<span class="k">def</span> <span class="nf">extract_csv</span><span class="p">(</span><span class="n">archive</span><span class="p">):</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">archive</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="k">return</span> <span class="n">np</span><span class="p">.</span><span class="n">loadtxt</span><span class="p">(</span>
<span class="n">f</span><span class="p">,</span>
<span class="n">delimiter</span><span class="o">=</span><span class="s">","</span><span class="p">,</span>
<span class="n">skiprows</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="c1"># Header.
</span> <span class="n">converters</span><span class="o">=</span><span class="p">{</span> <span class="c1"># Hacky date handling.
</span> <span class="mi">0</span><span class="p">:</span> <span class="k">lambda</span> <span class="n">s</span><span class="p">:</span> <span class="n">time</span><span class="p">.</span><span class="n">strftime</span><span class="p">(</span>
<span class="s">"%Y%m"</span><span class="p">,</span> <span class="n">time</span><span class="p">.</span><span class="n">strptime</span><span class="p">(</span><span class="n">s</span><span class="p">.</span><span class="n">decode</span><span class="p">(</span><span class="s">"ascii"</span><span class="p">),</span> <span class="s">"%Y-%m-%d"</span><span class="p">)</span>
<span class="p">)</span>
<span class="p">},</span>
<span class="p">)</span>
<span class="n">ijs_data</span> <span class="o">=</span> <span class="n">extract_csv</span><span class="p">(</span><span class="n">download</span><span class="p">(</span><span class="n">IJS</span><span class="p">))</span>
<span class="n">ijs</span> <span class="o">=</span> <span class="n">ijs_data</span><span class="p">[:,</span> <span class="mi">5</span><span class="p">]</span> <span class="c1"># Adj Close (includes dividends).
</span>
<span class="c1"># Turn into monthly percentage returns.
</span><span class="n">ijs</span> <span class="o">=</span> <span class="mi">100</span> <span class="o">*</span> <span class="p">(</span><span class="n">ijs</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span> <span class="o">/</span> <span class="n">ijs</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">ijs_date</span> <span class="o">=</span> <span class="n">ijs_data</span><span class="p">[</span><span class="mi">1</span><span class="p">:,</span> <span class="mi">0</span><span class="p">]</span>
<span class="n">ijs_date</span><span class="p">,</span> <span class="n">indices</span><span class="p">,</span> <span class="n">ijs_indices</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">intersect1d</span><span class="p">(</span><span class="n">date</span><span class="p">,</span> <span class="n">ijs_date</span><span class="p">,</span> <span class="n">return_indices</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="c1"># Regression model for CAPM.
</span><span class="n">A</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">stack</span><span class="p">([</span><span class="n">np</span><span class="p">.</span><span class="n">ones_like</span><span class="p">(</span><span class="n">ijs_date</span><span class="p">),</span> <span class="n">mktmrf</span><span class="p">[</span><span class="n">indices</span><span class="p">]],</span> <span class="n">axis</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="n">y</span> <span class="o">=</span> <span class="n">ijs</span><span class="p">[</span><span class="n">ijs_indices</span><span class="p">]</span> <span class="o">-</span> <span class="n">rf</span><span class="p">[</span><span class="n">indices</span><span class="p">]</span>
<span class="n">B</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">inv</span><span class="p">(</span><span class="n">A</span><span class="p">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">A</span><span class="p">)</span> <span class="o">@</span> <span class="n">A</span><span class="p">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">y</span>
<span class="n">alpha</span><span class="p">,</span> <span class="n">beta</span> <span class="o">=</span> <span class="n">B</span>
<span class="c1"># R^2 and adjusted R^2.
</span><span class="n">model_err</span> <span class="o">=</span> <span class="n">A</span> <span class="o">@</span> <span class="n">B</span> <span class="o">-</span> <span class="n">y</span>
<span class="n">ss_err</span> <span class="o">=</span> <span class="n">model_err</span><span class="p">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">model_err</span>
<span class="n">r2</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">-</span> <span class="n">ss_err</span><span class="p">.</span><span class="n">item</span><span class="p">()</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="n">var</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="n">ddof</span><span class="o">=</span><span class="nb">len</span><span class="p">(</span><span class="n">y</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">adjr2</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">-</span> <span class="n">ss_err</span><span class="p">.</span><span class="n">item</span><span class="p">()</span> <span class="o">/</span> <span class="p">(</span><span class="n">A</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="n">A</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="n">var</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="n">ddof</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span>
<span class="s">"CAPM: alpha=%.2f%%; beta=%.2f. R^2=%.1f%%; R_adj^2=%.1f%%. Annualized alpha: %.2f%%"</span>
<span class="o">%</span> <span class="p">(</span>
<span class="n">alpha</span><span class="p">,</span>
<span class="n">beta</span><span class="p">,</span>
<span class="mi">100</span> <span class="o">*</span> <span class="n">r2</span><span class="p">,</span>
<span class="mi">100</span> <span class="o">*</span> <span class="n">adjr2</span><span class="p">,</span>
<span class="p">((</span><span class="mi">1</span> <span class="o">+</span> <span class="n">alpha</span> <span class="o">/</span> <span class="mi">100</span><span class="p">)</span> <span class="o">**</span> <span class="mi">12</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mi">100</span><span class="p">,</span>
<span class="p">)</span>
<span class="p">)</span>
</code></pre></div></div>
<p>This prints:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CAPM: alpha=0.13%; beta=1.14. R^2=77.8%; R_adj^2=77.7%. Annualized alpha: 1.58%
</code></pre></div></div>
<p>Since \(\alpha\) is the weight for the constant intercept vector \(\1
= (1,\ldots,1)\), we can think of it as having percentage points as
its unit. Note that fees are not included in this calculation.
However, as for many ETFs fees for IJS are low, currently at 0.25%
per year. (Managed mutual funds will typically have an
annual fee of at least 1%, historically often more than that.)</p>
<p>It seems bit strange that this ETF tracking the S&P Small-Cap 600
Value index has significant \(\alpha\): Presumably, the index just
includes firms based on simple rules, not genius insights by some
above-average fund manager. Looking at the \(R^2\) value, we “explain”
only 77% of the variance of the returns of IJS (the usual caveats
to the wording “explain” apply).</p>
<p>Clearly more research was needed. Or just a larger subspace for the
linear regression to project onto?</p>
<h2 id="fama--french-1993-more-factors">Fama & French (1993): More factors.</h2>
<p>By the 1980s, research
into financial economics had noticed that certain segments of the market
outperformed other segments, and thus the market as a whole, on
average. There are several possible explanations for this effect with
different implications for the future. For example: Are these segments
of the market just inherently riskier such that rational traders
demand higher expected returns via sufficiently low prices for these
stocks? Or were traders
just irrationally disinterested in some ‘unsexy’ firms and have
perhaps caught on by now (or not, hence TSLA)? The latter is the
behavioural explanation, while the former tends to be put
forth by proponents of the <a href="https://en.wikipedia.org/wiki/Efficient-market_hypothesis" target="_blank">Efficient-market hypothesis
(EMH)</a>,
which includes
<a href="https://en.wikipedia.org/wiki/The_Superinvestors_of_Graham-and-Doddsville" target="_blank">Jensen</a>
as well as Fama and French.
We won’t be getting into this now. Let’s instead take
a look at which ‘easily’ identifiable segments of the market have
historically outperformed.</p>
<p>Citing previous literature, Fama & French (1993) mention <em>size</em>
(market capitalization, i.e., price per stock times number of shares),
<em>earnings per price</em> and <em>book-to-market</em> (book value divided by
market value) as variables that appear to have “explanatory power”,
which I take to mean that some model that includes these variables has
nonzero regression coefficients and a relatively large \(R^2\) or other
appropriate statistics.</p>
<p>The specific way in which Fama & French (1993) introduce these variables into
the model is through the construction of portfolios that mimic these
variables. This approach contributed to their being awarded the
Nobel (Memorial) Prize in Economic Sciences in 2013. The specific
construction goes as follows:</p>
<p>Take all stocks in the overall market and order them by their size
(i.e., market capitalization). Then take the top and bottom halves and
call them “<em>big</em>” (<em>B</em>) and “<em>small</em>” (<em>S</em>), respectively.</p>
<p>Next, again take all stocks in the overall market and order them by
book-to-market equity. Then take the bottom 30% (“<em>low</em>”, <em>L</em>), the middle 40%
(“<em>medium</em>”, <em>M</em>), and the top 30$ (“<em>high</em>”, <em>H</em>). In both cases, some care
needs to be taken: E.g., how to handle firms dropping in and out of the
market, how to define book equity properly in the presence of deferred
taxes, and other effects.</p>
<p>Then, construct the six portfolios containing stocks in the
intersections of the two size and the three book-to-market equity
groups, e.g.</p>
<table>
<thead>
<tr>
<th style="text-align: right"> </th>
<th style="text-align: center">low</th>
<th style="text-align: center">medium</th>
<th style="text-align: center">high</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: right"><strong>small</strong></td>
<td style="text-align: center"><em>S/L</em></td>
<td style="text-align: center"><em>S/M</em></td>
<td style="text-align: center"><em>S/H</em></td>
</tr>
<tr>
<td style="text-align: right"><strong>big</strong></td>
<td style="text-align: center"><em>B/L</em></td>
<td style="text-align: center"><em>B/M</em></td>
<td style="text-align: center"><em>B/H</em></td>
</tr>
</tbody>
</table>
<p>Out of these six building blocks, Fama & French build a <em>size</em> and a
<em>book-to-market equity</em> portfolio:</p>
<ul>
<li>
<p>The <em>size</em> portfolio is “small minus
big” (<em>SMB</em>) consisting of the monthly difference of the three
small-stock portfolios <em>S/L</em>, <em>S/M</em>, and <em>S/H</em> to the three big-stock
portfolios <em>B/L</em>, <em>B/M</em>, and <em>B/H</em>.</p>
</li>
<li>
<p>The <em>book-to-market equity</em> portfolio is “high minus low” (<em>HML</em>),
the monthly difference of the two high book-to-market
portfolios <em>S/H</em> and <em>B/H</em> to the two low book-to-market
portfolios <em>S/L</em> and <em>B/L</em>. This is also known as the <em>value</em>
factor.</p>
</li>
</ul>
<p>Additionally, the authors also use the <em>market portfolio</em> as “market
return minus risk-free return (one-month treasury bill rate)” in the
same way as Jensen (1968).</p>
<h4 id="an-aside">An aside</h4>
<p>I’m not sure why <em>SMB</em> and <em>HML</em> need the to have their
two terms be equally weighted among the splits of the other
ordering. The authors mention</p>
<blockquote>
<p>[For <em>HML</em>] the difference between the two returns should be largely free of
the size factor in returns, focusing instead on the different return
behaviors of high- and low-[book-to-market] firms. As testimony to the
success of this simple procedure, the correlation between the
1963–1991 monthly mimicking returns for the size and
book-to-market factors is only \(- 0.08\).</p>
</blockquote>
<p>Taking “correlation” to mean the Pearson correlation coefficient, we
can test this using the data from French’s homepage:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">date</span><span class="p">,</span> <span class="n">mktmrf</span><span class="p">,</span> <span class="n">smb</span><span class="p">,</span> <span class="n">hml</span><span class="p">,</span> <span class="n">rf</span> <span class="o">=</span> <span class="n">extract</span><span class="p">(</span><span class="n">download</span><span class="p">())</span>
<span class="k">print</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">corrcoef</span><span class="p">(</span><span class="n">smb</span><span class="p">,</span> <span class="n">hml</span><span class="p">))</span>
</code></pre></div></div>
<p>This prints</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[[1. 0.12889074]
[0.12889074 1. ]]
</code></pre></div></div>
<p>which implies a coefficient of \(0.13\). In 1993, Fama and French had
less data available: The paper uses the 342 months from July 1963 to
December 1991. Let’s check with this range:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">orig_indices</span> <span class="o">=</span> <span class="p">(</span><span class="mi">196307</span> <span class="o"><=</span> <span class="n">date</span><span class="p">)</span> <span class="o">&</span> <span class="p">(</span><span class="n">date</span> <span class="o"><=</span> <span class="mi">199112</span><span class="p">)</span>
<span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">smb</span><span class="p">[</span><span class="n">orig_indices</span><span class="p">])</span> <span class="o">==</span> <span class="mi">342</span>
<span class="k">print</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">corrcoef</span><span class="p">(</span><span class="n">smb</span><span class="p">[</span><span class="n">orig_indices</span><span class="p">],</span> <span class="n">hml</span><span class="p">[</span><span class="n">orig_indices</span><span class="p">]))</span>
</code></pre></div></div>
<p>This yields</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[[ 1. -0.09669641]
[-0.09669641 1. ]]
</code></pre></div></div>
<p>a coefficient of roughly \(-0.10\), not the \(-0.08\) the authors
mention, but relatively close. I guess the data has been cleaned a bit
since 1993?</p>
<p>As a further aside, accumulating this data and analyzing it was a true
feat in 1993. These days, we can do the same using the internet and
a few lines of Python (or, spoiler alert, using just a
<a href="https://www.portfoliovisualizer.com/" target="_blank">website</a>).</p>
<h4 id="back-to-modelling">Back to modelling</h4>
<p>So what are we to do with <em>SMB</em> and <em>HML</em>? You guessed it – just add
them to the regression model. Of course, this makes the subspace we
project on larger, which will always decrease the “fraction of
variance unexplained”, without necessarily explaining much. However,
in the case of IJS it appears to explain a bit:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Continuing from above.
</span><span class="n">A</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">stack</span><span class="p">(</span>
<span class="p">[</span><span class="n">np</span><span class="p">.</span><span class="n">ones_like</span><span class="p">(</span><span class="n">ijs_date</span><span class="p">),</span> <span class="n">mktmrf</span><span class="p">[</span><span class="n">indices</span><span class="p">],</span> <span class="n">smb</span><span class="p">[</span><span class="n">indices</span><span class="p">],</span> <span class="n">hml</span><span class="p">[</span><span class="n">indices</span><span class="p">]],</span> <span class="n">axis</span><span class="o">=</span><span class="mi">1</span>
<span class="p">)</span>
<span class="n">y</span> <span class="o">=</span> <span class="n">ijs</span><span class="p">[</span><span class="n">ijs_indices</span><span class="p">]</span> <span class="o">-</span> <span class="n">rf</span><span class="p">[</span><span class="n">indices</span><span class="p">]</span>
<span class="n">B</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">inv</span><span class="p">(</span><span class="n">A</span><span class="p">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">A</span><span class="p">)</span> <span class="o">@</span> <span class="n">A</span><span class="p">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">y</span>
<span class="n">alpha</span><span class="p">,</span> <span class="n">beta_mkt</span><span class="p">,</span> <span class="n">beta_smb</span><span class="p">,</span> <span class="n">beta_hml</span> <span class="o">=</span> <span class="n">B</span>
<span class="n">model_err</span> <span class="o">=</span> <span class="n">A</span> <span class="o">@</span> <span class="n">B</span> <span class="o">-</span> <span class="n">y</span>
<span class="n">ss_err</span> <span class="o">=</span> <span class="n">model_err</span><span class="p">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">model_err</span>
<span class="n">r2</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">-</span> <span class="n">ss_err</span><span class="p">.</span><span class="n">item</span><span class="p">()</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="n">var</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="n">ddof</span><span class="o">=</span><span class="nb">len</span><span class="p">(</span><span class="n">y</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">adjr2</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">-</span> <span class="n">ss_err</span><span class="p">.</span><span class="n">item</span><span class="p">()</span> <span class="o">/</span> <span class="p">(</span><span class="n">A</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="n">A</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="n">var</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="n">ddof</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span>
<span class="s">"FF3F: alpha=%.2f%%; beta_mkt=%.2f; beta_smb=%.2f; beta_hml=%.2f."</span>
<span class="s">" R^2=%.1f%%; R_adj^2=%.1f%%. Annualized alpha: %.2f%%"</span>
<span class="o">%</span> <span class="p">(</span>
<span class="n">alpha</span><span class="p">,</span>
<span class="n">beta_mkt</span><span class="p">,</span>
<span class="n">beta_smb</span><span class="p">,</span>
<span class="n">beta_hml</span><span class="p">,</span>
<span class="mi">100</span> <span class="o">*</span> <span class="n">r2</span><span class="p">,</span>
<span class="mi">100</span> <span class="o">*</span> <span class="n">adjr2</span><span class="p">,</span>
<span class="p">((</span><span class="mi">1</span> <span class="o">+</span> <span class="n">alpha</span> <span class="o">/</span> <span class="mi">100</span><span class="p">)</span> <span class="o">**</span> <span class="mi">12</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mi">100</span><span class="p">,</span>
<span class="p">)</span>
<span class="p">)</span>
</code></pre></div></div>
<p>This prints:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>FF3F: alpha=0.04%; beta_mkt=0.97; beta_smb=0.79; beta_hml=0.51. R^2=95.8%; R_adj^2=95.8%. Annualized alpha: 0.43%
</code></pre></div></div>
<p>In other words, we dropped from an (annualized) \(\alpha_{\rm CAPM} = 1.58\%\) to
only \(\alpha_{\rm FF3F} = 0.43\%\). The explained fraction of
variance has increased to above 95%.</p>
<p>Remembering that Jensen (1968) talked about assessing fund managers
with this model, we could try the same with actual managed
funds. While I couldn’t produce any impressive results there, French
and Fama did go into the question of <a href="http://mba.tuck.dartmouth.edu/bespeneckbo/default/AFA611-Eckbo%20web%20site/AFA611-S8C-FamaFrench-LuckvSkill-JF10.pdf" target="_blank"><em>Luck versus Skill in the
Cross-Section of Mutual Fund
Returns</em></a>
in a 2010 paper. The results, on average, don’t look good for fund
managers’ skill. The story for individual fund managers may be better,
but don’t hold your breath.</p>
<h3 id="was-this-worth-it">Was this worth it?</h3>
<p>We discussed academic outputs of Jensen, French and Fama. The latter
two even got a Nobel for
their work on factor models. But nowadays, we can do (parts) of their
computations in a few lines of Python.</p>
<p>It’s actually easier than that still. The website
portfoliovisualizer.com allows us to do <a href="https://www.portfoliovisualizer.com/factor-analysis?s=y&regressionType=1&symbols=IJS&sharedTimePeriod=true&factorDataSet=0&marketArea=0&factorModel=1&useHMLDevFactor=false&includeQualityFactor=false&includeLowBetaFactor=false&fixedIncomeFactorModel=0&__checkbox_ffmkt=true&__checkbox_ffsmb=true&__checkbox_ffsmb5=true&__checkbox_ffhml=true&__checkbox_ffmom=true&__checkbox_ffrmw=true&__checkbox_ffcma=true&__checkbox_ffstrev=true&__checkbox_ffltrev=true&__checkbox_aqrmkt=true&__checkbox_aqrsmb=true&__checkbox_aqrhml=true&__checkbox_aqrhmldev=true&__checkbox_aqrmom=true&__checkbox_aqrqmj=true&__checkbox_aqrbab=true&__checkbox_aamkt=true&__checkbox_aasmb=true&__checkbox_aahml=true&__checkbox_aamom=true&__checkbox_aaqmj=true&__checkbox_qmkt=true&__checkbox_qme=true&__checkbox_qia=true&__checkbox_qroe=true&__checkbox_qeg=true&__checkbox_trm=true&__checkbox_cdt=true&timePeriod=2&rollPeriod=12&marketAssetType=1&robustRegression=false" target="_blank">all
of</a>
<a href="https://www.portfoliovisualizer.com/factor-analysis?s=y&regressionType=1&symbols=IJS&sharedTimePeriod=true&factorDataSet=0&marketArea=0&factorModel=3&useHMLDevFactor=false&includeQualityFactor=false&includeLowBetaFactor=false&fixedIncomeFactorModel=0&__checkbox_ffmkt=true&__checkbox_ffsmb=true&__checkbox_ffsmb5=true&__checkbox_ffhml=true&__checkbox_ffmom=true&__checkbox_ffrmw=true&__checkbox_ffcma=true&__checkbox_ffstrev=true&__checkbox_ffltrev=true&__checkbox_aqrmkt=true&__checkbox_aqrsmb=true&__checkbox_aqrhml=true&__checkbox_aqrhmldev=true&__checkbox_aqrmom=true&__checkbox_aqrqmj=true&__checkbox_aqrbab=true&__checkbox_aamkt=true&__checkbox_aasmb=true&__checkbox_aahml=true&__checkbox_aamom=true&__checkbox_aaqmj=true&__checkbox_qmkt=true&__checkbox_qme=true&__checkbox_qia=true&__checkbox_qroe=true&__checkbox_qeg=true&__checkbox_trm=true&__checkbox_cdt=true&timePeriod=2&rollPeriod=12&marketAssetType=1&robustRegression=false" target="_blank">these
computations</a>
and more with a few clicks. In that sense, this blog post was perhaps
not worth it.</p>
<p>Another question is how useful these models are. This touches on <em>why</em>
<em>SMB</em> and <em>HML</em> ‘explain’ returns of portfolios (e.g., the risk
explanation vs the behavioural explanation mentioned above, or perhaps
both or neither). In
2014, Fama and French presented another updated model with five
factors, adding <em>profitability</em> and <em>investment</em>; judged by \(R^2\),
this five-factor model ‘explains’ even more of the variance of example
portfolios. Other research
suggesting alternative factors abounds.</p>
<p>How well do these models
really ‘explain’ the phenomenal historical returns of star investors
like Warren Buffett? Given that Buffett is a proponent of the <a href="https://en.wikipedia.org/wiki/Benjamin_Graham" target="_blank">Benjamin
Graham</a> school of
<em>value investing</em>, including a value factor like <em>HML</em> could perhaps
be the key to explain his success?
For the Fama & French five-factor model, we can
check
<a href="https://www.portfoliovisualizer.com/factor-analysis?s=y&regressionType=1&symbols=BRK.A&sharedTimePeriod=true&factorDataSet=0&marketArea=0&factorModel=5&useHMLDevFactor=false&includeQualityFactor=false&includeLowBetaFactor=false&fixedIncomeFactorModel=0&__checkbox_ffmkt=true&__checkbox_ffsmb=true&__checkbox_ffsmb5=true&__checkbox_ffhml=true&__checkbox_ffmom=true&__checkbox_ffrmw=true&__checkbox_ffcma=true&__checkbox_ffstrev=true&__checkbox_ffltrev=true&__checkbox_aqrmkt=true&__checkbox_aqrsmb=true&__checkbox_aqrhml=true&__checkbox_aqrhmldev=true&__checkbox_aqrmom=true&__checkbox_aqrqmj=true&__checkbox_aqrbab=true&__checkbox_aamkt=true&__checkbox_aasmb=true&__checkbox_aahml=true&__checkbox_aamom=true&__checkbox_aaqmj=true&__checkbox_qmkt=true&__checkbox_qme=true&__checkbox_qia=true&__checkbox_qroe=true&__checkbox_qeg=true&__checkbox_trm=true&__checkbox_cdt=true&timePeriod=2&rollPeriod=12&marketAssetType=1&robustRegression=false" target="_blank">portfoliovisualizer.com</a>:
With \(R^2 \approx 33\%\), and an annualized \(\alpha\) of 4.87%, the results
don’t look too good for the math nerds but very good for the ‘Oracle
of Omaha’.</p>
<p>This is obviously not a new observation. There is even a paper by a
number of people from investment firm AQR about <a href="https://www.tandfonline.com/doi/full/10.2469/faj.v74.n4.3" target="_blank"><em>Buffett’s
Alpha</em></a>
that aims to explain Buffett’s successes with leveraging as well as
yet another set of new factors in a linear regression model:</p>
<blockquote>
<p>[Buffett’s] alpha became insignificant, however, when we controlled
for exposure to the factors “betting against beta” and “quality
minus junk.”</p>
</blockquote>
<p>Nice as this may sound, it would appear more convincing to this author
if the financial analysis community could converge on a small common
set of factors instead of seemingly creating them <em>ad hoc</em>. Otherwise,
von Neumann’s line comes to mind: “With four parameters I can fit an
elephant, and with five I can make him wiggle his trunk.”</p>
<h3 id="and-now-what">And now what?</h3>
<p>We discussed two financial economics papers and the linear regression
models they propose, merely to give us a sense of what’s done in this
field. One may get a sense that this research should be useful for
more than just amusement, perhaps it could even inform our investment
choices? Many good <a href="https://www.youtube.com/watch?v=ViTnIebSzj4" target="_blank">financial
advisors</a> will make use
of data analyses
like this and suggest <em>factor-tilted</em> portfolios. However, value
investing, both with factors as well as the Buffett/Munger variety,
has trailed the overall market in the last 10–15
years. Statistically, this is to be expected to happen every now and
then, so we cannot read too much into that. But it’s <em>possible</em> the
market has just caught on, past performance is not indicative of
future results and value investing should be cancelled in 2020.
That would at least match the <em>zeitgeist</em>. However, it’s also
entirely possible it’s exactly times like the present that make value
investing hard but ultimately worthwhile and we should be greedy when
others are fearful.</p>
<p>Time will tell.</p>
<h4 id="references">References</h4>
<ul class="simplelist">
<li>Frazzini, Andrea & Kabiller, David & Pedersen, Lasse Heje.
<a href="https://www.tandfonline.com/doi/full/10.2469/faj.v74.n4.3" target="_blank"><em>Buffett’s Alpha</em></a>.
Financ. Anal. J. 74 (4), 35–55
<span class="smallcaps"><a href="https://doi.org/10.2469/faj.v74.n4.3" target="_blank">DOI:10.2469/faj.v74.n4.3</a></span>.</li>
<li>Fama, Eugene F. & French, Kenneth R.
<a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.139.5892" target="_blank"><em>Common risk factors in the returns on stocks and bonds</em></a>.
J. Financ. Econ. 33, (1), 3–56 (1993).
<span class="smallcaps"><a href="https://doi.org/10.1016/0304-405X(93)90023-5" target="_blank">DOI:10.1016/0304-405X(93)90023-5</a></span>.</li>
<li>———.
<a href="http://mba.tuck.dartmouth.edu/bespeneckbo/default/AFA611-Eckbo%20web%20site/AFA611-S8C-FamaFrench-LuckvSkill-JF10.pdf" target="_blank"><em>Luck versus skill in the cross‐section of mutual fund
returns</em></a>.
J. Financ. 65 (5), 1915–1947 (2010).
<span class="smallcaps"><a href="https://doi.org/10.1111/j.1540-6261.2010.01598.x" target="_blank">DOI:10.1111/j.1540-6261.2010.01598.x</a></span>.</li>
<li>———.
<a href="https://tevgeniou.github.io/EquityRiskFactors/bibliography/FiveFactor.pdf" target="_blank"><em>A five-factor asset pricing model</em></a>.
J. Financ. Econ. 116 (1), 1–22 (2015).
<span class="smallcaps"><a href="https://doi.org/10.1016/j.jfineco.2014.10.010" target="_blank">DOI:10.1016/j.jfineco.2014.10.010</a></span>.</li>
<li>Jensen, Michael C.
<a href="https://onlinelibrary.wiley.com/doi/full/10.1111/j.1540-6261.1968.tb00815.x" target="_blank"><em>The performance of mutual funds in the period 1945–1964</em></a>.
J. Financ. 23 (2), 389–416 (1968).
<span class="smallcaps"><a href="https://doi.org/10.1111/j.1540-6261.1968.tb00815.x" target="_blank">DOI:10.1111/j.1540-6261.1968.tb00815.x</a></span>.</li>
</ul>
Tue, 08 Sep 2020 00:00:00 +0000
https://heiner.ai/blog/2020/09/08/more-linear-regression-capm.html
https://heiner.ai/blog/2020/09/08/more-linear-regression-capm.htmlblogOn linear regression<p><small>[Edit 14 May 2020: Thanks to Marcus Waurick for pointing out \(A\)
needs to be closed for Lemmas 1 and 2 to be true in
general. Unfortunately, there seems no easy way of doing linear
regression in general Hilbert spaces (no equivalent of \(\1\),
although the idea of using weighted \(L_2\) spaces and writing a
blog post on <em>Linear Regression in Hilbert spaces with Morgenstern
norm</em> has a certain ring to it.]</small></p>
<p>Apropos of nothing, this is a post about linear regression. There’s a
whole world of information on that out there, but little with the
right point of view: The Hilbert space perspective. That might not
be universally loved, so you might feel more comfortable reading
\(\H_1 = \R^m\), \(\H_2 = \R^n\) and “matrix” in place of “linear
operator” below.</p>
<p>We’ll do the short theory up front, then look at an example, then
say something about “fraction of variance explained”. A later blog
post will discuss the CAPM, French-Fama models and efficient markets as examples.</p>
<h2 id="two-lemmas">Two lemmas.</h2>
<p>Let \(\H_1\), \(\H_2\) be Hilbert spaces and \(A\in L(\H_1,\H_2)\) be
a closed linear operator.</p>
<p><strong>Lemma 1.</strong> \(\H_2 = \im A\oplus\ker A^*\) in the sense of direct sums
of Hilbert spaces.</p>
<p><em>Proof</em> Let \(x\in\im A\), \(y\in\ker A^*\). There is a \(x_1\in\H_1\)
with \(x = Ax_1\) and</p>
\[\langle x,y\rangle = \langle Ax_1, y\rangle = \langle x_1, A^*
y\rangle = 0.\]
<p>Thus \(\im A\perp\ker A^*\).</p>
<p>Reversely let \(y\in(\im A)^\perp\). Then \(0 = \langle Ax_1,
y\rangle = \langle x_1, A^* y\rangle\) for all \(x_1\in\H_1\), and
thus \(y\in\ker A^*\). //</p>
<p><strong>Lemma 2.</strong> Let \(P\from\H_2\to\im A\) be the orthogonal
projection.</p>
<p>(a) Let \(y\in\H_2\). Then there is a \(b\in\H_1\) such that \(A^*Ab =
A^*y\) and \(Py = Ab\). This is called the <em>normal equation</em>.</p>
<p>(b) If \(\ker A = \{0\}\), i.e., \(A\) injective, then \(P =
A(A^*A)^{-1}A^*\).</p>
<p><em>Proof.</em> (a) There is \(b\in\H_2\) with \(Py = Ab\). Also \(y - Py\in(\im
A)^\perp\), and thus by Lemma 1</p>
\[0 = A^*(y -Py) = A^*(y - Ab) = A^*y - A^*Ab.\]
<p>(b) Lemma 1 implies \(\H_1 = \im A^*\oplus\ker A = \im A^*\),
i.e. \(A^*\) is surjective. Since \(\im A = (\ker A^*)^\perp\) and
evidently \(A^*\from(\ker A^*)^\perp\to\H_1\) is injective, that
mapping is bijective. Additionally
\(A\from\H_1\to\im A\) is bijective, and thus \(A^*A\from\H_1\to\H_1\)
is bijective and invertible. Using (a) it follows that \(Py = Ab =
A(A^*A)^{-1}A^*y\). //</p>
<h2 id="linear-regression-as-projection-to-subspaces">Linear regression as projection to subspaces.</h2>
<h3 id="example-warships">Example: Warships</h3>
<p>To take a <a href="https://de.wikipedia.org/wiki/Bestimmtheitsma%C3%9F#Rechenbeispiel">favorite example from German
Wikipedia</a>,
let’s discuss warships from the Second World War. Let’s say we’ve got
\(x_1\in\R^n\), a list of lengths of \(n\) warships, \(x_2\in\R^n\) a list
of their beams (widths) and \(y\in\R^n\) a list of their
drafts (distance from bottom to waterline), all in meters. We call
\(x_1\) and \(x_2\) <em>feature vectors</em> (also known as <em>explanatory</em> or
<em>independent</em> variables) and can safely assume they are
linearly independent, such that the matrix</p>
\[A = \begin{pmatrix}
| & | \\
x_1 & x_2 \\
| & |
\end{pmatrix}\in\R^{n\times 2}\]
<p>defines an injective operator. Its image is the linear span of \(x_1\)
and \(x_2\), i.e., \(\im A = \{\alpha x_1 + \beta x_2 \st \alpha,
\beta\in\R\}\subseteq\R^n\). We wouldn’t expect \(y\) to be an element
of \(\im A\), but the hope of a linear regression model trying to
predict a warship’s draft from its length and beam is that \(y\)
is not too far from \(\im A\) as a subspace of \(\R^n\)
either. Specifically, the \(\abs{\dotid}_2\)-distance is</p>
\[\dist(\{y\}, \im A) = \min_{y'\in\im A}\abs{y - y'}_2 = \abs{y - P y}_2\]
<p>where \(P\from\R^n\to\im A\) is the orthogonal projection. We can call
\(Py\) the model’s prediction, and Lemma 2 above tells us how to
compute \(P\) from \(A\), namely \(P = A(A^\top A)^{-1}A^\top\). Moreover, the
normal equation tells us which linear combination<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote">1</a></sup> of \(x_1\) and \(x_2\)
computes \(Py\):</p>
\[Py = A(A^\top A)^{-1}A^\top y = Ab \;\text{ with }\; b = (A^\top
A)^{-1}A^\top y\in\R^2.\]
<p>Thus, if we are given an additional warship’s length and beam as a
vector \(a\in\R^2\), the model’s prediction of its draft will be
\(\langle a, b\rangle\).</p>
<p>We can implement this idea in simple Python code (<a href="https://colab.research.google.com/drive/1lPXUxTBDrRC8aZ7MqZZDkvKaUz5Ogh5b" target="_blank">Colab
link</a>):</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="c1"># Lengths, beams and drafts of 10 warships
</span><span class="n">data</span> <span class="o">=</span> <span class="s">"""
187 31 9.4
242 31 9.6
262 32 8.7
216 32 9
195 32 9.7
227 31 11
193 20 5.2
175 17 5.2
"""</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
<span class="n">lengths</span><span class="p">,</span> <span class="n">beams</span><span class="p">,</span> <span class="n">drafts</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">loadtxt</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">unpack</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">A</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">stack</span><span class="p">([</span><span class="n">lengths</span><span class="p">,</span> <span class="n">beams</span><span class="p">],</span> <span class="n">axis</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="n">b</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">inv</span><span class="p">(</span><span class="n">A</span><span class="p">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">A</span><span class="p">)</span> <span class="o">@</span> <span class="n">A</span><span class="p">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">drafts</span>
<span class="k">print</span><span class="p">(</span><span class="s">"b:"</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"model prediction:"</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([</span><span class="mi">200</span><span class="p">,</span> <span class="mi">20</span><span class="p">])</span> <span class="o">@</span> <span class="n">b</span><span class="p">)</span>
</code></pre></div></div>
<p>This will print</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>b: [-0.00539494 0.34045321]
model prediction: 5.730077087608246
</code></pre></div></div>
<p>So our model would predict a hypothetical warship with length 200m
and beam 20m to have 5.73m of draft.</p>
<p>Notice that the way we built our model makes it predict a draft of
zero for the (nonsensical) inputs of a warship
of zero meters length or beam. While this seems fine enough in this
case, it’s not in others. A simple way of fixing this is to add an
“intercept” (in machine learning known as “bias”) term: Define
\(\1=(1,\ldots,1)\in\R^n\) and add that as an additional (say, first)
“feature” vector. This turns our model into an affine function of its
data inputs. Doing this in our Python example changes little:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">A</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">stack</span><span class="p">([</span><span class="n">np</span><span class="p">.</span><span class="n">ones_like</span><span class="p">(</span><span class="n">lengths</span><span class="p">),</span> <span class="n">lengths</span><span class="p">,</span> <span class="n">beams</span><span class="p">],</span> <span class="n">axis</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="n">b</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">inv</span><span class="p">(</span><span class="n">A</span><span class="p">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">A</span><span class="p">)</span> <span class="o">@</span> <span class="n">A</span><span class="p">.</span><span class="n">T</span> <span class="o">@</span> <span class="n">drafts</span>
<span class="k">print</span><span class="p">(</span><span class="s">"b:"</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"model prediction:"</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">20</span><span class="p">])</span> <span class="o">@</span> <span class="n">b</span><span class="p">)</span>
</code></pre></div></div>
<p>Result:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>b: [ 0.09353128 -0.00580401 0.34027063]
model prediction: 5.738140993529072
</code></pre></div></div>
<p>However, trying to predict crew sizes changes that, see the <a href="https://colab.research.google.com/drive/1lPXUxTBDrRC8aZ7MqZZDkvKaUz5Ogh5b" target="_blank">Colab for
details</a>.</p>
<p>Of course, we can use more than two or three feature vectors as part
of the <em>design matrix</em> \(A\), as long as they are linearly
independent, which is is typically the case in practice with enough
examples \(n\).</p>
<p>Using a matrix \(Y\in\R^{n\times m}\) in place of
\(y\in\R^n\) the same math allows us to succinctly treat the
“multivariate” case in which we’re trying to predict more than one
“dependent variable”, e.g. a warship’s draft and the size of its
crew. This is just doing more than one linear regression at once.</p>
<h3 id="r2-and-all-that">\(R^2\) and all that</h3>
<p>As mentioned above, the distance \(\abs{y - Py}_2\) gives us a sense
of the quality of our model’s predictions when applied to the data we
built it on. The textbooks, being obsessed with element-wise
expressions, call \(\abs{y - Py}_2^2\) the <em>residual sum of squares</em>.</p>
<p>While this quantity (or a normalized version of it) is a measure of
the error our model produces on the data we know, it doesn’t tell us
if it was our input data that was useful in particular. To quantify
that, we can compare it with a minimal, “inputless” model built from only
the intercept entry, i.e., using \(A_\1 = \1\). The prediction of that model
will be the mean of the data, \(\frac{1}{n}\langle y,
\1\rangle\), and the orthogonal projection on \(\im A_\1 =
\lin\{\1\}\) is \(P_1y = \frac{1}{n}\langle y, \1\rangle\1\). The
squared distance \(\abs{y - P_\1y}_2^2\) of that minimal model’s
predictions from the data is known as the <em>total sum of squares</em>. It’s
also the unnormalized variance of the data. If our original model used
an intercept term, i.e., \(\1\in\im A\), then \(Py - P_1y\in\im A\)
and therefore \(y - Py \perp Py - P_1y\). Hence, the Pythagorean
identity tells us</p>
\[\abs{y - P_1y}_2^2 = \abs{y - Py + Py - P_1y}_2^2
= \abs{y - Py}_2^2 + \abs{Py - P_1y}_2^2.\]
<p>The last term is known somewhat factitiously as the <em>explained sum of
squares</em> with the idea that it measures deviations from the mean
caused by the data.</p>
<p>The ratio \(\abs{y - Py}_2^2 / \abs{y - P_1y}_2^2\) is called the
<em>fraction of variance unexplained</em>, although one has to be careful
with that terminology.
The <em>coefficient of determination</em> is one minus that number, or</p>
\[R^2 := 1 - \frac{\abs{y - Py}_2^2}{\abs{y - P_1y}_2^2}
= \frac{\abs{Py - P_1y}_2^2}{\abs{y - P_1y}_2^2},\]
<p>where the last equality is true if and only if \(\1\in\im A\).</p>
<p><strong>Adjustments.</strong> Since including more features in our model matrix
\(A\) will make
\(\im A\) a larger subspace of \(\R^n\), the error \(\abs{y -
Py}_2^2\) will be monotonically decreasing and \(R^2\) monotonically
increasing. While this offers the
opportunity to claim to “explain” more, it might in fact make our
model’s predictions on new inputs worse. Various solutions for this
have been proposed. One somewhat principled approach is to use
“adjusted \(R^2\)”, defined as</p>
\[\bar{R}^2 = 1 - \frac{\abs{y - Py}_2^2 / (n - p - 1)}{\abs{y -
P_1y}_2^2 / (n - 1)} \le R^2,\]
<p>where \(p\) is the number of features, i.e., \(A\in\R^{n\times
(p+1)}\) if we use an intercept term. This substitutes the unbiased
sample variance and error estimators for their biased versions.</p>
<p>That’s it for now. We’ll add a proper example from finance in a future
blog post.</p>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:1" role="doc-endnote">
<p>In situations with very many feature vectors, computing the
inverse \((A^\top A)^{-1}\) may no longer be the best way of
finding \(b\). Instead, one could try to minimize \(\abs{y-Ab}_2\)
in another way, e.g. via gradient descent. This is how “linear
layers” in machine learning are trained. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
Wed, 19 Feb 2020 00:00:00 +0000
https://heiner.ai/blog/2020/02/19/linear-regression.html
https://heiner.ai/blog/2020/02/19/linear-regression.htmlblogAnnuity loans<p>I’m fond of small mental calculation helpers like the <a href="https://en.wikipedia.org/wiki/Rule_of_72">rule of
72</a>. Not that I am good at
mental math (<a href="https://play.google.com/store/apps/details?id=org.kuettler.mathapp">I once tried to fix that and got
sidetracked</a>),
but I am good at spending time contemplating how I’d do it if I was
better at it.</p>
<p>Another thing I’m not good at is finance. Lack of capital usually
saves me from the worst mistakes, but despite the <a href="https://www.youtube.com/watch?v=Uwl3-jBNEd4">brilliant advice
from Ben Felix</a>, I sometimes
contemplate spending money on real estate. Real estate tends to be
financed with a morgage, which often is a type of annuity loan. What
is an annuity loan and is there a neat rule of thumb for it? Read on
to find out.</p>
<h2 id="whats-an-annuity-loan">What’s an annuity loan?</h2>
<p>We receive a loan of size \(S_0\) and pay it back. Each period we’ll
pay the same amount</p>
\[R = T_k + Z_k\]
<p>with a principal repayment \(T_k\) and an interest payment \(Z_k\) for
the \(k\)th payment out of \(n\) total payments.</p>
<p>The interest payment is going to be a fixed percentage of the
outstanding principal balance and thus \(Z_1 = pS_0,\) where we set
e.g. \(p=0.02\) for a 2% interest rate.</p>
<h2 id="so-we-always-pay-the-same-amount-how-much">So we always pay the same amount. How much?</h2>
<p>Let’s consider an interest rate of \(p\) and \(n\) periods with one
payment per period. We note that the payment</p>
\[R = T_1 + pS_0 = T_2 + p(S_0 - T_1),\]
<p>since \(S_0 - T_1\) is the outstanding balance after the first
payment. Hence \(T_2 = (1 + p)T_1\). After \(k\) and \(k+1\) periods</p>
\[R = T_k + p\Bigl(S_0 - \sum_{j=1}^{k-1} T_j\Bigr)
= T_{k+1} + p\Bigl(S_0 - \sum_{j=1}^k T_j\Bigr),\]
<p>hence \(T_{k+1} = (1+p)T_k\) and</p>
\[T_k = (1 + p)^{k-1}T_1.\]
<p>To impose another condition, let’s say we want to fully pay back the
loan after \(n\) periods, i.e.,</p>
\[S_0 = \sum_{j=1}^{n} T_k = T_1 \sum_{j=1}^{n}(1+p)^{k-1} =
T_1\frac{(1+p)^n - 1}{p},\]
<p>where, as so often, we made use of the sequence of partial sums
\(\sum_{k=0}^{n} q^k = \frac{q^{n+1}-1}{q-1}\) of the geometric
series. Thus we find</p>
\[R = T_1 + Z_1 = pS_0\frac{1}{(1+p)^n - 1} + pS_0
= pS_0\frac{(1+p)^n}{(1+p)^n - 1}\]
<p>The regular annuity payment \(R\) is therefore a constant factor of
the loaned amount \(S_0\), the <em>annuity factor</em></p>
\[\af(p, n) = p\frac{(1+p)^n}{(1+p)^n - 1}.\]
<p>Not quite incidentelly, the annuity factor also shows up in formulas
for computing the equivalent annual cost from the net present
value. We won’t go into that here.</p>
<p>Note that the condition to fully pay back \(S_0\) does not in practice
constrain us very much – if less is paid back, say \(S_1\), we would
do the calculation with \(S_1\) in place of \(S_0\) and add a regular
interest payment of \(p(S_0 - S_1)\).</p>
<h2 id="months-and-years">Months and years</h2>
<p>Typically we’ll make a monthly payment over many years. This is where
some treatments get confusing and also where banks make a bit of an
extra buck. For \(n\) years and \(p\) interest per year, for our
purposes we’ll just take \(12n\) periods and a monthly interest of
\(\sqrt[12]{1 + p} - 1 = \frac{p}{12} + O(p^2)\). For small \(p\),
e.g. not more than 10%, this is a good approximation. The monthly
payment is then</p>
\[\frac{p}{12}\frac{(1 + p/12)^{12n}}{(1 + p/12)^{12n} - 1}S_0.\]
<h2 id="taylored-for-mental-arithmetic">Taylored for mental arithmetic</h2>
<p>We started this looking for a simple approximation we can use for
mental arithmetic, like the rule of 72 (it takes \(72/x\) periods for an
investment to double in value if it appreciates \(x\)% per
period). The above isn’t that. The binomial theorem helps:</p>
\[\Bigl(1 + \frac{p}{12}\Bigr)^{12n}
= \sum_{k=0}^{12n} \binom{12n}{k} \Bigl(\frac{p}{12}\Bigr)^k
= 1 + np + \binom{12n}{2}\Bigl(\frac{p}{12}\Bigr)^2 + O(p^3).\]
<p>If we want to forget about the \(p^2\) term as well we end up at</p>
\[\af(p/12, 12n) \approx \frac{p}{12}\frac{1 + np}{np} = \frac{1 +
np}{12n},\]
<p>which is nice. But not great. A short calculation with the binomial
coefficient \(\binom{12n}{2}\) yields</p>
\[\binom{12n}{2}\Bigl(\frac{p}{12}\Bigr)^2
= \frac{(np)^2}{2} - \frac{np^2}{24}.\]
<p>For typical \(n\) and \(p\) (e.g., \(n = 20\) and \(p = 0.02\)) the
second term won’t play any role. With the first term we improve our
approximation to</p>
\[\af(p/12, 12n)
\approx \frac{p}{12}\frac{1 + np + (np)^2/2}{np + (np)^2/2}
= \frac{1}{12n}\frac{1 + np(1 + np/2)}{1 + np/2}
= \frac{1}{12n}\Bigl(\frac{1}{1 + np/2} + np\Bigr).\]
<p>Now, this is clearly unsuitable. But using the geometric series again
we see that \(\frac{1}{1 + np/2} = 1 - np/2 + (np/2)^2 + O(p^3)\) and
hence</p>
\[\af(p/12, 12n) \approx \frac{1 + \frac{np}{2}(1 +
\frac{np}{2})}{12n}.\]
<p>This, too, is not too convienient. But if we drop the \((np)^2\) term
we end up with</p>
\[\af(p/12, 12n) \approx \frac{1 + np/2}{12n}.\]
<p>This isn’t too bad. For slightly larger \(n\) and \(p\) we could also
have taken \(1 + \frac{np}{2} = 1.2\), which would give us \(0.6\)
instead of \(1/2\) in the above formula. Of course we can also do the
division by 12 and arrive at another formula.</p>
<p>Let’s look at this from a slightly different perspective. A naive,
“interest-free” calculation on what the monthly payment for an \(n\)
year loan of \(S_0\) is would be \(\frac{S_0}{12n}.\)</p>
<p>Our formula \(\af(p/12, 12n) \approx \frac{1 + np/2}{12n}\) says: <strong>Do
the naive thing, then add x% to the result, where x is “\(n\) times
the interest rate over 2”.</strong></p>
<h2 id="example">Example</h2>
<p>A loan of $400000 with 2% interest over 20 years:</p>
\[\frac{\$400000}{12\cdot 20} \ \cdot\ \frac{20\cdot 2}{2}\%
= \$1666 \ \cdot\ 20\% = \$333,\]
<p>so the monthly rate will be \(\$1666 + \$333 = \$2000\). This isn’t
too far from the exact value of \(\af(\sqrt[12]{1.02} - 1, 12n) \cdot
\$400000 = \$2020\).</p>
<h2 id="more-numbers">More numbers</h2>
<p>The following table compares exact monthly rates as a percentage of
the total loan with our estimate, i.e., the true annuity factor
\(\af(\sqrt[12]{1 + p} - 1, 12n)\) and our approximation
\(\frac{1 + np/2}{12}\) of it (<strong>bold</strong>).</p>
<table>
<thead>
<tr>
<th style="text-align: right"> </th>
<th style="text-align: right"> \(n = 2\)</th>
<th style="text-align: right"> \(n = 5\)</th>
<th style="text-align: right"> \(n = 7\)</th>
<th style="text-align: right"> \(n = 10\)</th>
<th style="text-align: right"> \(n = 15\)</th>
<th style="text-align: right"> \(n = 20\)</th>
<th style="text-align: right"> \(n = 25\)</th>
<th style="text-align: right"> \(n = 30\)</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: right">\(p = 0.5\%\)</td>
<td style="text-align: right">\(4.188\%\)<br />\(\bf 4.188\%\)</td>
<td style="text-align: right">\(1.688\%\)<br />\(\bf 1.688\%\)</td>
<td style="text-align: right">\(1.212\%\)<br />\(\bf 1.211\%\)</td>
<td style="text-align: right">\(0.854\%\)<br />\(\bf 0.854\%\)</td>
<td style="text-align: right">\(0.577\%\)<br />\(\bf 0.576\%\)</td>
<td style="text-align: right">\(0.438\%\)<br />\(\bf 0.438\%\)</td>
<td style="text-align: right">\(0.355\%\)<br />\(\bf 0.354\%\)</td>
<td style="text-align: right">\(0.299\%\)<br />\(\bf 0.299\%\)</td>
</tr>
<tr>
<td style="text-align: right">\(p = 1.0\%\)</td>
<td style="text-align: right">\(4.210\%\)<br />\(\bf 4.208\%\)</td>
<td style="text-align: right">\(1.709\%\)<br />\(\bf 1.708\%\)</td>
<td style="text-align: right">\(1.233\%\)<br />\(\bf 1.232\%\)</td>
<td style="text-align: right">\(0.876\%\)<br />\(\bf 0.875\%\)</td>
<td style="text-align: right">\(0.598\%\)<br />\(\bf 0.597\%\)</td>
<td style="text-align: right">\(0.460\%\)<br />\(\bf 0.458\%\)</td>
<td style="text-align: right">\(0.377\%\)<br />\(\bf 0.375\%\)</td>
<td style="text-align: right">\(0.321\%\)<br />\(\bf 0.319\%\)</td>
</tr>
<tr>
<td style="text-align: right">\(p = 1.5\%\)</td>
<td style="text-align: right">\(4.232\%\)<br />\(\bf 4.229\%\)</td>
<td style="text-align: right">\(1.731\%\)<br />\(\bf 1.729\%\)</td>
<td style="text-align: right">\(1.254\%\)<br />\(\bf 1.253\%\)</td>
<td style="text-align: right">\(0.897\%\)<br />\(\bf 0.896\%\)</td>
<td style="text-align: right">\(0.620\%\)<br />\(\bf 0.618\%\)</td>
<td style="text-align: right">\(0.482\%\)<br />\(\bf 0.479\%\)</td>
<td style="text-align: right">\(0.399\%\)<br />\(\bf 0.396\%\)</td>
<td style="text-align: right">\(0.345\%\)<br />\(\bf 0.340\%\)</td>
</tr>
<tr>
<td style="text-align: right">\(p = 2.0\%\)</td>
<td style="text-align: right">\(4.253\%\)<br />\(\bf 4.250\%\)</td>
<td style="text-align: right">\(1.752\%\)<br />\(\bf 1.750\%\)</td>
<td style="text-align: right">\(1.276\%\)<br />\(\bf 1.274\%\)</td>
<td style="text-align: right">\(0.919\%\)<br />\(\bf 0.917\%\)</td>
<td style="text-align: right">\(0.643\%\)<br />\(\bf 0.639\%\)</td>
<td style="text-align: right">\(0.505\%\)<br />\(\bf 0.500\%\)</td>
<td style="text-align: right">\(0.423\%\)<br />\(\bf 0.417\%\)</td>
<td style="text-align: right">\(0.369\%\)<br />\(\bf 0.361\%\)</td>
</tr>
<tr>
<td style="text-align: right">\(p = 3.0\%\)</td>
<td style="text-align: right">\(4.296\%\)<br />\(\bf 4.292\%\)</td>
<td style="text-align: right">\(1.795\%\)<br />\(\bf 1.792\%\)</td>
<td style="text-align: right">\(1.320\%\)<br />\(\bf 1.315\%\)</td>
<td style="text-align: right">\(0.964\%\)<br />\(\bf 0.958\%\)</td>
<td style="text-align: right">\(0.689\%\)<br />\(\bf 0.681\%\)</td>
<td style="text-align: right">\(0.553\%\)<br />\(\bf 0.542\%\)</td>
<td style="text-align: right">\(0.472\%\)<br />\(\bf 0.458\%\)</td>
<td style="text-align: right">\(0.419\%\)<br />\(\bf 0.403\%\)</td>
</tr>
<tr>
<td style="text-align: right">\(p = 5.0\%\)</td>
<td style="text-align: right">\(4.382\%\)<br />\(\bf 4.375\%\)</td>
<td style="text-align: right">\(1.882\%\)<br />\(\bf 1.875\%\)</td>
<td style="text-align: right">\(1.408\%\)<br />\(\bf 1.399\%\)</td>
<td style="text-align: right">\(1.055\%\)<br />\(\bf 1.042\%\)</td>
<td style="text-align: right">\(0.785\%\)<br />\(\bf 0.764\%\)</td>
<td style="text-align: right">\(0.654\%\)<br />\(\bf 0.625\%\)</td>
<td style="text-align: right">\(0.578\%\)<br />\(\bf 0.542\%\)</td>
<td style="text-align: right">\(0.530\%\)<br />\(\bf 0.486\%\)</td>
</tr>
<tr>
<td style="text-align: right">\(p = 7.0\%\)</td>
<td style="text-align: right">\(4.468\%\)<br />\(\bf 4.458\%\)</td>
<td style="text-align: right">\(1.970\%\)<br />\(\bf 1.958\%\)</td>
<td style="text-align: right">\(1.499\%\)<br />\(\bf 1.482\%\)</td>
<td style="text-align: right">\(1.150\%\)<br />\(\bf 1.125\%\)</td>
<td style="text-align: right">\(0.887\%\)<br />\(\bf 0.847\%\)</td>
<td style="text-align: right">\(0.762\%\)<br />\(\bf 0.708\%\)</td>
<td style="text-align: right">\(0.693\%\)<br />\(\bf 0.625\%\)</td>
<td style="text-align: right">\(0.651\%\)<br />\(\bf 0.569\%\)</td>
</tr>
<tr>
<td style="text-align: right">\(p = 10.0\%\)</td>
<td style="text-align: right">\(4.595\%\)<br />\(\bf 4.583\%\)</td>
<td style="text-align: right">\(2.104\%\)<br />\(\bf 2.083\%\)</td>
<td style="text-align: right">\(1.638\%\)<br />\(\bf 1.607\%\)</td>
<td style="text-align: right">\(1.298\%\)<br />\(\bf 1.250\%\)</td>
<td style="text-align: right">\(1.048\%\)<br />\(\bf 0.972\%\)</td>
<td style="text-align: right">\(0.937\%\)<br />\(\bf 0.833\%\)</td>
<td style="text-align: right">\(0.878\%\)<br />\(\bf 0.750\%\)</td>
<td style="text-align: right">\(0.846\%\)<br />\(\bf 0.694\%\)</td>
</tr>
<tr>
<td style="text-align: right">\(p = 20.0\%\)</td>
<td style="text-align: right">\(5.010\%\)<br />\(\bf 5.000\%\)</td>
<td style="text-align: right">\(2.560\%\)<br />\(\bf 2.500\%\)</td>
<td style="text-align: right">\(2.124\%\)<br />\(\bf 2.024\%\)</td>
<td style="text-align: right">\(1.826\%\)<br />\(\bf 1.667\%\)</td>
<td style="text-align: right">\(1.637\%\)<br />\(\bf 1.389\%\)</td>
<td style="text-align: right">\(1.572\%\)<br />\(\bf 1.250\%\)</td>
<td style="text-align: right">\(1.547\%\)<br />\(\bf 1.167\%\)</td>
<td style="text-align: right">\(1.537\%\)<br />\(\bf 1.111\%\)</td>
</tr>
</tbody>
</table>
<p>For low interests \(p\) our approximation is rather good. For larger
interests over many years it starts underestimating the true
factor. In this regime using \(0.6\) or higher in place of \(1/2\)
will yield better results.</p>
<p>This doesn’t mean you should invest in real estate though.</p>
Mon, 19 Aug 2019 23:25:06 +0000
https://heiner.ai/blog/2019/08/19/annuity-loans.html
https://heiner.ai/blog/2019/08/19/annuity-loans.htmlblogDylanchords<p>Ahh… dylanchords.com. A long time ago, when the internet was in its
puberty and I just ridded myself of »Music« as a subject in school,
you were there for me. A website in the style of the times, which
filled my youthful admiration of Dylan with an actual, achievable,
purpose: To teach myself to play the guitar (after a fashion). I
scanned those songs for the <a href="http://dylanchords.info/roadmaps.htm#fingering">evil F
chord</a> and other
cryptic nastiness (Bm7-5?!), printed out and tried to recreate one
after another (after a fashion). Soon enough I tuned
my borrowed guitar in Open D tuning and played a heartfelt
<em>Buckets of Rain</em>. I felt sad but proud, the family went from
amused to annoyed, and my guitar skills from pre-beginner to amateur.</p>
<p>The guitar, Dylan, and dylanchords.com would stay with the through
university. Printing out old-style HTML would take a detour through an
arguably more <a href="https://en.wikipedia.org/wiki/TeX">old-styled system</a>,
and that mere process helped convince a number of people that I had
sufficient interest in »culture« to be worth their time. Today,
the <a href="http://kuettler.org/seal/">resulting</a> »project« is dormant, and
made obsolete by more <a href="http://www.apple.com/iphone/">recent</a>
<a href="https://madeby.google.com/phone/">technology</a>.</p>
<p>And yet, dylanchords stayed with me. The .com domain name effectively
moved to another one for reasons that don’t seem to matter so much
now, and these days, picking up an instrument isn’t something I do
daily anymore. Or even weekly. But dylanchords still seems to
matter. Recently, even the choice of subject has <a href="https://www.nobelprize.org/nobel_prizes/literature/laureates/2016/dylan-facts.html">arguably been
vindicated</a>.</p>
<p>It being Christmas today, it feels right to thank the creator. No, not
that one. Eyolf Østrem has »tabbed« around 900 songs, with patience
and skill that others couldn’t even think of displaying, to not even
mention giving away all this work for free. <em>Thank you</em>, Eyolf
Chordmaster. We don’t always
<a href="http://oestrem.com/thingstwice/2010/06/neighbourhood-bully-indeed/">agree</a>. It
doesn’t matter. Thanks for your work. It inspired me, I’m sure it
inspired many others.</p>
<p>Merry Christmas.</p>
<p>For further convenience, I’ve started hosting a jekyll-generated,
mobile-enabled version of Eyolf’s chordwork at
<a href="http://dylaniki.org">dylaniki.org</a> (<a href="https://github.com/heiner/dylaniki/tree/gh-pages">code at
github</a>). I find it
useful for looking up songs from the phone, and maybe others feel the same.</p>
Sun, 25 Dec 2016 13:50:34 +0000
https://heiner.ai/blog/2016/12/25/dylaniki.html
https://heiner.ai/blog/2016/12/25/dylaniki.htmlblogIn every beginning there is a delusion<p>So… somewhere in the order of 15 years too late I’ve also taken up
this blogging thing. At least for a while. <a href="http://karpathy.github.io/">Karpathy’s
blog</a> and the elegance of
<a href="http://jekyllrb.com">Jekyll</a> finally convinced me.</p>
Sun, 21 Aug 2016 23:31:34 +0000
https://heiner.ai/blog/2016/08/21/in-every-beginning-there-is-a-delusion.html
https://heiner.ai/blog/2016/08/21/in-every-beginning-there-is-a-delusion.htmlblog