# cassandra.R - a program that computes the value of certain pension # guarantee structures. # # You must fill in the blanks for a bunch of constants, which are at the # top of the file, which pertain to your country and your beliefs about # the most sensible values for these constants. # After that, when you run the program, you get a bunch of useful results. # # The program embeds a range of alternative investment strategies and # guarantee structures. If you want to make changes to those, then you # will need to delve deeper into the program. But if you merely want # numerical values that pertain to your setting, it's enough to tweak # the numerical values at the top and run. # # Ajay Shah # http://www.mayin.org/ajayshah # Version 0.1, Sat Jul 1 22:44:23 IST 2006 # --------------------------------------------------------------------------- # Assumptions # --------------------------------------------------------------------------- # A. Country characteristics # 1. starting wage, in local currency units, expressed per working day wage.range <- seq(20,200,10) # 2. Wage growth anticipated over lifetime - a mix of GDP growth and the # wage-experience profile. Expressed in percent in real terms per year. wage.growth.per.year <- 3 # 3. Your view about the riskless rate in real terms (in percent per year) real.riskless <- 2.5 # 4. Your view about the equity premium (in percentage points per year) equity.premium <- 7 # 5. Your view about the DAILY volatility of the equity index (percent) sigma.M <- 1.3 # 6. Your view about the price of an annuity deep in the future # This is expressed as the lumpsum required at retirement date # in order to buy an annuity of 1 LCU per day. annuity.price <- 3842 # 7. Post-retirement income - LCU/day - below which it is poverty poverty.income <- 46 # B. Other assumptions which are not country-specific. # From here on, you are tweaking assumptions about the program which # are generic and don't particularly refer to any one country. # Number of working days per year days.per.year <- 250 # working days only, of course # Working life (in years) workinglife.years <- 40 # Pension contribution rate (fixed for life), in percent contribution.rate <- 8.33 # How much compute resources you have to splurge :-) N.simulations <- 500 # 5000 is nice, 10000 is infinity. # --------------------------------------------------------------------------- # You shouldn't need to edit anything from here on. # --------------------------------------------------------------------------- # A function that converts a number like "15% per year" into a number # like 1.000559 - in 1+r format - for the per-day returns. annual.to.daily <- function(r) { (1 + r/100)^(1/days.per.year) } # The function simengine does the heavy lifting. It is given 3 facts: # the mean and sigma of the pension portfolio, and a `cvector' object # which is a column from the contributions matrix. # It pumps through N.simulations outcomes for the terminal pension # wealth. This generates a vector W of all the pension wealth outcomes. simengine <- function(mean, sd, cvector) { W <- as.numeric(N.simulations) for (simulation in 1:N.simulations) { r <- mean + (Z[,simulation] * sd) piece1 <- c(1, cumprod(r)) ## Not c(1, cumprod(rev(r))), as rev(r) and r are equally i.i.d. N() :) W[simulation] <- piece1 %*% cvector } W } # This function is given a long vector with N.simulations outcomes # from the risk-neutral distribution of terminal pension wealth. It # applies various kinds of guarantee structures, and reports the price # of each of 'em. facets.rn <- function(W, lastwage, sumcontributions) { ## Guarantee 1: we will top you up beyond poverty target <- poverty.wealth new <- W new[new < target] <- target g1.payoff <- sum(new-W)/N.simulations # Guarantee 2: we will top you up to 50% replacement rate target <- 0.5*lastwage*annuity.price # The 0.5 IS TWEAKABLE new <- W new[new < target] <- target g2.payoff <- sum(new-W)/N.simulations # Guarantee 3: we will top you off to sumcontributions target <- sumcontributions new <- W new[new < target] <- target g3.payoff <- sum(new-W)/N.simulations discounting <- (1+(real.riskless/100))^workinglife.years c(g1.payoff, g2.payoff, g3.payoff)/discounting } # This function is given a long vector with N.simulations outcomes # from the true distribution of terminal pension wealth. It reports useful # things about this such as quantiles, Pr(below poverty), etc. facets.true <- function(W, lastwage, sumcontributions) { pr.poverty <- sum(W