Skip to main content
Erschienen in:
Buchtitelbild

Open Access 2022 | OriginalPaper | Buchkapitel

6. Goodbye LogNormal Distribution

verfasst von : Moshe Arye Milevsky

Erschienen in: How to Build a Modern Tontine

Verlag: Springer International Publishing

Aktivieren Sie unsere intelligente Suche, um passende Fachinhalte oder Patente zu finden.

search-config
loading …

Abstract

The R-scripts presented and developed in the prior chapters assumed an investment return generating process that is both static and LogNormal, via the basic rnorm() function. Indeed, had this work been done in the 1970s, or perhaps the 1670s when national (versus natural) tontines were first launched, that might have been sufficient.
The R-scripts presented and developed in the prior chapters assumed an investment return generating process that is both static and LogNormal, via the basic rnorm() function. Indeed, had this work been done in the 1970s, or perhaps the 1670s when national (versus natural) tontines were first launched, that might have been sufficient. But in the early twenty-first century, being normal doesn’t cut it and mean with standard deviations aren’t enough. In this chapter I explain (i) why that assumption is problematic and (ii) how to implement more robust models of portfolio investment returns. I will begin by returning to higher moments, such as skewness and kurtosis and their important role in testing data for normality. I then examine historical returns from the stock market during the prior half century and discuss how they deviate from normality. The chapter concludes by using a technique called statistical bootstrapping to simulate modern tontine dividends as an alternative construction method for the critical portfolio return matrix PORET. Overall the pedagogical objective is to help readers answer the basic question: Does all this complexity make a difference?

6.1 Statement of the Historical Problem

As noted above, the forward-looking simulations presented in the last few chapters have been predicated on LogNormal investment returns; that is that the logarithm of one-plus investment returns is normally distributed. That was occasionally referred to as the continuously compounded investment return (CC-IR), which is taken as Normal. In R they were simulated using the command rnorm(TH,EXR,SDR), where TH was the number of years (e.g. 30 years), EXR was the mean return (e.g. 4% per year), and SDR was the standard deviation (e.g. 3% per year). That assumption, which is also labelled Gaussian or just bell curving should be familiar to readers from portfolio or option pricing theory. It states that future market investment returns can be described fully and exclusively in terms of their mean and standard deviation, a.k.a. the first two moments. Alas, bell curves are certainly convenient to work with, but they are a fiction in markets.
The facts are that historical (log) investment returns aren’t really normally distributed, especially over short horizons such as trading days, weeks and even months. Just as importantly, historical (log) investment returns aren’t independent and are somewhat serially correlated with each other. In reality they are not independent from month-to-month or year-to-year, which of course stands in contrast to generating TH independent and identically distributed (i.i.d.) random variables.
Now, this really isn’t news to anyone who has worked with historical (and especially high frequency) stock return data. Moreover, this certainly isn’t the proper place to review the voluminous scholarly literature on (i) the reasons they deviate from normality, and (ii) the many alternative non-normal models. Rather the point of this chapter is much more limited. I would like to show and explain how real-world historical (stock) returns have deviated from the normality, suggest some possible fixes and alternative simulation approach and conclude by discussing how this might impact the distribution of modern tontine dividends.

6.2 Measuring Skewness and Kurtosis

Let’s go back to basics. I’ll begin by simulating monthly (instead of annual) investment returns using the usual rnorm(.) method and display some summary statistics of those artificial returns. The plan is to compare those (artificial, laboratory grown) numbers to actual historical returns from the SP500 total return; the most widely known and quoted stock index in the world. To do this higher-moment analysis, you might want to install a new package into the R-studio environment, which computes statistical moments. Install via the command install.packages("moments").
Depending on your R studio environment, or the software version you are using and perhaps even your operating system, you might have to tinker a bit and Fig. 6.1 is an alternative way to load this up (although don’t use my directory!). You may also need to run the command library(moments) before you start your script. In the end though, once the warnings lights have stopped flashing and the proper boxes have been ticked, you should get results that look like this next script. If you get error messages for the skewness and the kurtosis command, go back and try loading the libraries again. Alternatively, you can compute those two manually (without the moment packages) based on the formulas in Chap. 2, which I’ll revisit in a moment.

                  
                    set.seed(1693)
                  
                  
                    rv<-rnorm(612,0.0085,0.044)
                  
                  
                    mean(rv)
                  
                  
                    > 0.007751903
                  
                  
                    sd(rv)
                  
                  
                    > 0.04484798
                  
                  
                    median(rv)
                  
                  
                    > 0.00664067
                  
                  
                    skewness(rv)
                  
                  
                    > 0.04799061
                  
                  
                    kurtosis(rv)
                  
                  
                    > 2.607695
                  
                
