Happy 2018 and welcome to our first reproducible finance post of the year! What better way to ring in a new beginning than pondering/calculating/visualizing returns distributions.
We ended 2017 by tackling skewness, and we will begin 2018 by tackling kurtosis.
Kurtosis is a measure of the degree to which portfolio returns appear in the tails of our distribution. A normal distribution has a kurtosis of 3, which follows from the fact that a normal distribution does have some of its mass in its tails. A distribution with a kurtosis greater than 3 has more returns out in its tails than the normal, and one with kurtosis less than 3 has fewer returns in its tails than the normal. That matters to investors because more bad returns out in tails means that our portfolio might be at risk of a rare but huge downside. The terminology is a bit confusing. Negative kurtosis is considered less risky because it has fewer returns out in the tails. Negative == less risky? We’re not used to that in finance.
Kurtosis is often has the word ‘excess’ appended to its description, as in ‘negative excess kurtosis’ or ‘positive excess kurtosis’. That ‘excess’ is in comparison to a normal distribution kurtosis of 3. A distribution with negative excess kurtosis equal to -1 has an actual kurtosis of 2.
Enough with the faux investopedia entry, let’s get to the calculations, R code and visualizations.
Here’s the equation for excess kurtosis. Note that we subtract 3 at the end:
\[Kurtosis=\sum_{t=1}^n (x_i-\overline{x})^4/n \bigg/ (\sum_{t=1}^n (x_i-\overline{x})^2/n)^{2}-3 \]
By way of reminder, we will be working with our usual portfolio consisting of:
+ SPY (S&amp;P500 fund) weighted 25%
+ EFA (a non-US equities fund) weighted 25%
+ IJS (a small-cap value fund) weighted 20%
+ EEM (an emerging-mkts fund) weighted 20%
+ AGG (a bond fund) weighted 10%
Before we can calculate kurtosis, we need to find portfolio monthly returns, which was covered in this post.
Building off that previous work, we will be working with two objects of portfolio returns:
+ portfolio_returns_xts_rebalanced_monthly (an xts of monthly returns)
+ portfolio_returns_tq_rebalanced_monthly (a tibble of monthly returns)
Now we are going to test our past self’s work on skewness, and reuse that code flow to expedite the kurtosis work. The logic will remain the same, but we will call different built-in functions and different by-hand calculations.
For the xts world, we use the kurtosis() function instead of the skewness() function.
kurt_xts % select(kurt_builtin, kurt_byhand)
Let’s confirm that we have consistent calculations.
kurt_xts
## [1] 0.5267736
kurt_tidy$kurt_builtin
## [1] 0.5267736
kurt_tidy$kurt_byhand
## [1] 0.5267736
We have consistent results from xts and the tidy built-in/by-hand worlds, and we were able to reuse our code from above to shorten the development time here. dd
Let’s do the same with the visualizations and head straight for a density plot, starting with the same portfolio_density_plot.
portfolio_density_plot % ggplot(aes(x = returns)) +
stat_density(geom = &quot;line&quot;, alpha = 1, colour = &quot;cornflowerblue&quot;)
portfolio_density_plot
We are interested in both tails for kurtosis, so let’s shade at 2 standard deviations above and below the mean return (for our skewness work, we only shaded the negative tail).
mean % rename(rolling_kurtosis = calcs) %__% ggplot(aes(x = date, y = rolling_kurtosis)) + geom_line(color = &quot;cornflowerblue&quot;) +
xlab(&quot;date&quot;) +
ylab(&quot;rolling kurtosis&quot;) + ggtitle(&quot;Rolling Kurtosis&quot;)
Interestingly, this portfolio has displayed slight positive rolling excess kurtosis for most of its life, except during the last half of 2015 through early 2016.
That’s all for today. Our work on kurtosis was made a lot more efficient by our work on skewness - so let’s thank our 2017 selves for constructing a reproducible and reusable code flow! See you next time.