Skip to content

Instantly share code, notes, and snippets.

@bobular
Last active April 26, 2018 08:32
Show Gist options
  • Save bobular/914eed165f77a0ee54624a328deeb411 to your computer and use it in GitHub Desktop.
Save bobular/914eed165f77a0ee54624a328deeb411 to your computer and use it in GitHub Desktop.
Same model as previous v3 version but with a step change expected return in the contribution period.
#!/usr/bin/env perl
# -*- mode: cperl -*-
#
# The purpose of this little model is to figure out what kind of
# investment returns the pension fund needs to make in order to meet
# its defined benefits promises.
#
# It assumes a single employee with their own "pot" and a fixed payout
# period. I'm not suggesting euthanasia... Obviously in reality the
# longevity risk is shared by the many thousands of scheme
# members. I'm trying to keep this simple...
#
# Salary progresses through early career to a fixed level until
# retirement. A very simple career-averaged earnings approach is used
# to calculate the pension payout.
#
# This is 100% defined benefit. There is no 55k cap (as found in the
# USS scheme). No in-service death benefits are included.
#
# In v3 - an annual payrise parameter is added, and the lump sum and payout parameters
# are changed to be expressed as annual accrual fractions
#
# In this (v4) version, the expected growth can be different for the first B years. Fixed small bug in annual_increment.
#
# ./pension-model-with-USS-returns.pl 0.23 0.01 10 0.04 35000 20 60000 20 0.02 3/75 1/75 0.02 25
#
# 0.23 = C, fraction of salary contribution total (employer+employee)
# 0.01 = I, expected annual asset investment return (e.g. 1%)
# 10 = B, number of years at investment return rate I
# 0.04 = K, expected investment return after B years (e.g. 4%)
# 35000 = S, starting salary
# 20 = X, number of years working with linear annual salary increments
# 60000 = T, salary after X years of increments
# 20 = Y, number of years working at fixed salary T until retirement
# 0.02 = R, annual above-inflation payrise
# 3/75 = L, lump sum accrual rate
# 1/75 = A, annual pension accrual rate
# 0.02 = J, expected annual asset return in drawdown period*
# 25 = Z, number of years retirement
#
# (* in a large and long-running scheme with good cashflow there is no
# need to de-risk and be more prudent here, but I give the option anyway)
#
# example output shows that USS's projection of 1% return for first 10 years
# followed by 4% for the next 30 years (and then 2% return thereafter to be
# conservative)
# will require
# 15% contributions will fund current benefits:
# 1/75 accrual rate, 3/75 accrual of lump sum
#
#
# ./pension-model-with-USS-returns.pl 0.15 0.01 10 0.04 35000 20 60000 20 0 3/75 1/75 0.02 25
# Starting salary was 35000 and after 20y it was 60000
# Career averaged salary over 40 years is 53437
# Pot is 682301 after 40y contributions at 15% of salary and 1% (then 4% after 10 years) annual growth of pot
# Lump sum payout of 1.6 x career avg salary = 85500 upon retirement
# After 25y retirement paying out 53% of career-averaged salary, the pot (with 2% annual return) is 47994
#
# If you reduce the 0.15 (15% contribution rate) any lower, the pot ends
# up in negative territory
#
use strict;
use warnings;
my ($contrib, $growth1, $growth1_years, $growth2, $start_salary, $years_1, $end_salary, $years_2,
$payrise, $lump_sum_accrual, $accrual, $growth3, $years_retired) = @ARGV;
$lump_sum_accrual = eval $lump_sum_accrual;
$accrual = eval $accrual;
my $pot = 0;
my $salary = $start_salary;
my $annual_increment = ($end_salary-$start_salary)/$years_1;
my $sum_salary = 0; # for calculating career-averaged salary
my $total_years = $years_1+$years_2;
my $year = 0; # year counter used to decide between growth rates 1&2
for (1 .. $years_1) {
$year++;
$pot *= 1+($year <= $growth1_years ? $growth1 : $growth2);
$pot += $salary*$contrib;
$sum_salary += $salary;
$salary += $annual_increment;
$salary *= 1+$payrise;
$annual_increment *= 1+$payrise;
}
for (1 .. $years_2) {
# same as above but without the annual increment
$year++;
$pot *= 1+($year <= $growth1_years ? $growth1 : $growth2);
$pot += $salary*$contrib;
$sum_salary += $salary;
$salary *= 1+$payrise;
}
printf "Starting salary was %d and after %dy it was %d\n",
$start_salary, $years_1, $salary;
my $career_averaged_salary = $sum_salary/$total_years;
printf "Career averaged salary over %d years is %d\n",
$total_years, $career_averaged_salary;
printf "Pot is %d after %dy contributions at %d%% of salary and %d%% (then %d%% after %d years) annual growth of pot\n",
$pot, $total_years, $contrib*100, $growth1*100, $growth2*100, $growth1_years;
my $lump_sum = $career_averaged_salary*$total_years*$lump_sum_accrual;
$pot -= $lump_sum;
printf "Lump sum payout of %.1f x career avg salary = %d upon retirement\n",
$total_years*$lump_sum_accrual, $lump_sum;
for (1 .. $years_retired) {
$pot -= $career_averaged_salary*$total_years*$accrual;
$pot *= 1+$growth3;
}
printf "After %dy retirement paying out %d%% of career-averaged salary, the pot (with %d%% annual return) is %d\n",
$years_retired, 100*$total_years*$accrual, $growth3*100, $pot;
@bobular
Copy link
Author

