Perform a sliding-window analysis on S&P 500 daily-return data

library(dplyr)
library(lubridate)
library(FinCal)
library(sp500SlidingWindow)

max_annual_investment <- 3350

annual_fee        <- 0.0125

window_width      <- 30

life_expectancy   <- 70

# how much of the lifetime medical expenses will insurance cover?
insurance_share   <- 0.70

img_path          <- "~/Dropbox/GrandPere/HSA calculations/doc/images/"
#img_path          <- "~/Dropbox/GrandPere/HSA calculations/doc/tmp/"

Medical Expense Distribution year-by-year

# total lifetime medical expenses
total_lifetime_medical_expenses <- 316579
total_lifetime_medical_expenses <- 317000 # round up

# average medical expense per year of life
average_annual_medical_costs <- round(total_lifetime_medical_expenses / life_expectancy, 0)

# distribution of expenses from age 30 to age 60
medical_costs_age30 <- round(average_annual_medical_costs * 0.70, 0)
medical_costs_age60 <- round(average_annual_medical_costs * 2.00, 0)

medical_expense_distribution <- round(seq(from = medical_costs_age30,
                                          to   = medical_costs_age60,
                                          length.out = 30), 0)

# distribution of annual medical expenses during investing years
post_insurance_medical_expense <- round(medical_expense_distribution * 
                                            (1 - insurance_share), 
                                        0)

fmt(post_insurance_medical_expense)
#>  [1] "  951" "1,012" "1,073" "1,134" "1,195" "1,256" "1,316" "1,377"
#>  [9] "1,438" "1,499" "1,560" "1,621" "1,682" "1,743" "1,804" "1,865"
#> [17] "1,926" "1,987" "2,048" "2,108" "2,169" "2,230" "2,291" "2,352"
#> [25] "2,413" "2,474" "2,535" "2,596" "2,657" "2,717"

Investment Amount Distribution year-by-year

# a flat line with one inflection point
investment_amount_distribution <- c(seq(from = max_annual_investment*0.30,
                                        to   = max_annual_investment*1.00,
                                        length.out = 15),
                                    rep(length.out = 15, x = max_annual_investment))
# this produces a smoothly-increasing, concave-downward curve
# see http://math.stackexchange.com/questions/316481/
#            formula-for-an-upwards-sloping-convex-curve-with-known-endpoints
# ===========================================================================

x0 <- 30
x1 <- x0 + window_width - 1  # age at the end of the window

y0 <- max_annual_investment * 0.35   # initial investment amount
y1 <- max_annual_investment * 1.00   # final investment amount

hs <- seq(from=0.5*(y0+y1), to=y1, length.out=5)  # a free parameter ranging as shown

h <- hs[5]  # smallest is least curvature, largest the most curvature

xvec <- seq(from=x0, to=x1)

investment_amount_distribution <- sapply(xvec, function(x) {
   num <- y0*(x1 - x)**2 + 2*(x1 - x)*(x - x0)*h + y1*(x - x0)**2
   dem <- (x1 - x0)**2
   return(num / dem)
})

fmt(investment_amount_distribution)
#>  [1] "1,172" "1,320" "1,462" "1,600" "1,732" "1,859" "1,980" "2,097"
#>  [9] "2,208" "2,314" "2,415" "2,511" "2,602" "2,687" "2,767" "2,843"
#> [17] "2,912" "2,977" "3,037" "3,091" "3,140" "3,184" "3,223" "3,257"
#> [25] "3,285" "3,309" "3,327" "3,340" "3,347" "3,350"

Net Investment by year

fmt(investment_amount_distribution - post_insurance_medical_expense)
#>  [1] "222" "308" "389" "466" "537" "603" "664" "720" "770" "815" "855"
#> [12] "890" "920" "944" "963" "978" "986" "990" "989" "983" "971" "954"
#> [23] "932" "905" "872" "835" "792" "744" "690" "633"

Sliding-Window Investment Analysis

This function is part of the ‘sp500SlidingWindow’ package written by the author.
It’s under development and has not yet been exported to GitHub or CRAN.

All the graphs and statistics in the report were generated by this package
which is a general-purpose package for such sliding-window investment analyses

window_df <- sp500SlidingWindow(investment_amount_distribution,
                                post_insurance_medical_expense, 
                                window_width = window_width,
                                annual_fee   = annual_fee,
                                output_path  = img_path)