Note that I have simulated 612 monthly (log) investment returns, where the theoretical and assumed mean is 85 basis points (a.k.a. 0.85% per month) and the assumed standard deviation is 4.4% (per month). The rationale for these two very specific and rather odd numbers will become evident over the next few pages. But the first thing to notice is that if you (only) simulate 612 months, which is 51 years of returns, the sample mean can end up being different from the theoretical mean. In the above case, the sample mean was (only) 78 basis points and the sample standard deviation was closer to 4.5%. Neither of these differences should be cause for alarm, and generating this small sample with a different seed will obviously change the numbers. Just as importantly, the sample median is 66 basis points, which is 11 basis points lower than the mean, and well-within (small) sample variations.
Nevertheless, notice how the sample mean is just slightly higher than the sample median. This is a telltale sign of things to come and is related to the coefficient of skewness and kurtosis to which I would like to now direct readers attention. The formal and mathematical definition of those two variables was briefly given back in Chap. 2, but recall that for the normal distribution the coefficients should be zero (skewness) and 3 (kurtosis), respectively. In the above small sample the skewness was slightly higher than zero—consistent with a mean higher than a median—and the kurtosis was slightly lower than 3. Once again, these (small sample) results shouldn’t be alarming or indicate any violation of normality. In fact, if you rerun or generate with set.seed(1000), the sample skewness is − 0.04792736 (on the other side of zero) and the sample kurtosis is 2.904078 (getting closer to 3). That’s noise for you.
For those who are having difficulty using the built-in functions for higher moments, they can also be constructed and computed manually. The following script should replicate the skewness values:

                  
                    set.seed(1693)
                  
                  
                    rv<-rnorm(612,0.0085,0.044)
                  
                  
                    # Sample Mean
                  
                  
                    mrv<-sum(rv)/(length(rv))
                  
                  
                    # Third Cumulant Defined
                  
                  
                    m3<-sum((rv-mrv)^3)/length(rv)
                  
                  
                    # Second Cumulant Defined
                  
                  
                    m2<-(sum((rv-mrv)^2)/(length(rv)))
                  
                  
                    # Fisher’s Coefficient of Skewness
                  
                  
                    m3/m2^(3/2)
                  
                  
                    > 0.04799061
                  
                  
                    skewness(rv)
                  
                  
                    > 0.04799061
                  
                
A similar script can be used to compute and confirm the kurtosis function values, except that instead of scaling the third cumulant by the second cumulant to the power of 3∕2, the fourth cumulant is scaled by the (raw vs. sample) standard deviation to the power of four. The point of all this is to provide readers with a deeper understanding of the skewness and kurtosis values, what they represent and when they deviate too much from what is expected.

                  
                    set.seed(1693)
                  
                  
                    rv<-rnorm(612,0.0085,0.044)
                  
                  
                    # Sample Mean
                  
                  
                    mrv<-sum(rv)/(length(rv))
                  
                  
                    # Fourth Cumulant Defined
                  
                  
                    m4<-sum((rv-mrv)^4)/length(rv)
                  
                  
                    # Raw Standard Deviation Defined
                  
                  
                    sdrv<-sqrt(sum((rv-mrv)^2)/(length(rv)))
                  
                  
                    # Coefficient of Kurtosis
                  
                  
                    m4/sdrv^4
                  
                  
                    > 2.607695
                  
                  
                    kurtosis(rv)
                  
                  
                    > 2.607695
                  
                
In fact, while on this minor statistical digression I shall take this opportunity to remind readers that the sd(.) function built into R computes the sample standard deviation, not the above-noted (and christened) raw standard deviation. The difference between them will be well-known to readers from basic statistics, but I’ll re-iterate here that the sample estimate divides all sums by (N − 1) and what I called raw divides by the original N. The following script should clarify any confusion in this matter. In particular notice and pay attention to the first few digits after the decimal sign, which in both cases represents a volatility of 4.5% per month. Indeed, the differences are small (to an empiricist).

                  
                    set.seed(1693)
                  
                  
                    rv<-rnorm(612,0.0085,0.044)
                  
                  
                    # Sample Mean
                  
                  
                    mrv<-sum(rv)/(length(rv))
                  
                  
                    # Raw Standard Deviation
                  
                  
                    sqrt(sum((rv-mrv)^2)/(length(rv)))
                  
                  
                    > 0.04481132
                  
                  
                    # Sample Standard Deviation
                  
                  
                    sqrt(sum((rv-mrv)^2)/(length(rv)-1))
                  
                  
                    > 0.04484798
                  
                  
                    # As computed by R.
                  
                  
                    sd(rv)
                  
                  
                    > 0.04484798
                  
                

6.3 Continuously Compounded vs. Effective Annual

This might be a good point to digress just a bit and revisit the statistical distinction between the effective annual return as modelled and captured in the PORET[i,j] matrix, versus the continuously compounded return, which is computed via log(1+PORET[i,j]). During the last few pages and chapters, I might have sloppily used the term returns when referring to either of these two variables, even though they are technically different from each other. One is an effective annual rate (EAR), and one is a type of annual percentage rate (APR).
Recall that the basic simulation script for generating PORET[i,j] begins with a normally distributed random vector with mean EXR and standard deviation SDR, a.k.a. the volatility. The number e, or approximately 2.718, as the base raised to the power of that vector using the built-in exp(.) function. Finally, the numerical value of 1 is subtracted from that exponentiated value to convert the entire vector into an effective annual rate. My point here is that the exponentiation process will distort the higher moments that I introduced and explained in the prior paragraph, and especially the skewness. Here is a detailed numerical example that should help illuminate this insight.

                  
                    set.seed(1693)
                  
                  
                    rv0<-rnorm(100000,0.04,0.06)
                  
                  
                    rv1<-exp(rv0)-1
                  
                  
                    # Compare Means
                  
                  
                    mean(rv0)
                  
                  
                    > 0.03991409
                  
                  
                    mean(rv1)
                  
                  
                    > 0.04258999
                  
                  
                    # Compare Deviations
                  
                  
                    sd(rv0)
                  
                  
                    > 0.0599022
                  
                  
                    sd(rv1)
                  
                  
                    > 0.0624973
                  
                  
                    # Compare Skewness
                  
                  
                    skewness(rv0)
                  
                  
                    > -0.005790745
                  
                  
                    skewness(rv1)
                  
                  
                    > 0.1724074
                  
                  
                    # Compare Kurtosis
                  
                  
                    kurtosis(rv0)
                  
                  
                    > 2.9789
                  
                  
                    kurtosis(rv1)
                  
                  
                    > 3.033556
                  
                
