Retirement Nest Egg Longevity Calculator

Retirement Nest Egg Longevity Calculator

Your Current Situation & Retirement Goals

Age you plan to start withdrawals.
Amount saved towards retirement each year until retirement age.
Your desired spending in today's dollars. This will be the initial withdrawal.
Calculated as (Desired Annual Income / Portfolio at Retirement). You can adjust this, or it will be derived.

Financial & Economic Assumptions

Expected return on investments during accumulation.
Expected return on investments during retirement (decumulation).
How long you want the nest egg to last after retirement.

Note: These are fixed average assumptions for an illustrative simulation. Real-world returns and inflation will vary and impact outcomes.

Nest Egg Longevity Projection

Click "Calculate Longevity" to view results. Ensure all inputs are set.

Total Withdrawn During Retirement: ${formatCurrency(data.retirementSummary.totalWithdrawnPostRetirement)}

`; html += `
`; // end summary grid // Accumulation Table html += `

Accumulation Phase Projection (Up to Age ${data.inputs.targetRetirementAge}):

`; if(data.accumulationTable.length > 0) { html += `
`; html += ``; data.accumulationTable.forEach(row => { html += ``; }); html += `
YearAgeStart BalanceContributionsGrowthEnd Balance
${row.year}${row.age} ${formatCurrency(row.yearStartBalance)}${formatCurrency(row.savingsThisYear)} ${formatCurrency(row.investmentGrowth)}${formatCurrency(row.endBalance)}
`; } else { html += `

No accumulation phase (retiring at current age or no accumulation years specified).

`; } // Decumulation Table if (data.decumulationTable.length > 0) { html += `

Retirement (Decumulation) Phase Projection:

`; html += `
`; html += ``; data.decumulationTable.forEach(row => { html += ``; }); html += `
Ret. YearAgeStart BalanceWithdrawalGrowthEnd Balance
${row.year}${row.age} ${formatCurrency(row.startBalance)}${formatCurrency(row.withdrawal)} ${formatCurrency(row.growth)} ${formatCurrency(row.endBalance)} ${row.notes ? `(${row.notes})` : ''}
`; } else { html += `

No decumulation phase to display (e.g., funds depleted immediately or retirement duration was 0).

