var template = document.getElementById('template').innerHTML;
var compiled = _.template(template);
// Normal distribution with mean of 6% gain, and std dev= .13 (n=50)
function rateOfReturn() {
var distribution = gaussian(1.06, Math.pow(0.13, 2));
return distribution.ppf(Math.random()) - 1;
}
// Get data from input fields
function getValue(id) {
return document.getElementById(id).value;
}
function getInput() {
var age = getValue('age') !== '' ? parseInt(getValue('age'), 10) : 30;
var balance = getValue('balance') !== '' ? parseFloat(getValue('balance')) : 1000.00;
var contribution = getValue('contribution') !== '' ? parseFloat(getValue('contribution')) : 3000.00;
return {
"age": age,
"balance": balance,
"contribution": contribution
};
}
function displayData() {
var input = getInput();
var ages = _.filter([45, 50, 55, 60, 65], function(age) {
return age >= input.age;
});;
var simulations = runSimulations(50);
var data = ages.map(function(age) {
return {
age: age,
firstQuartile: getNetWorth(simulations, age, 25),
secondQuartile: getNetWorth(simulations, age, 50),
thirdQuartile: getNetWorth(simulations, age, 75),
averageRoR: getAverageRoR(simulations, age)
}
});
var results = compiled({ data: data });
document.querySelector('tbody').innerHTML = results;
}
function addHandlers() {
var button = document.getElementById('submit');
var ageField = document.getElementById('age');
var balanceField = document.getElementById('balance');
var contributionField = document.getElementById('contribution');
button.addEventListener('click', function(e) {
e.preventDefault();
displayData();
});
ageField.addEventListener('blur', function(e) {
displayData();
});
balanceField.addEventListener('blur', function(e) {
displayData();
});
contributionField.addEventListener('blur', function(e) {
displayData();
});
}
function simulateRetirement(age, balance, contribution) {
var initialRoR = rateOfReturn();
var data = [{
"age": age,
"balance": balance,
"contribution": contribution,
"ror": initialRoR,
"total": balance + contribution + (initialRoR * (balance + contribution))
}];
for (var i = 1; i <= (65 - age); i++) {
var nextRoR = rateOfReturn();
var nextBalance = data[i - 1].total;
var nextYear = {
"age": age + i,
"balance": nextBalance,
"contribution": contribution,
"ror": nextRoR,
"total": nextBalance + contribution + (nextRoR * (nextBalance + contribution))
};
data.push(nextYear);
}
return data;
}
function runSimulations(n) {
var n = n || 50;
var simulations = [];
var options = getInput();
for (var i = 0; i < n; i++) {
var simulation = simulateRetirement(options.age, options.balance, options.contribution);
simulations.push(simulation);
}
return simulations;
}
function dataAtAge(simulations, age) {
return simulations.map(function(simulation) {
return _.find(simulation, { age: age });
});
}
function getNetWorth(simulations, age, percent) {
var totalsAtAge = dataAtAge(simulations, age).map(function(data) {
return data.total;
})
return percentile(percent, totalsAtAge);
}
function getAverageRoR(simulations, age) {
var rorAtAge = dataAtAge(simulations, age).map(function(data) {
return data.ror;
});
return _.mean(rorAtAge);
}
displayData();
addHandlers();