bobular commented Apr 25, 2018

From Sam Marsh and http://ucu.group.shef.ac.uk/wp-content/uploads/Technical-provisions-December-2017.pdf
The expected growth rates for the current valuation are as follows:
Years 1-10: -0.53%, reducing linearly to -1.32%
Years 11-20: 2.56%, reducing linearly to 1.7%
Years 21 onwards: 1.7%

I've simplified that (because the model currently only allows a step-change between two rates of return) to

Years 1-10: -1.0% return (negative)
Years 11-40: +1.7% return
Years 41-65: +2.0% return (my figure)

This requires 23% of salary contributions to sustain:

./pension-model-with-USS-returns.pl 0.23 -0.01 10 0.017 35000 20 60000 20 0 3/75 1/75 0.02 25
Starting salary was 35000 and after 20y it was 60000
Career averaged salary over 40 years is 53437
Pot is 658270 after 40y contributions at 23% of salary and -1% (then 1% after 10 years) annual growth of pot
Lump sum payout of 1.6 x career avg salary = 85500 upon retirement
After 25y retirement paying out 53% of career-averaged salary, the pot (with 2% annual return) is 8569

@bobular
Copy link
Author

bobular commented Apr 26, 2018

Modifying the script to final salary basis (not shown, but it's trivial: replace $career_averaged_salary with $salary in last few lines) the example given above (-1% then +1.7% returns on assets) - requires 26% contributions to break even. This assumes a salary trajectory of 35k to 60k in 20 years and then flatlining after that - I call this "lecturer".

Then factor in just 1% above CPI salary growth into that and you need a whopping 32% contributions:

$ ./pension-model-final-salary.pl 0.32 -0.01 10 0.017 35000 20 60000 20 0.01 3/75 1/75 0.02 25
Starting salary was 35000 and after 20y it was 89331
Career averaged salary over 40 years is 66332
Pot is 1118311 after 40y contributions at 32% of salary and -1% (then 1% after 10 years) annual growth of pot
Lump sum payout of 1.6 x final salary = 142930 upon retirement
After 25y retirement paying out 53% of final salary, the pot (with 2% annual return) is 43654

Assuming flat asset growth of CPI+2% throughout the entire period, final salary costs around 24% contributions with no above inflation salary growth and 29% with CPI+1% pay growth.

Now let's change the salary trajectory to resemble a "professor": progression from 35k to 90k in the first 30 years and then flat for the last 10. No above-inflation. This costs 29% contributions - compare with the 24% above.

$ ./pension-model-final-salary.pl 0.29 0.02 10 0.02 35000 30 90000 10 0.0 3/75 1/75 0.02 25
Starting salary was 35000 and after 30y it was 89999
Career averaged salary over 40 years is 68687
Pot is 1130186 after 40y contributions at 28% of salary and 2% (then 2% after 10 years) annual growth of pot
Lump sum payout of 1.6 x final salary = 143999 upon retirement
After 25y retirement paying out 53% of final salary, the pot (with 2% annual return) is 49739

On a career-average basis (using the script above unmodified), these same scenarios cost: 21% (lecturer) and 22% (professor).

Final salary was unjust and expensive!

@bobular
Copy link
Author

bobular commented Apr 26, 2018

Late joiners are expensive too...

In a flat CPI+2% growth scenario (wages at CPI+0%), someone joining 10 years before retirement at 50k and progressing to 60k requires 28% contributions on career-averaged basis and 31% contributions in a final salary scheme.

Here's the career-averaged run:

$ ./pension-model-with-USS-returns.pl 0.28 0.02 10 0.02 50000 10 60000 0 0.0 3/75 1/75 0.02 25
Starting salary was 50000 and after 10y it was 60000
Career averaged salary over 10 years is 54500
Pot is 166592 after 10y contributions at 28% of salary and 2% (then 2% after 10 years) annual growth of pot
Lump sum payout of 0.4 x career avg salary = 21800 upon retirement
After 25y retirement paying out 13% of career-averaged salary, the pot (with 2% annual return) is 138

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment