[
{
"name": "£1,000 drawn at £300 a year with no growth: three full years and a £100 fourth",
"args": [
{
"minor": 100000,
"currency": "GBP"
},
{
"minor": 30000,
"currency": "GBP"
},
0,
0,
10
],
"expect": {
"fullYears": 3,
"exhausted": true,
"totalWithdrawn": {
"minor": 100000,
"currency": "GBP"
},
"closingBalance": {
"minor": 0,
"currency": "GBP"
},
"schedule": [
{
"year": 1,
"opening": {
"minor": 100000,
"currency": "GBP"
},
"withdrawal": {
"minor": 30000,
"currency": "GBP"
},
"growth": {
"minor": 0,
"currency": "GBP"
},
"closing": {
"minor": 70000,
"currency": "GBP"
}
},
{
"year": 2,
"opening": {
"minor": 70000,
"currency": "GBP"
},
"withdrawal": {
"minor": 30000,
"currency": "GBP"
},
"growth": {
"minor": 0,
"currency": "GBP"
},
"closing": {
"minor": 40000,
"currency": "GBP"
}
},
{
"year": 3,
"opening": {
"minor": 40000,
"currency": "GBP"
},
"withdrawal": {
"minor": 30000,
"currency": "GBP"
},
"growth": {
"minor": 0,
"currency": "GBP"
},
"closing": {
"minor": 10000,
"currency": "GBP"
}
},
{
"year": 4,
"opening": {
"minor": 10000,
"currency": "GBP"
},
"withdrawal": {
"minor": 10000,
"currency": "GBP"
},
"growth": {
"minor": 0,
"currency": "GBP"
},
"closing": {
"minor": 0,
"currency": "GBP"
}
}
]
}
},
{
"name": "withdrawal first, then 10% growth on what is left (not growth first)",
"args": [
{
"minor": 100000,
"currency": "GBP"
},
{
"minor": 10000,
"currency": "GBP"
},
1000,
0,
3
],
"expect": {
"fullYears": 3,
"exhausted": false,
"totalWithdrawn": {
"minor": 30000,
"currency": "GBP"
},
"closingBalance": {
"minor": 96690,
"currency": "GBP"
},
"schedule": [
{
"year": 1,
"opening": {
"minor": 100000,
"currency": "GBP"
},
"withdrawal": {
"minor": 10000,
"currency": "GBP"
},
"growth": {
"minor": 9000,
"currency": "GBP"
},
"closing": {
"minor": 99000,
"currency": "GBP"
}
},
{
"year": 2,
"opening": {
"minor": 99000,
"currency": "GBP"
},
"withdrawal": {
"minor": 10000,
"currency": "GBP"
},
"growth": {
"minor": 8900,
"currency": "GBP"
},
"closing": {
"minor": 97900,
"currency": "GBP"
}
},
{
"year": 3,
"opening": {
"minor": 97900,
"currency": "GBP"
},
"withdrawal": {
"minor": 10000,
"currency": "GBP"
},
"growth": {
"minor": 8790,
"currency": "GBP"
},
"closing": {
"minor": 96690,
"currency": "GBP"
}
}
]
}
},
{
"name": "a withdrawal equal to the growth on the remainder lasts for ever",
"args": [
{
"minor": 110000,
"currency": "GBP"
},
{
"minor": 10000,
"currency": "GBP"
},
1000,
0,
5
],
"expect": {
"fullYears": 5,
"exhausted": false,
"totalWithdrawn": {
"minor": 50000,
"currency": "GBP"
},
"closingBalance": {
"minor": 110000,
"currency": "GBP"
},
"schedule": [
{
"year": 1,
"opening": {
"minor": 110000,
"currency": "GBP"
},
"withdrawal": {
"minor": 10000,
"currency": "GBP"
},
"growth": {
"minor": 10000,
"currency": "GBP"
},
"closing": {
"minor": 110000,
"currency": "GBP"
}
},
{
"year": 2,
"opening": {
"minor": 110000,
"currency": "GBP"
},
"withdrawal": {
"minor": 10000,
"currency": "GBP"
},
"growth": {
"minor": 10000,
"currency": "GBP"
},
"closing": {
"minor": 110000,
"currency": "GBP"
}
},
{
"year": 3,
"opening": {
"minor": 110000,
"currency": "GBP"
},
"withdrawal": {
"minor": 10000,
"currency": "GBP"
},
"growth": {
"minor": 10000,
"currency": "GBP"
},
"closing": {
"minor": 110000,
"currency": "GBP"
}
},
{
"year": 4,
"opening": {
"minor": 110000,
"currency": "GBP"
},
"withdrawal": {
"minor": 10000,
"currency": "GBP"
},
"growth": {
"minor": 10000,
"currency": "GBP"
},
"closing": {
"minor": 110000,
"currency": "GBP"
}
},
{
"year": 5,
"opening": {
"minor": 110000,
"currency": "GBP"
},
"withdrawal": {
"minor": 10000,
"currency": "GBP"
},
"growth": {
"minor": 10000,
"currency": "GBP"
},
"closing": {
"minor": 110000,
"currency": "GBP"
}
}
]
}
},
{
"name": "an income rising 10% a year runs out in the fifth year",
"args": [
{
"minor": 100000,
"currency": "GBP"
},
{
"minor": 20000,
"currency": "GBP"
},
0,
1000,
10
],
"expect": {
"fullYears": 4,
"exhausted": true,
"totalWithdrawn": {
"minor": 100000,
"currency": "GBP"
},
"closingBalance": {
"minor": 0,
"currency": "GBP"
},
"schedule": [
{
"year": 1,
"opening": {
"minor": 100000,
"currency": "GBP"
},
"withdrawal": {
"minor": 20000,
"currency": "GBP"
},
"growth": {
"minor": 0,
"currency": "GBP"
},
"closing": {
"minor": 80000,
"currency": "GBP"
}
},
{
"year": 2,
"opening": {
"minor": 80000,
"currency": "GBP"
},
"withdrawal": {
"minor": 22000,
"currency": "GBP"
},
"growth": {
"minor": 0,
"currency": "GBP"
},
"closing": {
"minor": 58000,
"currency": "GBP"
}
},
{
"year": 3,
"opening": {
"minor": 58000,
"currency": "GBP"
},
"withdrawal": {
"minor": 24200,
"currency": "GBP"
},
"growth": {
"minor": 0,
"currency": "GBP"
},
"closing": {
"minor": 33800,
"currency": "GBP"
}
},
{
"year": 4,
"opening": {
"minor": 33800,
"currency": "GBP"
},
"withdrawal": {
"minor": 26620,
"currency": "GBP"
},
"growth": {
"minor": 0,
"currency": "GBP"
},
"closing": {
"minor": 7180,
"currency": "GBP"
}
},
{
"year": 5,
"opening": {
"minor": 7180,
"currency": "GBP"
},
"withdrawal": {
"minor": 7180,
"currency": "GBP"
},
"growth": {
"minor": 0,
"currency": "GBP"
},
"closing": {
"minor": 0,
"currency": "GBP"
}
}
]
}
},
{
"name": "growth is rounded to the penny every year",
"args": [
{
"minor": 10001,
"currency": "GBP"
},
{
"minor": 3333,
"currency": "GBP"
},
333,
0,
10
],
"expect": {
"fullYears": 3,
"exhausted": true,
"totalWithdrawn": {
"minor": 10352,
"currency": "GBP"
},
"closingBalance": {
"minor": 0,
"currency": "GBP"
},
"schedule": [
{
"year": 1,
"opening": {
"minor": 10001,
"currency": "GBP"
},
"withdrawal": {
"minor": 3333,
"currency": "GBP"
},
"growth": {
"minor": 222,
"currency": "GBP"
},
"closing": {
"minor": 6890,
"currency": "GBP"
}
},
{
"year": 2,
"opening": {
"minor": 6890,
"currency": "GBP"
},
"withdrawal": {
"minor": 3333,
"currency": "GBP"
},
"growth": {
"minor": 118,
"currency": "GBP"
},
"closing": {
"minor": 3675,
"currency": "GBP"
}
},
{
"year": 3,
"opening": {
"minor": 3675,
"currency": "GBP"
},
"withdrawal": {
"minor": 3333,
"currency": "GBP"
},
"growth": {
"minor": 11,
"currency": "GBP"
},
"closing": {
"minor": 353,
"currency": "GBP"
}
},
{
"year": 4,
"opening": {
"minor": 353,
"currency": "GBP"
},
"withdrawal": {
"minor": 353,
"currency": "GBP"
},
"growth": {
"minor": 0,
"currency": "GBP"
},
"closing": {
"minor": 0,
"currency": "GBP"
}
}
]
}
},
{
"name": "a pot that reaches exactly zero on a full withdrawal counts that year",
"args": [
{
"minor": 20000,
"currency": "GBP"
},
{
"minor": 10000,
"currency": "GBP"
},
0,
0,
5
],
"expect": {
"fullYears": 2,
"exhausted": true,
"totalWithdrawn": {
"minor": 20000,
"currency": "GBP"
},
"closingBalance": {
"minor": 0,
"currency": "GBP"
},
"schedule": [
{
"year": 1,
"opening": {
"minor": 20000,
"currency": "GBP"
},
"withdrawal": {
"minor": 10000,
"currency": "GBP"
},
"growth": {
"minor": 0,
"currency": "GBP"
},
"closing": {
"minor": 10000,
"currency": "GBP"
}
},
{
"year": 2,
"opening": {
"minor": 10000,
"currency": "GBP"
},
"withdrawal": {
"minor": 10000,
"currency": "GBP"
},
"growth": {
"minor": 0,
"currency": "GBP"
},
"closing": {
"minor": 0,
"currency": "GBP"
}
}
]
}
},
{
"name": "a market halving every year",
"args": [
{
"minor": 100000,
"currency": "GBP"
},
{
"minor": 10000,
"currency": "GBP"
},
-5000,
0,
10
],
"expect": {
"fullYears": 3,
"exhausted": true,
"totalWithdrawn": {
"minor": 33750,
"currency": "GBP"
},
"closingBalance": {
"minor": 0,
"currency": "GBP"
},
"schedule": [
{
"year": 1,
"opening": {
"minor": 100000,
"currency": "GBP"
},
"withdrawal": {
"minor": 10000,
"currency": "GBP"
},
"growth": {
"minor": -45000,
"currency": "GBP"
},
"closing": {
"minor": 45000,
"currency": "GBP"
}
},
{
"year": 2,
"opening": {
"minor": 45000,
"currency": "GBP"
},
"withdrawal": {
"minor": 10000,
"currency": "GBP"
},
"growth": {
"minor": -17500,
"currency": "GBP"
},
"closing": {
"minor": 17500,
"currency": "GBP"
}
},
{
"year": 3,
"opening": {
"minor": 17500,
"currency": "GBP"
},
"withdrawal": {
"minor": 10000,
"currency": "GBP"
},
"growth": {
"minor": -3750,
"currency": "GBP"
},
"closing": {
"minor": 3750,
"currency": "GBP"
}
},
{
"year": 4,
"opening": {
"minor": 3750,
"currency": "GBP"
},
"withdrawal": {
"minor": 3750,
"currency": "GBP"
},
"growth": {
"minor": 0,
"currency": "GBP"
},
"closing": {
"minor": 0,
"currency": "GBP"
}
}
]
}
},
{
"name": "one year modelled",
"args": [
{
"minor": 100000,
"currency": "GBP"
},
{
"minor": 1000,
"currency": "GBP"
},
500,
0,
1
],
"expect": {
"fullYears": 1,
"exhausted": false,
"totalWithdrawn": {
"minor": 1000,
"currency": "GBP"
},
"closingBalance": {
"minor": 103950,
"currency": "GBP"
},
"schedule": [
{
"year": 1,
"opening": {
"minor": 100000,
"currency": "GBP"
},
"withdrawal": {
"minor": 1000,
"currency": "GBP"
},
"growth": {
"minor": 4950,
"currency": "GBP"
},
"closing": {
"minor": 103950,
"currency": "GBP"
}
}
]
}
},
{
"name": "an empty pot pays nothing and is exhausted at once",
"args": [
{
"minor": 0,
"currency": "GBP"
},
{
"minor": 1000,
"currency": "GBP"
},
500,
0,
5
],
"expect": {
"fullYears": 0,
"exhausted": true,
"totalWithdrawn": {
"minor": 0,
"currency": "GBP"
},
"closingBalance": {
"minor": 0,
"currency": "GBP"
},
"schedule": [
{
"year": 1,
"opening": {
"minor": 0,
"currency": "GBP"
},
"withdrawal": {
"minor": 0,
"currency": "GBP"
},
"growth": {
"minor": 0,
"currency": "GBP"
},
"closing": {
"minor": 0,
"currency": "GBP"
}
}
]
}
},
{
"name": "a falling withdrawal: 50% less each year",
"args": [
{
"minor": 10000,
"currency": "GBP"
},
{
"minor": 4000,
"currency": "GBP"
},
0,
-5000,
5
],
"expect": {
"fullYears": 5,
"exhausted": false,
"totalWithdrawn": {
"minor": 7750,
"currency": "GBP"
},
"closingBalance": {
"minor": 2250,
"currency": "GBP"
},
"schedule": [
{
"year": 1,
"opening": {
"minor": 10000,
"currency": "GBP"
},
"withdrawal": {
"minor": 4000,
"currency": "GBP"
},
"growth": {
"minor": 0,
"currency": "GBP"
},
"closing": {
"minor": 6000,
"currency": "GBP"
}
},
{
"year": 2,
"opening": {
"minor": 6000,
"currency": "GBP"
},
"withdrawal": {
"minor": 2000,
"currency": "GBP"
},
"growth": {
"minor": 0,
"currency": "GBP"
},
"closing": {
"minor": 4000,
"currency": "GBP"
}
},
{
"year": 3,
"opening": {
"minor": 4000,
"currency": "GBP"
},
"withdrawal": {
"minor": 1000,
"currency": "GBP"
},
"growth": {
"minor": 0,
"currency": "GBP"
},
"closing": {
"minor": 3000,
"currency": "GBP"
}
},
{
"year": 4,
"opening": {
"minor": 3000,
"currency": "GBP"
},
"withdrawal": {
"minor": 500,
"currency": "GBP"
},
"growth": {
"minor": 0,
"currency": "GBP"
},
"closing": {
"minor": 2500,
"currency": "GBP"
}
},
{
"year": 5,
"opening": {
"minor": 2500,
"currency": "GBP"
},
"withdrawal": {
"minor": 250,
"currency": "GBP"
},
"growth": {
"minor": 0,
"currency": "GBP"
},
"closing": {
"minor": 2250,
"currency": "GBP"
}
}
]
}
},
{
"name": "a negative pot is an error",
"args": [
{
"minor": -1,
"currency": "GBP"
},
{
"minor": 1000,
"currency": "GBP"
},
0,
0,
5
],
"expectError": "pot must be whole minor units, 0 or more"
},
{
"name": "a zero withdrawal is an error",
"args": [
{
"minor": 1000,
"currency": "GBP"
},
{
"minor": 0,
"currency": "GBP"
},
0,
0,
5
],
"expectError": "annualWithdrawal must be whole minor units greater than zero"
},
{
"name": "a fractional withdrawal is an error",
"args": [
{
"minor": 1000,
"currency": "GBP"
},
{
"minor": 10.5,
"currency": "GBP"
},
0,
0,
5
],
"expectError": "annualWithdrawal must be whole minor units greater than zero"
},
{
"name": "growth below -100% is an error",
"args": [
{
"minor": 1000,
"currency": "GBP"
},
{
"minor": 100,
"currency": "GBP"
},
-10001,
0,
5
],
"expectError": "annualGrowthBasisPoints must be a whole number, -10000 or more"
},
{
"name": "an increase below -100% is an error",
"args": [
{
"minor": 1000,
"currency": "GBP"
},
{
"minor": 100,
"currency": "GBP"
},
0,
-10001,
5
],
"expectError": "withdrawalIncreaseBasisPoints must be a whole number, -10000 or more"
},
{
"name": "zero years is an error",
"args": [
{
"minor": 1000,
"currency": "GBP"
},
{
"minor": 100,
"currency": "GBP"
},
0,
0,
0
],
"expectError": "maxYears must be a whole number from 1 to 100"
},
{
"name": "101 years is an error",
"args": [
{
"minor": 1000,
"currency": "GBP"
},
{
"minor": 100,
"currency": "GBP"
},
0,
0,
101
],
"expectError": "maxYears must be a whole number from 1 to 100"
},
{
"name": "fractional years are an error",
"args": [
{
"minor": 1000,
"currency": "GBP"
},
{
"minor": 100,
"currency": "GBP"
},
0,
0,
2.5
],
"expectError": "maxYears must be a whole number from 1 to 100"
},
{
"name": "a withdrawal in another currency is an error",
"args": [
{
"minor": 1000,
"currency": "GBP"
},
{
"minor": 100,
"currency": "EUR"
},
0,
0,
5
],
"expectError": "currency mismatch: GBP and EUR"
}
]