I have generated 100,000 numbers from a normally distributed random variable with a theoretical mean of 4% and a standard deviation of 6%. Of course, the sample statistics will differ from the theoretical values, and especially after exponentiation to convert from continuously compounded to effective annual. By construction the baseline rv0 is normally distributed, but rv1 is created by exponentiating rv0 and then subtracting one.
Per the results, which of course depend on the seed, the mean of the 100,000 numbers in the continuously compounded investment return (CC-IR) vector rv0 is indeed very close to 4%, but the mean of the effective annual return vector is higher than 4%, as indeed it should be. Also, the standard deviation of the continuously compounded return is close to 6%, but for the effective annual return it’s higher than 6%, once again as it should be. More importantly, the skewness of the continuously compounded return is slightly negative but zero for two digits after the decimal point, again consistent with the symmetry (and zero theoretical skewness) of the normal distribution. But, when the rv0 vector is exponentiated to create the rv1 vector, which recall is the basis for the PORET[i,j] matrix, raising e to the power of these values, induces statistical skewness. This is important to remember. Skewness in effective annual investment returns is not a sign of abnormality. Finally, the kurtosis of the effective annual return rv1 is just slightly higher than the corresponding value for the continuously compounded return rv0, although both are quite close to the anticipated value of 3. No big change there.
The important takeaway (or reminder) is threefold. First, the effective annual investment return as captured by the PORET[i,j] matrix and the foundation for the simulation algorithm will have a small amount of skewness due to the exponentiation, even if the underlying return generating process was perfectly normal. Second, if you (blindly) compute the sample standard deviation of any PORET[i,j] matrix—regardless of how it was obtained—it will likely be just a tad higher than the standard deviation SDR used to generate the underlying returns, and what I have called volatility. Third, and just as importantly, if-and-when I happen to be sloppy and use the term expected return or standard deviation without specifying whether I’m referring to the continuously compounded rv0 or the effective annual rv1, I should apologize in advance. But, more often than not I’ll be referring to the former rv0 and not the latter rv1. Or, using the language or R, it’s the second and third argument in the rnorm(.) function. Go back to Chap. 2 for a refresher.

6.4 Quantile Plots of Investment Returns

Back to our main objective, another perspective on the normality (or lack thereof) of a particular dataset is obtained by generating and creating a simple quantile plot against the normal distribution. This process compares the number of data points within different quantile ranges or bins relative to what they should have been if they were normally distributed. This is a very well-known procedure for quickly visualizing and summarizing the distribution of the data.
Figure 6.2 displays a quantile plot of the normally distributed rv data using the qqnorm(rv) and then qqline(rv) command, which adds the diagonal line. What this picture is telling us by virtue of the points falling almost perfectly on the diagonal is that our sample (612 normal numbers generated using the 1693 seed) appears normally distributed. Ok, yes, in the lower-left corner a few data points are above the diagonal and in the upper-right corner a few points are under the diagonal, but this is consistent with the sample kurtosis value being under (the theoretical, perfect) 3. And for those readers who now worry about the accuracy of rnorm(.), if you want to convince yourself R’s random number generator is functioning properly, generate 612,000 monthly returns and run the same procedure. It might take a while to sort and plot them, but the points will all rest nicely on the diagonal and barely a dot will deviate. So, I might be a bit cavalier with confidence intervals here, but the point is to (i) develop some quick and easy intuition for detecting or not being able to detect normality and (ii) remembering that it very much depends on the sample size.

6.5 Serial Autocorrelation of Returns

Another aspect of the artificial and simulated data that I used to generate forward-looking scenarios for modern tontine dividends is that the underlying periodic investment returns have been assumed independent of each other over time. That is, a large (or small) return in one year is unlikely to follow a large (or small) return in the next year. The random draws from the investment urns are uncorrelated with each other. The best way to see the absence of correlation over time (lags) is to compute the autocorrelation value and plot them via the command acf(rv) in R.
Figure 6.3 plots the autocorrelation function over lagging periods ranging from 0 to 25 and draws a 95% confidence interval around the point estimate for this correlation value. You can extract individual (lag) values using the next script and syntax. The first number displayed is technically lag zero, that is the correlation of the investment return with itself, which is obviously a perfect one. The second number displayed is the correlation of a particular month’s return, with the prior month’s return. So, for example, a correlation value greater than zero would indicate that positive (negative) months are followed by positive (negative) months, and vice versa. A number less than zero would indicate investment (and momentum) reversals. If there is no autocorrelation at all, they should be (statistically) zero.

                  
                    acf(rv)$acf[1:5]
                  
                  
                    > 1.000000  0.029472  0.000302 -0.025429 -0.020377
                  
                