‘sp500SlidingWindow’ uses some functions in another of my personal R packages which can be found on GitHub

To install a complete working set of functions,

1. Download the source for 'sp500SlidingWindow' from   
https://www.dropbox.com/s/l7twrg7lipt87az/sp500SlidingWindow_0.1.0.tar.gz?dl=0

2. Make sure you have the latest version of R installed

3. Issue these four commands in R, in order
    * install.packages("devtools")
    * install.packages(c("dplyr", "FinCal", "gdata", "jrvFinance", "lubridate", "pbivnorm", "magrittr", "RCurl", "rvest", "tidyr", "XML", "xml2", "xts", "YieldCurve"))
    * devtools::install_github("grfiv/ustreasuries")
    * install.packages("sp500SlidingWindow_0.1.0.tar.gz", repos=NULL, type="source")  
    

Please contact the author about any issues george at georgefisher dot com

Environment

devtools::session_info()
#> Session info --------------------------------------------------------------
#>  setting  value                       
#>  version  R version 3.3.0 (2016-05-03)
#>  system   x86_64, linux-gnu           
#>  ui       X11                         
#>  language en_US                       
#>  collate  en_US.UTF-8                 
#>  tz       posixrules                  
#>  date     2016-05-05
#> Packages ------------------------------------------------------------------
#>  package            * version  date       source        
#>  assertthat           0.1      2013-12-06 CRAN (R 3.3.0)
#>  bitops               1.0-6    2013-08-17 CRAN (R 3.3.0)
#>  colorspace           1.2-6    2015-03-11 CRAN (R 3.3.0)
#>  DBI                  0.4      2016-05-02 CRAN (R 3.3.0)
#>  devtools             1.11.1   2016-04-21 CRAN (R 3.3.0)
#>  digest               0.6.9    2016-01-08 CRAN (R 3.3.0)
#>  dplyr              * 0.4.3    2015-09-01 CRAN (R 3.3.0)
#>  evaluate             0.9      2016-04-29 CRAN (R 3.3.0)
#>  FinCal             * 0.6.2    2015-12-30 CRAN (R 3.3.0)
#>  formatR              1.3      2016-03-05 CRAN (R 3.3.0)
#>  ggplot2              2.1.0    2016-03-01 CRAN (R 3.3.0)
#>  gtable               0.2.0    2016-02-26 CRAN (R 3.3.0)
#>  htmltools            0.3.5    2016-03-21 CRAN (R 3.3.0)
#>  knitr                1.12.3   2016-01-22 CRAN (R 3.3.0)
#>  lattice              0.20-33  2015-07-14 CRAN (R 3.2.1)
#>  lazyeval             0.1.10   2015-01-02 CRAN (R 3.3.0)
#>  lubridate          * 1.5.6    2016-04-06 CRAN (R 3.3.0)
#>  magrittr           * 1.5      2014-11-22 CRAN (R 3.3.0)
#>  memoise              1.0.0    2016-01-29 CRAN (R 3.3.0)
#>  munsell              0.4.3    2016-02-13 CRAN (R 3.3.0)
#>  plyr                 1.8.3    2015-06-12 CRAN (R 3.3.0)
#>  R6                   2.1.2    2016-01-26 CRAN (R 3.3.0)
#>  Rcpp                 0.12.4   2016-03-26 CRAN (R 3.3.0)
#>  RCurl                1.95-4.8 2016-03-01 CRAN (R 3.3.0)
#>  reshape2             1.4.1    2014-12-06 CRAN (R 3.3.0)
#>  rmarkdown            0.9.6    2016-05-01 CRAN (R 3.3.0)
#>  scales               0.4.0    2016-02-26 CRAN (R 3.3.0)
#>  sp500SlidingWindow * 0.1.0    2016-05-05 local         
#>  stringi              1.0-1    2015-10-22 CRAN (R 3.3.0)
#>  stringr              1.0.0    2015-04-30 CRAN (R 3.3.0)
#>  ustreasuries         1.0.0    2016-05-04 local         
#>  withr                1.0.1    2016-02-04 CRAN (R 3.3.0)
#>  xts                  0.9-7    2014-01-02 CRAN (R 3.3.0)
#>  yaml                 2.1.13   2014-06-12 CRAN (R 3.3.0)
#>  YieldCurve           4.1      2013-01-30 CRAN (R 3.3.0)
#>  zoo                  1.7-13   2016-05-03 CRAN (R 3.3.0)