Monte Carlo simulations are a way to predict the outcome of a scenario that has a significant degree of uncertainty. By running thousands of simulations, each with random variations based on your inputted volatility, the tool can model a vast range of possible investment paths. However, to keep the graph clear and easy to interpret, only ten representative trajectories are displayed—each one corresponding to a different percentile of the final investment distribution. This approach gives you a snapshot of potential outcomes, from the lower end (what you might end up with in less favorable conditions) to the higher end (the outcome if things go exceptionally well).
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/script.js b/script.js
index cd4700f..6968237 100644
--- a/script.js
+++ b/script.js
@@ -4,6 +4,24 @@ function updateSliderValue(sliderId, displayId) {
display.textContent = slider.value;
}
+function toggleMonthlyInput() {
+ var investmentType = document.getElementById('investmentType').value;
+ var monthlyInvestmentInput = document.getElementById('monthlyInvestmentInput');
+
+ // Check if the investment type is 'monthly' and show/hide the monthly investment input accordingly
+ if (investmentType === 'monthly') {
+ // Remove the 'hidden' class if it exists
+ if (monthlyInvestmentInput.classList.contains('hidden')) {
+ monthlyInvestmentInput.classList.remove('hidden');
+ }
+ } else {
+ // Add the 'hidden' class if it's not already there
+ if (!monthlyInvestmentInput.classList.contains('hidden')) {
+ monthlyInvestmentInput.classList.add('hidden');
+ }
+ }
+}
+
function getColorForPercentile(percentile) {
// Red to yellow gradient: interpolate between red (255,0,0) and yellow (255,255,0)
var greenValue = Math.round(255 * (percentile / 10)); // Interpolate green channel
@@ -22,6 +40,8 @@ function gaussianRandom(mean=0, stdev=1) {
function runSimulations() {
// Retrieve input values
var amountInvested = parseFloat(document.getElementById('amountInvested').value);
+ var investmentType = document.getElementById('investmentType').value; // Get the investment type
+ var monthlyInvestment = investmentType === 'monthly' ? parseFloat(document.getElementById('monthlyInvestment').value) : 0;
var cagr = parseFloat(document.getElementById('cagr').value) / 100; // Convert percentage to decimal
var volatility = parseFloat(document.getElementById('volatility').value) / 100; // Convert percentage to decimal
var timeHorizon = parseInt(document.getElementById('timeHorizon').value);
@@ -32,6 +52,15 @@ function runSimulations() {
var monthlyReturn = Math.log(1 + cagr)/12; // like cagr/12 but adjusted for compounding
var monthlyVolatility = volatility/Math.sqrt(12); // lognormal process, volatility grows with sqrt(time)
+ // Calculate the timeseries of investment contributions
+ var investmentContributions = [amountInvested]; // Start with the initial amount invested
+ for (let month = 1; month <= numMonths; month++) {
+ // Each month, add the monthly investment to the last value
+ let lastValue = investmentContributions[month - 1];
+ let newValue = lastValue + monthlyInvestment;
+ investmentContributions.push(newValue);
+ }
+
// Run all simulations and store final values with corresponding simulation data
var simulationResults = [];
for (let sim = 0; sim < monteCarloSimulations; sim++) {
@@ -40,7 +69,7 @@ function runSimulations() {
let lastValue = data[month - 1];
// Simulate the monthly growth with volatility
let monthlyGrowth = monthlyReturn + monthlyVolatility*gaussianRandom(mean=0, stdev=1)
- let newValue = lastValue * (1 + monthlyGrowth);
+ let newValue = lastValue * (1 + monthlyGrowth) + monthlyInvestment;
data.push(newValue);
}
simulationResults.push({ finalValue: data[numMonths], data: data });
@@ -71,6 +100,18 @@ function runSimulations() {
pointRadius: 0, // Hide points for a cleaner look
}));
+ // Add the blue dashed line dataset for the cumulative investments
+ datasets.push({
+ label: 'Cumulative Investment',
+ data: investmentContributions,
+ borderColor: 'blue',
+ backgroundColor: 'rgba(0, 0, 255, 0.1)', // Light blue fill under the line
+ borderWidth: 1,
+ borderDash: [5, 5], // Dashed line: 5px dash, 5px gap
+ pointRadius: 0, // Hide points for a cleaner look
+ fill: true // Fill the area under the line
+ });
+
// Create Chart.js chart
new Chart(ctx, {
type: 'line',
@@ -124,8 +165,9 @@ function runSimulations() {
});
}
-// Initialize slider values on page load
+// Initialization
document.addEventListener('DOMContentLoaded', function() {
updateSliderValue('cagr', 'cagrValue');
updateSliderValue('volatility', 'volatilityValue');
+ toggleMonthlyInput();
});
\ No newline at end of file
diff --git a/styles.css b/styles.css
index d3b1233..fe79805 100644
--- a/styles.css
+++ b/styles.css
@@ -8,6 +8,10 @@ h1 {
color: #0b422e; /* Dark green color for the title */
}
+#monthlyInvestmentInput.hidden.hidden {
+ display: none;
+}
+
/* Base styles for mobile-first approach */
.container {
width: 100%; /* Full width */
@@ -45,6 +49,12 @@ h1 {
.content button {
margin-bottom: 30px; /* Increase vertical separation */
}
+
+.content select {
+ width: 45%; /* Custom width for dropdown menu */
+ padding: 5px 5px; /* Increase padding to make the dropdown menu lager*/
+ font-size: 1.2em; /* Larger font size for the number inside the input */
+}
.content input[type="number"] {
width: 35%; /* Custom width for number inputs */
font-size: 1.3em; /* Larger font size for the number inside the input */