Looking at the above numbers, while the correlations for lag one and two are positive, and for lags three and four are negative, they are statistically indistinguishable from zero as per the confidence interval bands noted in Fig. 6.3. In fact what we have done is confirmed something we already knew by construction. These 612 monthly numbers were generated independently and identically distributed. Ok, let’s see what happens when we filter real world investment returns thru the lens of the above-noted functions.

6.6 The SP500 Total Return

As part of the (online) material, on my website www.​MosheMilevsky.​com I have included a CSV file that contains realized historical monthly returns for the SP500 index, including dividends from January 1970 to the end of December 2020. This time series is also known as the SP500 Total Return, to differentiate it from the Index that does not include dividends. Those 51 years of historical returns are exactly 612 months, which might help explain the origins of that rather odd number earlier in the chapter. In the next script I import those numbers into R, which is something we have not yet done in this book, and I store those numbers in a vector called SP500TR. Simple importing can be done with a menu command in the graphical R-studio environment as well. In fact, the exact syntax you must use depends on where (on your desktop) you have downloaded and stored the CSV file. You also might want to ensure there are no extraneous entries or cells in the downloaded CSV. All these minor irritants can create error messages. Also, every time you see a +  in the script below, it means that this line should be appended to the previous line.

                  
                    library(readr)
                  
                  
                    SP500TR <- read_csv("~/SP500TR.csv",
                  
                  
                    +     col_types = cols(MONTH = col_date(format = "%m/%d/%Y"),
                  
                  
                    +         RETURN = col_number()))
                  
                
Next, once you have SP500TR saved in memory, that is loaded into your environment, a simple calculation of (log one plus) mean and standard deviation should yield the following two numbers, which should further help clear up the rationale from my rather odd selection of parameters earlier in this chapter.

                  
                    mean(log(1+SP500TR$RETURN))
                  
                  
                    > 0.008501958
                  
                  
                    sd(log(1+SP500TR$RETURN))
                  
                  
                    > 0.04436831
                  
                
These are two rather important numbers. The historical average monthly (log) price return of all companies in the SP500 index, including all their dividends, has been about 85 basis points, or 0.85%. If you multiply that number by 12, which is what you should do with CC-IR numbers, then annual (log return) value is 10.2%, which is an astonishingly high rate of return that is unlikely to be repeated in the next half century. The basis for this phenomenal growth, and why prior chapters have used (much) more conservative numbers closer to 5%, is partially because of the dramatic and unprecedented decline in interest rates over the last half century. Now, my point here isn’t to argue about forward-looking investment return assumptions (are you bullish or bearish?), but rather to focus on the higher moments. Moving right along, compute the skewness and kurtosis of the 612 historical monthly returns and compare them to and against the values for the artificial returns. Remember, rv and the SP500TR share the first two (log) moments, but what about the 3rd and 4th moments?

                  
                    skewness(log(1+SP500TR$RETURN))
                  
                  
                    > -0.6962339
                  
                  
                    kurtosis(log(1+SP500TR$RETURN))
                  
                  
                    > 5.503288
                  
                
The results are rather startling. The historical (realized, actual) skewness is extremely negative at (−0.696). The kurtosis is 5.5 and also much higher than the normally required 3. Now, to be precise I should also report a confidence internal on these two numbers—which would necessitate explaining how to compute those intervals using the sampling distribution—all which would take me even farther away from modern tontines. My point here is to make one simple and very important point, historical (log one plus) returns of the widest and most quoted stock index in the world aren’t normally distributed. And, if the negative skewness and excess kurtosis don’t convince you, then perhaps the QQplot will help. For the record, here is the precise R script to create the QQplot.

                  
                    rv_history<-log(1+SP500TR$RETURN)
                  
                  
                    qqnorm(rv_history,main="QQplot: Is the SP500TR Normal?")
                  
                  
                    qqline(rv_history)
                  
                
Figure 6.4 displays the earlier explained QQplot, but using the historical monthly SP500 total returns. Readers should quickly and easily be able to discern the excess kurtosis (standardized 4th moment) as evidenced by the many data points or outliers that are under the diagonal on the left-hand side of the figure (a.k.a. fat left tails) and the somewhat smaller number of data points above the diagonal on the right-hand side. Bottom line from all of this: history isn’t normal.
So, while the prior discussion should convince you of the need to incorporate some (negative) skewness and (positive) excess kurtosis in forward-looking simulations, another issue I would like to address is serial correlation. Is there any persistence in the monthly (or annual) returns of the SPR500TR? Recall that a few pages ago I used the acf(.) command to display the autocorrelation function in R. Using the randomly simulated (612) investment returns, those serial correlation values were within the 95% confidence interval of zero—which is exactly what you would anticipate based on the underlying generating process. But what about the total monthly returns from the SP500 index over the last half century? Do they display any serial correlation? Do broad stock indices continue to go up (or down) after they have gone up (or down)? Is there (negative) momentum in monthly returns?
Interestingly enough it turns out that to a first order of approximation the original independence assumption isn’t that bad and Fig. 6.5 provides the visual evidence. In particular, if you compute acf(log(1+SP500TR$RETURN))$acf[2], which is the autocorrelation using a lag of one month, the resulting number is indeed positive with a point estimate of 0.0365. Remember, that should be interpreted as a correlation between this month and last month. But technically, one can’t reject the null hypothesis that its value is indeed zero—given that it falls within the confidence intervals noted in Fig. 6.5.
Now, I must emphasize and remind readers that this statement or modelling position, namely that “You can assume the serial correlation is zero” is rather controversial in the financial econometrics literature and is partially driven by the fact the index averages returns of (close to) 500 stocks. Individual stocks or sub-indices or portfolios that use derivatives will behave differently and goes beyond the range of this chapter. Also, if we examined daily or hourly investment returns, the correlation patterns would deviate and might not fall within the acceptable range of zero. But this is key. Remember that modern tontines are not designed for continuous time trading. Rather, the assets are assumed to be invested in simple low-risk and linear instruments. The dividends are re-calibrated yearly, or perhaps quarterly at most. So, incorporating serial correlations in our (basic) forecasting model is less of an imperative. But, to be clear, the third and fourth moments can’t be as easily ignored or dismissed.

6.7 Path Forward for Deviations from LogNormality

The natural question arises then, how does this (negative skewness, excess kurtosis) affect projected tontine dividends? The discrepancy in the higher (3rd and 4th) moments will obviously impact the statistical distribution of returns and the PORET[i,j] matrix. But how exactly? Is it economically material? The only way to actually find out is to simulate tontine values in which the first two moments—a.k.a mean and variance—remain the same, but the higher moments are modified. What I will now describe is a procedure that can be used to replace the PORET[i,j] matrix, as opposed to a completely different modern tontine simulation procedure. This will limit the surgery (in the code) and the overall work involved. There are two different ways to do this, and I will describe both. The first one is rather basic, and that is to use an external program or economic forecasting engine to create the 10,000 paths required by PORET[i,j]. From a business management point of view, this implies having someone other than the (tontine) quant who is designing the algorithm take responsibility for generating those asset return scenarios. I have nothing more to say about that first approach, other than to remind readers that PORET[i,j] should reflect an asset allocation that is suitable for the clientele investing in the modern tontine. The second approach is more organic, the historical bootstrap, and involves using a new function in R.

6.8 Basic Historical Bootstrap

I will start by explaining how to use the sample(.) command within R, which is a rather powerful tool for simulating forward-looking investment returns. The following script samples 4 numbers from the entire vector of 612 numbers (monthly returns) stored in the SP500TR$RETURN dataset. For variety, I will use another seed to generate this sample.

                  
                    set.seed(1)
                  
                  
                    sample(SP500TR$RETURN,4)
                  
                  
                    > 0.0294 -0.0601  0.0876 -0.0364
                  
                
The ubiquitous set.seed command ensures that everyone gets the same four numbers, no different than setting the seed before generating random numbers. In the above case, R selected the four numbers listed in the results. The first (random) number was a gain of 2.94% in the month, the second was a loss of 6.01% in a month, the third was a gain of 8.76%, and the final sample monthly return was a loss of 3.64%. Now, to look clever, I could have also sampled from the actual months themselves that are part of the SP500TR dataset. In this case the syntax would have been:

                  
                    set.seed(1)
                  
                  
                    sample(SP500TR$MONTH,4)
                  
                  
                    > "1980-09-30" "2012-05-31" "2009-03-31" "1994-11-30"
                  
                
Notice that (because the random seed was the same) the results were the same. Indeed, the monthly returns for the periods ending in the above four calendar dates were the same ones as listed above. Type in the following command and out pops the corresponding return:

                  
                    SP500TR$RETURN[SP500TR$MONTH=="1980-09-30"]
                  
                  
                    > 0.0294
                  
                
The next step is to use this method or command to sample a total of 30 years’ worth of investment returns from the SP500TR dataset, to then create one possible path for the tontine fund and then tontine dividends. The 30 years is 360 months, and we want a total of 10,000 such samples, so there is a bit of work that must be done before we can replace the old PORET[i,j] matrix with a new one. First, since we will be sampling 360 months (from a total of 612) we probably want to sample-with-replacement and allow for multiple picks and repetitions of a given month. Generally the arguments for sampling with (or without) replacement are rather deep and philosophical in the context of forward-looking investment returns, but once again this isn’t the venue for such debates. The key is that we must use a slightly modified version of the sample(.) command in R. Here is the next step on the path to creating the modified PORET[i,j] matrix. I will generate one possible path for the 30 years, using our original familiar 1693 seed.

                  
                    set.seed(1693)
                  
                  
                    path<-sample(SP500TR$RETURN,360,replace = TRUE)
                  
                  
                    > summary(path)
                  
                  
                     Min.      1st Qu.    Median    Mean  3rd Qu.     Max.
                  
                  
                    -0.215400 -0.017200 0.009600 0.007188 0.037675 0.110400
                  
                
Notice that is quite the large and wide range of monthly returns. The worst month was a loss of 21.5% (which can be traced to October 1987). How exactly do I know this? Well, I can reverse the query noted above and ask R for the month ending date in which that return was observed.

                  
                    SP500TR$MONTH[SP500TR$RETURN=="-0.2154"]
                  
                  
                    > "1987-10-30"
                  
                
I note this (again) so that readers appreciate how this particular simulation methodology—that is sampling from historical returns—is simply another way of picking and scrambling random months, and assuming the investment returns from those months will repeat themselves. For those who are curious, the best of the 360 selected months corresponds to the month of August 1984.

                  
                    SP500TR$MONTH[SP500TR$RETURN=="0.1104"]
                  
                  
                    > "1984-08-31"
                  
                