`; } simulationResultsDiv.innerHTML = html; } if (runSimulationBtn) { runSimulationBtn.addEventListener('click', runFIRESimulation); // Still uses the same function name, logic inside is adapted } // --- PDF Download --- function loadJsPdfIfNeeded(callback) { if (jsPdfLoaded) { if (callback) callback(); return; } const script = document.createElement('script'); script.src = 'https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js'; script.onload = () => { jsPdfLoaded = true; console.log("jsPDF loaded dynamically."); if (callback) callback(); }; script.onerror = () => { console.error("Failed to load jsPDF."); alert("Error: Could not load PDF library."); }; document.head.appendChild(script); } function downloadResultsAsPdf() { if (!jsPdfLoaded) { alert("PDF library not loaded."); return; } if (!simulationDataForPdf) { alert("No simulation data to download. Please run the simulation first."); return; } const { jsPDF } = window.jspdf; const doc = new jsPDF({ unit: 'pt', format: 'a4' }); const data = simulationDataForPdf; const pageMargin = 40; const pageWidth = doc.internal.pageSize.getWidth() - 2 * pageMargin; let y = pageMargin; function addMainTitle(text) { doc.setFontSize(18); doc.setFont(undefined, 'bold'); doc.setTextColor(26, 83, 92); // Primary doc.text(text, doc.internal.pageSize.getWidth() / 2, y, { align: 'center' }); y += 35; } function addSectionTitle(text) { if (y > doc.internal.pageSize.getHeight() - 80) { doc.addPage(); y = pageMargin; } doc.setFontSize(14); doc.setFont(undefined, 'bold'); doc.setTextColor(78, 205, 196); // Secondary doc.text(text, pageMargin, y); y += 25; } function addLine(key, value, keyColor = [33,37,41], valueColor = [33,37,41]) { if (y > doc.internal.pageSize.getHeight() - 40) { doc.addPage(); y = pageMargin; } doc.setFontSize(10); doc.setFont(undefined, 'bold'); doc.setTextColor(keyColor[0], keyColor[1], keyColor[2]); doc.text(key, pageMargin, y); doc.setFont(undefined, 'normal'); doc.setTextColor(valueColor[0], valueColor[1], valueColor[2]); const valueText = String(value); doc.text(valueText, pageMargin + 240, y, { align: 'left', maxWidth: pageWidth - 240 - 5 }); y += 18; } function addInfo(text, isError = false) { if (y > doc.internal.pageSize.getHeight() - 50) { doc.addPage(); y = pageMargin; } doc.setFontSize(8.5); doc.setFont(undefined, 'italic'); doc.setTextColor(isError ? 220 : 108, isError ? 53 : 117, isError ? 69 : 125); const splitText = doc.splitTextToSize(text, pageWidth); doc.text(splitText, pageMargin, y); y += (doc.getTextDimensions(splitText).h) + 10; } function addTable(headers, tableData, columnWidths) { // Removed highlight logic for this version if (y > doc.internal.pageSize.getHeight() - 60) { doc.addPage(); y = pageMargin; } doc.setFontSize(8); const headerFillColor = [78, 205, 196]; const headerTextColor = [26, 83, 92]; const rowTextColor = [33,37,41]; doc.setFillColor(headerFillColor[0], headerFillColor[1], headerFillColor[2]); doc.setTextColor(headerTextColor[0], headerTextColor[1], headerTextColor[2]); doc.setFont(undefined, 'bold'); let currentX = pageMargin; headers.forEach((header, i) => { doc.rect(currentX, y, columnWidths[i], 20, 'F'); doc.text(header, currentX + 5, y + 14); currentX += columnWidths[i]; }); y += 20; doc.setTextColor(rowTextColor[0], rowTextColor[1], rowTextColor[2]); doc.setFont(undefined, 'normal'); tableData.forEach((rowArray) => { if (y > doc.internal.pageSize.getHeight() - 35) { doc.addPage(); y = pageMargin; currentX = pageMargin; doc.setFillColor(headerFillColor[0], headerFillColor[1], headerFillColor[2]); doc.setTextColor(headerTextColor[0], headerTextColor[1], headerTextColor[2]); doc.setFont(undefined, 'bold'); headers.forEach((header, i) => { doc.rect(currentX, y, columnWidths[i], 20, 'F'); doc.text(header, currentX + 5, y + 14); currentX += columnWidths[i]; }); y += 20; doc.setTextColor(rowTextColor[0], rowTextColor[1], rowTextColor[2]); doc.setFont(undefined, 'normal'); } currentX = pageMargin; rowArray.forEach((cell, i) => { doc.rect(currentX, y, columnWidths[i], 18); const cellText = String(cell); const textLines = doc.splitTextToSize(cellText, columnWidths[i] - 8); doc.text(textLines, currentX + 4, y + 12); currentX += columnWidths[i]; }); y += 18; }); y += 10; } addMainTitle("Retirement Nest Egg Longevity Report"); addInfo(`Report Generated: ${new Date().toLocaleString()}`); y += 10; addSectionTitle("Input Parameters"); addLine("Current Age:", `${data.inputs.currentAge} years`); addLine("Target Retirement Age:", `${data.inputs.targetRetirementAge} years`); addLine("Current Nest Egg Value:", formatCurrency(data.inputs.currentPortfolioValue)); addLine("Annual Contributions (Pre-Retirement):", formatCurrency(data.inputs.annualSavings)); addLine("Desired Annual Income in Retirement:", formatCurrency(data.inputs.annualExpensesInRetirement)); // addLine("User Input SWR (Reference):", `${data.inputs.safeWithdrawalRatePct.toFixed(1)}%`); // Can be added if desired addLine("Avg. Annual Return (Pre-Retirement):", `${data.inputs.preRetirementReturnRatePct.toFixed(1)}%`); addLine("Avg. Annual Return (Post-Retirement):", `${data.inputs.postRetirementReturnRatePct.toFixed(1)}%`); addLine("Expected Avg. Annual Inflation:", `${data.inputs.inflationRatePct.toFixed(1)}%`); addLine("Retirement Duration Simulated:", `${data.inputs.retirementDuration} years`); addLine("Adjust Withdrawals for Inflation:", data.inputs.adjustExpensesForInflation ? "Yes" : "No"); y += 10; addSectionTitle("Nest Egg Longevity Summary"); addLine("Portfolio Value at Retirement (Age " + data.inputs.targetRetirementAge + "):", formatCurrency(data.accumulationSummary.portfolioAtRetirement)); addLine("Actual Initial Withdrawal Rate:", `${data.retirementSummary.actualInitialSWR.toFixed(2)}%`); if (data.retirementSummary.fundsDepletedYear !== null && data.retirementSummary.fundsDepletedYear <= data.inputs.retirementDuration) { addLine("Nest Egg Longevity:", `Depleted in Year ${data.retirementSummary.fundsDepletedYear} of retirement`,[220,53,69],[220,53,69]); addLine("Age at Depletion:", `${data.inputs.targetRetirementAge + data.retirementSummary.fundsDepletedYear -1} years old`); } else { addLine("Nest Egg Longevity:", `Lasted for simulated ${data.inputs.retirementDuration} years`,[40,167,69],[40,167,69]); addLine("Final Balance After "+data.inputs.retirementDuration+" Years:", formatCurrency(data.retirementSummary.finalBalancePostRetirement)); } addLine("Total Withdrawn During Retirement:", formatCurrency(data.retirementSummary.totalWithdrawnPostRetirement)); y += 10; addSectionTitle("Accumulation Phase Projection (Up to Age " + data.inputs.targetRetirementAge + ")"); const accHeaders = ["Year", "Age", "Start Balance", "Contributions", "Growth", "End Balance"]; const accColWidths = [40, 40, 110, 90, 90, 110]; const accTableFormattedData = data.accumulationTable.map(r => [ r.year, r.age, formatCurrency(r.yearStartBalance,0,0), formatCurrency(r.savingsThisYear,0,0), formatCurrency(r.investmentGrowth,0,0), formatCurrency(r.endBalance,0,0) ]); if (accTableFormattedData.length > 0) { addTable(accHeaders, accTableFormattedData, accColWidths); } else { addInfo("No accumulation phase (retiring at current age or target retirement age is current age)."); } if (data.decumulationTable.length > 0) { addSectionTitle("Retirement (Decumulation) Phase Projection"); const decHeaders = ["Ret. Year", "Age", "Start Balance", "Withdrawal", "Growth", "End Balance"]; const decColWidths = [50, 40, 110, 90, 90, 110]; const decTableFormattedData = data.decumulationTable.map(r => [ r.year, r.age, formatCurrency(r.startBalance,0,0), formatCurrency(r.withdrawal,0,0), formatCurrency(r.growth,0,0), formatCurrency(r.endBalance,0,0) + (r.notes ? ` (${r.notes.substring(0,10)}..)` : '') ]); addTable(decHeaders, decTableFormattedData, decColWidths); } addInfo("Disclaimer: This simulation uses fixed average assumptions and does not account for market volatility, sequence of returns risk, taxes, or fees. It is for illustrative and educational purposes only and should not be considered financial advice. Consult with a qualified financial advisor for personalized retirement planning."); // Footer const pageCount = doc.internal.getNumberOfPages(); for (let i = 1; i <= pageCount; i++) { doc.setPage(i); doc.setFontSize(8); doc.setTextColor(150); doc.text(`Page ${i} of ${pageCount} - Retirement Nest Egg Longevity Calculator`, pageMargin, doc.internal.pageSize.getHeight() - 20); } doc.save('Retirement_Nest_Egg_Longevity.pdf'); } if (downloadPdfBtn) { downloadPdfBtn.addEventListener('click', () => loadJsPdfIfNeeded(downloadResultsAsPdf)); } // --- Initialization --- showTab(0); loadJsPdfIfNeeded(); });
Scroll to Top