Before we proceed to stitching together our many single path values into a large matrix to replace PORET[i,j], it might be worthwhile to examine the statistical properties of the (log) one-plus investment return of this one path just created. The following script that computes the four moments should be familiar by now but is yet another check on your results. Confirm these numbers as well.

                  
                    mean(log(1+path))
                  
                  
                    > 0.006101569
                  
                  
                    sd(log(1+path))
                  
                  
                    > 0.04651308
                  
                  
                    skewness(log(1+path))
                  
                  
                    > -1.152608
                  
                  
                    kurtosis(log(1+path))
                  
                  
                    > 6.991457
                  
                
Notice how this particular collection of 360 values—from a Universe of 612 numbers, albeit with replacement—resulted in a lower mean return, slightly higher volatility, more negative skewness and a higher kurtosis, compared to the entire period 1970 to 2020. This is (very) non-normal, but also nothing more than random luck.

6.9 Monthly to Annual

The next step in this process—once we generate one path of 360 months—is to convert that into a path of 30 annual returns and then repeat that process again (and again) so that we create 10,000 such paths for our modern tontine simulation code. The process of converting from monthly to annual can be done in a variety of manners, but here is one possible R-script that will take you from 360 months to 30 years.

                  
                    set.seed(1693)
                  
                  
                    # Generate Vector of 360 Monthly Investment Returns.
                  
                  
                    vector1<-rnorm(360,0.01,0.05)
                  
                  
                    # Create Cumulative Investment Values.
                  
                  
                    vector2<-cumprod(1+vector1)
                  
                  
                    # Create Vector of Annual Values.
                  
                  
                    vector3<-vector2[seq(0, length(vector2), 12)]
                  
                  
                    vector3<-append(vector3,1,0)
                  
                  
                    # Extract the Annual Returns.
                  
                  
                    vector4<-vector3[-1]/vector3[-length(vector3)]-1
                  
                  
                    round(vector4,6)
                  
                  
                     [1]  0.073581  0.121747  0.411016  0.580719 -0.022159
                  
                  
                     [6] -0.053635 -0.150397  0.089884  0.254365  0.222345
                  
                  
                    [11]  0.411773 -0.183681  0.102055  0.117695  0.226608
                  
                  
                    [16]  0.319082  0.128694  0.015303  0.064975  0.399443
                  
                  
                    [21] -0.022303  0.084906  0.411599  0.035348  0.005110
                  
                  
                    [26] -0.274844  0.030719  0.176580  0.269325  0.343089
                  
                
What the (rather elaborate and cumbersome) script is doing in four stages, is generating a vector of 360 (random) monthly returns and then converting them to the 30 annual returns displayed and listed above. It does this by (first) cumulating the monthly returns to create total returns, then (second) selecting the year-end values of those total returns, and (third) extracting those values and dividing by the prior year-end values to end with an actual return. The end result is 30 pristine numbers. I will now do the exact same thing within a formal function (without all the explanations), which generates monthly samples and then converts the path into annual numbers.

                  
                    ANPATH<-function(hist_month_data,TH){
                  
                  
                    path<-sample(hist_month_data,TH*12,replace = TRUE)
                  
                  
                    path2<-cumprod(1+path)
                  
                  
                    path3<-path2[seq(0, length(path2), 12)]
                  
                  
                    path3<-append(path3,1,0)
                  
                  
                    path4<-path3[-1]/path3[-length(path3)]-1
                  
                  
                    path4}
                  
                
I’m performing two separate tricks or calculations within this ANPATH function. First, I am sampling from the historical monthly return data that is captured in the first argument of this function. In particular, since TH is measured in years, I’m sampling TH *12 months with replacement. That is the first operational line in the script. Then, once that path of monthly values has been created, the remainder of the script converts from monthly to annual, all as explained above. Here is one particular run of the ANPATH(.) function.

                  
                    set.seed(1693)
                  
                  
                    rv<-ANPATH(SP500TR$RETURN,30)
                  
                  
                    > summary(rv)
                  
                  
                        Min.  1st Qu.   Median     Mean  3rd Qu.     Max.
                  
                  
                    -0.30730 -0.01739  0.11606  0.09000  0.20254  0.42745
                  
                  
                    prod(1+rv)
                  
                  
                    > 8.994063
                  
                
Notice how for this sample, the worst total annual return (over 30 years) was a loss of 30.7%, and the best annual return was a gain of 42.7%. The (arithmetic) mean of those 30 years was 9.0%, and the inter-quartile range ranged from a loss of 1.7% to gain of 20.3%. To repeat, this was one annualized sample path for 30 years.
The final step then is to place this particular function into a loop and create the 10,000 paths to replace PORET[i,j]. Here is that final piece, of which the loop is lifted directly from the script.

                  
                    TH<-30; N<-10000
                  
                  
                    set.seed(1693)
                  
                  
                    PORET<-matrix(nrow=N,ncol=TH)
                  
                  
                    for (i in 1:N){
                  
                  
                      PORET[i,]<-ANPATH(SP500TR$RETURN,TH)
                  
                  
                      }
                  
                  
                    mean(log(1+PORET[,10]))
                  
                  
                    > 0.1018501
                  
                  
                    sd(log(1+PORET[,10]))
                  
                  
                    > 0.1528116
                  
                  
                    skewness(log(1+PORET[,10]))
                  
                  
                    > -0.2019967
                  
                  
                    kurtosis(log(1+PORET[,10]))
                  
                  
                    > 3.238949
                  
                
So, at the end of this process we have simulated 10,000 paths of 30 annual returns by bootstrapping the SP500 total return over the last half century. The resulting mean log one-plus (a.k.a. continuously compounded) investment return in year 10 was 10% per year, and the standard deviation (or realized volatility) in that year was 15% per year. Of course, the objective of this entire chapter or exercise was not those two moments, but the skewness of − 0.202 and the kurtosis of 3.24, well beyond the normal. In the end we have a new type of PORET[i,j] matrix, one that resembles the historical SP500 total return index—with negative skewness and higher kurtosis—which will be used to generate tontine fund values.

6.10 How Do Higher Moments Affect Tontine Payouts?

Regardless of how you construct and populate forward-looking investment returns—the procedure described in the last few pages, or by importing your own scenarios—the final step and objective of this chapter is to investigate the impact of that (new) matrix on the evolution and stability of modern tontine dividends. At this point in the narrative, I’ll refrain from copying and pasting the entire Monte Carlo simulation script yet again and will simply remind you to remove (or comment out) the two lines in which the PORET[i,j] matrix is defined in terms of the rnorm(.) function. Instead, replace that variable with the modified PORET numbers and then generate the modern tontine simulation code over a 30-year horizon with the usual Gompertz mortality parameters. The only remaining tricky and sticky point is to figure out what discount rate r to use. That determines the initial tontine dividends as well as the factor used to distribute cash in later years. Recall that when returns are simulated from a LogNormal distribution and the fund incurs no expenses or extra costs, the discount rate is the expected continuously compounded investment return (CC-IR).
But, when the PORET matrix is generated exogenously, we must manually compute the sample average and hope that using that as r stabilizes the dividends. For the PORET[i,j] matrix computed above, the arithmetic average was approximately 10%, which is what I’ll use for the r value in this one simulation. The expectation is that like the LogNormal case using that value of r will assure a stable tontine dividend profile.
Table 6.1 displays the results from a simulation run using the historically bootstrapped PORET[i,j] matrix, implemented in the standardized tontine dashboard. The first item to notice when compared against dashboards from prior chapters, is that the median modern tontine dividend is much higher than in previously reported simulations. The initial payout of $12,550 per year far exceeds the $7074 estimated and displayed in the dashboard of Chap. 5. The reason for this almost doubling of the dividend is driven entirely by the (much) higher discount rate of 10% versus the 4% used in Chap. 5. Now, it’s not that I have changed my mind about a suitable discount rate for setting the initial tontine payout. In fact, the number 10% is woefully inappropriate and much too high. Rather, what’s driving results and this choice of r, is that the underlying assets of the tontine fund are entirely invested in the (historical) SP500 index, which experienced a growth rate of 10% over time. I had no choice but to discount and value the embedded temporary life annuity at 10%, if I wanted stable tontine dividends when the assets are allocated to SP500TR.
Table 6.1
Tontine dividend using bootstrap SP500 total returns; set.seed(1693)
Modern Tontine (MoTo) Fund: Simulation Dashboard
Lifetime Income with Refundable Death Benefit
Statistical
DIVIDENDS: End of Year Number…
Outcome
T = 1
T = 5
T = 10
T = 20
T = 30
1 pct. (worst)
$12,550
$5,276
$3,232
$1,247
$0
25 pct.
$12,550
$9,940
$8,693
$7,179
$5,363
Median
$12,550
$12,619
$12,637
$12,475
$11,856
75 pct.
$12,550
$16,045
$18,205
$21,471
$24,650
99 pct. (best)
$12,550
$27,697
$42,803
$76,144
$143,983
St. Dev.
$0
$4,783
$8,271
$15,464
$30,633
Assumptions:
Historical SP500TR Bootstrap with: \(r\!=\!10.0\%\)
N = 10000
Gompertz: x = 65, m = 90 and b = 10.
TH=30
Investors: GL 0 = 1000 with f 0 = $100, 000.
Needless to say, it’s highly unlikely that growth rate will persist going forward into the future. More importantly, the very wide dispersion in modern tontine dividends over time in Table 6.1 is yet another reason it’s woefully inappropriate to allocate the entire funds into equity with a 15% annual volatility. More worrisome than the wide dispersion is that the worst case (1%) scenario after 30 years is no tontine dividends at all!
Again, the point isn’t to suggest or even hint that a 100% allocation to the SP500 total return would be suitable, so as to increase initial payouts. This particular assumption within the context of defined benefit pension plan contributions has been quite costly for the actuaries! Rather, the main technical objective of this chapter was to examine how the negative skewness and excess kurtosis of (real world) stock returns affects modern tontine dividends. We are halfway there. To make that an apple-to-apples comparison I must now go back to the same basic model underlying the dashboard of Chap. 5, and assume LogNormality but with an expected return of 10% and a standard deviation of 15%. Note that the LogNormal assumption forces the skewness to be close to zero and the kurtosis to be close to 3, regardless of the assumed value of first two moments. Recall though that for the historically bootstrapped PORET matrix underling Table 6.1 the skewness (of the year 10 investment return, for example) was − 0.20 and the kurtosis was 3.24.
Finally, Table 6.2 provides a dashboard summary and concludes this particular horse race. Again, the underlying PORET matrices share that same first two moments (at least approximately) but differ in their skewness and kurtosis. Can you see any differences in results between a parametric simulation (with LogNormal returns) and a non-parametric (with historical bootstrap returns)? Pay specific attention to the standard deviation of the dividends in year T = 10, as an example.
Table 6.2
Tontine dividends using moment matching LogNormal returns; set.seed(1693)
Modern Tontine (MoTo) Fund: Simulation Dashboard
Lifetime Income with Refundable Death Benefit
Statistical
DIVIDENDS: End of Year Number…
Outcome
T = 1
T = 5
T = 10
T = 20
T = 30
1 pct. (worst)
$12,550
$5,517
$3,316
$1,274
$240
25 pct.
$12,550
$9,912
$8,499
$7,037
$5,095
Median
$12,550
$12,486
$12,261
$11,960
$10,850
75 pct.
$12,550
$15,626
$17,665
$20,257
$22,485
99 pct. (best)
$12,550
$28,684
$40,990
$69,499
$129,557
St. Dev.
$0
$4,740
$7,931
$14,343
$29,199
Assumptions:
Financial: \(r\!=\!10.0\%, \nu \!=\!10.0\%, \sigma \!=\!15.0\%\)
N = 10000
Gompertz: x = 65, m = 90 and b = 10.
TH=30
Investors: GL 0 = 1000 with f 0 = $100, 000.
Alas, you would be quite correct if you concluded that the volatility or risk for the modern tontine dividends is just slightly higher—but not substantially so—when the underlying return generating process is historically bootstrapped instead of moment matched to the SP500 total return index. The median dividends are well within a few hundred dollars of each other—when comparing both dashboard tables against each other—although the 99% percentile at the long horizon appears to be a tad higher when returns are bootstrapped. In some sense, this is a manifestation of negative skewness and excess kurtosis in returns, although most of the blame for the wide range band sits squarely in the hands of mortality.

6.11 Conclusion: How Much Should We Worry?

To be very clear—and to conclude this chapter—I am not advocating that the underlying tontine fund assets be 100% allocated or linked to the SP500 total return, or any other broad-based equity index. Rather, what I have shown is that using a LogNormal model in which annual investment returns moment match history provides reasonably close results to the historically bootstrapped methodology. The unacceptably high spread or variability of the tontine dividends in later years is slightly higher in the bootstrapped case, but not enough to reject or discard the insights from and use of the LogNormal model. And, just as importantly, I’ll leave this as a concluding thought. The assumed mean and standard deviation of forward-looking investment returns will have the greatest impact—and are most critical—for setting modern tontine dividends. It’s absolutely essential to get those right, and unfortunately I don’t have that crystal ball.

6.12 Test Yourself

1.
Please generate a PORET[i,j] matrix in which 40% of the tontine fund assets are placed in a fund resembling the historical SP500 total return index, and the remaining 60% of the fund is invested in fixed income bonds that are normally distributed with a mean return of 2%, and volatility of 4%, per annum. There is no need to generate the entire modern tontine simulation, but please report the summary mean, standard deviation, skewness and kurtosis of the PORET[i,j] matrix in the tenth year of the fund.
 
2.
Create a PORET[i,j] matrix in which investment returns are based entirely on the historical SP500 total return, but the annual returns are both floored and capped. The floor and cap are located at the upper and lower 15th percentile. What this means is that 15% of the worst months are not used or experienced by the fund, in exchange for giving up or sacrificing the 15% of best months. To be very clear, your bootstrap procedure should only use 100% or all of 612 months, but replace the extreme returns with their floored and capped values. Again, there is no need to simulate tontine dividends. Rather, report the summary statistics (a.k.a. moments) of this PORET[i,j] matrix in the 10th year.
 
3.
The discussion of skewness and kurtosis has been devoted exclusively to the investment returns, but the same computation and summary statistics could be applied to the tontine dividends. Please generate the numbers underlying Tables 6.1 and 6.2 and compare the skewness and kurtosis of the modern tontine dividends in the 10th year of the fund. Note that the 10th year is rather arbitrary, but a horizon or time period must be fixed whenever the summary statistics are computed. Averaging all of the dividends or all of the returns would be mixing too many (calendar) apples and oranges.
 
4.
The previous question explored the effect that skewness and kurtosis of the PORET matrix have on the skewness and kurtosis of TONDV[,10]. This question looks at how PORET volatility affects the skewness and kurtosis of TONDV[,10]. Generate a PORET matrix where volatility is 0, and the expected annual return and discount rate are 10%. Use this returns matrix to simulate modern tontine dividends and measure the skewness and kurtosis of the dividends in the 10th year.
 
Open Access This chapter is licensed under the terms of the Creative Commons Attribution 4.0 International License (http://​creativecommons.​org/​licenses/​by/​4.​0/​), which permits use, sharing, adaptation, distribution and reproduction in any medium or format, as long as you give appropriate credit to the original author(s) and the source, provide a link to the Creative Commons license and indicate if changes were made.
The images or other third party material in this chapter are included in the chapter's Creative Commons license, unless indicated otherwise in a credit line to the material. If material is not included in the chapter's Creative Commons license and your intended use is not permitted by statutory regulation or exceeds the permitted use, you will need to obtain permission directly from the copyright holder.
Metadaten
Titel
Goodbye LogNormal Distribution
verfasst von
Moshe Arye Milevsky
Copyright-Jahr
2022
DOI
https://doi.org/10.1007/978-3-031-00928-0_6