Financial Independence (FI) Tracker
Step 1: Your Financial Snapshot & FI Goals
Personal & Income
Assets & Liabilities
FI Goal & Investment Plan
Step 2: Years to Financial Independence Projection
This projection uses your current invested assets, annual savings, expected real return, and FI Number calculated in Tab 1.
Projection Summary (Sample Years):
Step 3: Your FI Progress Summary
Complete calculations on Tab 1 and Tab 2 to see your summary.
Progress to FI Number: 0%
Key Factors for Your FI Journey:
- Savings Rate: The higher your savings rate, the faster you build investable assets.
- Investment Returns: Consistent, reasonable real returns significantly impact your growth over time.
- Managing Expenses: Keeping your desired retirement spending realistic affects your FI Number.
- Consistency: Regularly saving and investing is crucial.
- This tool provides estimates. Market conditions and personal circumstances can change. Review your plan periodically.
Desired Annual Spending in Retirement: $${desiredRetirementSpending.toFixed(2)}
Safe Withdrawal Rate (SWR): ${(swr*100).toFixed(1)}%
Your FI Number (Invested Assets Needed): $${fiNumber.toFixed(2)}
Current Progress towards FI Number: ${Math.min(100, progressToFi).toFixed(1)}% of invested assets
`; outputDiv.style.display = 'block'; // Also update desired spending if expenses changed and it was default document.getElementById('desiredRetirementSpending').value = desiredRetirementSpending; if (showAlerts) { alert("Snapshot and FI Goal calculated! Check the results below and proceed to Tab 2 for projection."); } } function projectYearsToFi(showAlerts = true) { if (!fiReportData.snapshot || !fiReportData.snapshot.fiNumber) { if(showAlerts) alert("Please calculate your snapshot and FI goal on Tab 1 first."); openFiTab(null, 'snapshotGoalTab'); calculateSnapshotAndGoals(false); // Try to calc silently if (!fiReportData.snapshot || !fiReportData.snapshot.fiNumber) return; // Still no data, exit } let currentInvestments = fiReportData.inputs.investedAssets; const annualSavings = fiReportData.snapshot.annualSavings; const realReturnRate = fiReportData.inputs.realReturnRate / 100; const fiNumber = fiReportData.snapshot.fiNumber; const annualSavingsIncreaseRate = getNumFi('annualSavingsIncreaseRate', 0) / 100; if (annualSavings <= 0 && currentInvestments < fiNumber) { if(showAlerts) alert("With current savings rate of zero or less, and investments below FI number, FI cannot be reached unless returns alone are sufficient. Please review inputs."); document.getElementById('projectionOutput').innerHTML = `Cannot project FI with current savings rate of $${annualSavings.toFixed(2)}. Your investments must grow to $${fiNumber.toFixed(2)} on their own or you need to save more.
`; document.getElementById('projectionOutput').style.display = 'block'; document.getElementById('projectionTableSummaryContainer').style.display = 'none'; fiReportData.projection = { yearsToFi: Infinity, ageAtFi: Infinity, fullTable: [], summaryTable: [] }; return; } if (currentInvestments >= fiNumber) { if(showAlerts) alert("Congratulations! Your current invested assets already meet or exceed your FI number."); document.getElementById('projectionOutput').innerHTML = `Congratulations! You've reached your FI number based on current invested assets!
`; document.getElementById('projectionOutput').style.display = 'block'; document.getElementById('projectionTableSummaryContainer').style.display = 'none'; fiReportData.projection = { yearsToFi: 0, ageAtFi: fiReportData.inputs.currentAge, fullTable: [], summaryTable: [] }; return; } let years = 0; let projectionTable = []; let currentAnnualSavingsContribution = annualSavings; while (currentInvestments < fiNumber && years < 100) { // Max 100 years projection years++; let yearStartInvestments = currentInvestments; // Grow investments currentInvestments *= (1 + realReturnRate); let investmentGrowthAmount = currentInvestments - yearStartInvestments; // Add savings (compounded if increase rate > 0) let savingsThisYear = currentAnnualSavingsContribution; currentInvestments += savingsThisYear; projectionTable.push({ year: years, startInvestments: yearStartInvestments, savingsAdded: savingsThisYear, investmentGrowth: investmentGrowthAmount, endInvestments: currentInvestments }); // Increase savings for next year currentAnnualSavingsContribution *= (1 + annualSavingsIncreaseRate); } fiReportData.projection.fullTable = projectionTable; fiReportData.projection.yearsToFi = years >= 100 ? Infinity : years; fiReportData.projection.ageAtFi = years >= 100 ? Infinity : (fiReportData.inputs.currentAge + years); const outputDiv = document.getElementById('projectionOutput'); if (years >= 100) { outputDiv.innerHTML = `Projection exceeds 100 years. FI may not be reachable with current parameters or will take a very long time.
`; } else { outputDiv.innerHTML = `Years to FI Projection:
Estimated Years to Financial Independence: ${years} years
Estimated Age at Financial Independence: ${fiReportData.projection.ageAtFi} years old
`; } outputDiv.style.display = 'block'; displayProjectionTableSummary(projectionTable); if(showAlerts) alert("Projection complete! Check the results below."); } function displayProjectionTableSummary(fullTable){ const tableContainer = document.getElementById('projectionTableSummaryContainer'); const tableBody = document.getElementById('fiProjectionTableSummary'); if(!fullTable || fullTable.length === 0) { tableContainer.style.display = 'none'; return; } let summaryData = []; // Show first 3 years, last 3 years, and perhaps a middle year if long projection if (fullTable.length <= 7) { summaryData = fullTable; } else { summaryData.push(...fullTable.slice(0, 3)); // First 3 summaryData.push({year:'...', startInvestments:'...', savingsAdded:'...', investmentGrowth:'...', endInvestments:'...'}); // Ellipsis summaryData.push(...fullTable.slice(-3)); // Last 3 } let tableHTML = `Please complete calculations on Tab 1 and Tab 2 first.
"; document.getElementById('downloadFiPdfButton').disabled = true; document.getElementById('fiProgressBar').style.width = '0%'; document.getElementById('fiProgressBar').textContent = '0%'; document.getElementById('progressPercentageDisplay').textContent = '0'; return; } const summaryContainer = document.getElementById('fiProgressSummaryContainer'); const progress = Math.min(100, fiReportData.snapshot.progressToFi || 0); summaryContainer.innerHTML = `Your FI Number: $${fiReportData.snapshot.fiNumber.toFixed(2)}
Current Invested Assets: $${fiReportData.inputs.investedAssets.toFixed(2)}
Progress to FI: ${progress.toFixed(1)}%
Estimated Years to FI: ${fiReportData.projection.yearsToFi === Infinity ? '>100 (Review Inputs)' : fiReportData.projection.yearsToFi + ' years'}
Estimated Age at FI: ${fiReportData.projection.ageAtFi === Infinity ? '>100+' : fiReportData.projection.ageAtFi + ' years old'}
Current Savings Rate: ${fiReportData.snapshot.savingsRate.toFixed(1)}%
`; const progressBar = document.getElementById('fiProgressBar'); progressBar.style.width = `${progress.toFixed(1)}%`; progressBar.textContent = `${progress.toFixed(1)}%`; document.getElementById('progressPercentageDisplay').textContent = progress.toFixed(1); document.getElementById('downloadFiPdfButton').disabled = false; } function downloadFiPdf() { if (!fiReportData.snapshot || !fiReportData.snapshot.fiNumber || !fiReportData.projection || fiReportData.projection.yearsToFi === undefined) { alert("Please complete all calculation steps first."); return; } if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined') { alert('PDF generation library (jsPDF) is not loaded.'); return; } const jsPDFConstructor = window.jspdf.jsPDF; const doc = new jsPDFConstructor(); if (typeof doc.autoTable !== 'function') { alert('jsPDF AutoTable plugin not loaded.'); return; } const { inputs, snapshot, projection } = fiReportData; const primaryColor = '#007bff', textColor = '#212529', tableHeaderColor = '#e9ecef'; let yPos = 22; const pageHeight = doc.internal.pageSize.height; const margin = 20; function checkY(increment = 10) { if (yPos + increment > pageHeight - margin) { doc.addPage(); yPos = margin; } } doc.setFontSize(18); doc.setTextColor(primaryColor); doc.text("Financial Independence Progress Report", 14, yPos); yPos += 8; doc.setFontSize(10); doc.setTextColor(textColor); doc.text(`Report Date: ${new Date().toLocaleDateString()}`, 14, yPos); yPos += 10; checkY(25); doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Your Financial Profile", 14, yPos); yPos += 6; let profileBody = [ ['Current Age:', `${inputs.currentAge} years`], ['Annual Net Income:', `$${inputs.annualNetIncome.toFixed(2)}`], ['Annual Living Expenses:', `$${inputs.annualExpenses.toFixed(2)}`], ['Annual Savings:', `$${snapshot.annualSavings.toFixed(2)}`], ['Savings Rate:', `${snapshot.savingsRate.toFixed(1)}%`] ]; doc.autoTable({startY: yPos, body: profileBody, theme:'plain', styles:{fontSize:9}, columnStyles:{0:{fontStyle:'bold'}}}); yPos = doc.lastAutoTable.finalY + 7; checkY(30); doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Net Worth Statement", 14, yPos); yPos += 6; let netWorthBody = [ ['Liquid Savings:', `$${inputs.liquidSavings.toFixed(2)}`], ['Invested Assets (for FI):', `$${inputs.investedAssets.toFixed(2)}`], ['Other Assets:', `$${inputs.otherAssets.toFixed(2)}`], [{content:'Total Assets:', styles:{fontStyle:'bold'}}, `$${snapshot.totalAssets.toFixed(2)}`], ['Total Debt:', `$${inputs.totalDebt.toFixed(2)}`], [{content:'Net Worth:', styles:{fontStyle:'bold', textColor:[0,100,0]}}, {content:`$${snapshot.netWorth.toFixed(2)}`, styles:{fontStyle:'bold', textColor:[0,100,0]}}] ]; doc.autoTable({startY: yPos, body: netWorthBody, theme:'plain', styles:{fontSize:9}, columnStyles:{0:{fontStyle:'bold'}}}); yPos = doc.lastAutoTable.finalY + 7; checkY(30); doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Financial Independence Goal", 14, yPos); yPos += 6; let goalBody = [ ['Desired Annual Spending in Retirement:', `$${inputs.desiredRetirementSpending.toFixed(2)}`], ['Safe Withdrawal Rate (SWR):', `${inputs.swr.toFixed(1)}%`], [{content:'Your FI Number:', styles:{fontStyle:'bold'}}, {content:`$${snapshot.fiNumber.toFixed(2)}`, styles:{fontStyle:'bold'}}], ['Progress to FI (Invested Assets):', `${snapshot.progressToFi.toFixed(1)}%`] ]; doc.autoTable({startY: yPos, body: goalBody, theme:'plain', styles:{fontSize:9}, columnStyles:{0:{fontStyle:'bold'}}}); yPos = doc.lastAutoTable.finalY + 10; checkY(30 + (projection.fullTable.length > 0 ? 20 : 0) ); // More space if table exists doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Projection to Financial Independence", 14, yPos); yPos += 6; let projectionSummaryBody = [ ['Current Invested Assets:', `$${inputs.investedAssets.toFixed(2)}`], ['Annual Savings (Year 1):', `$${snapshot.annualSavings.toFixed(2)}`], ['Annual Savings Increase Rate:', `${(getNumFi('annualSavingsIncreaseRate',0)).toFixed(1)}%`], ['Expected Real Return Rate:', `${inputs.realReturnRate.toFixed(1)}%`], [{content:'Estimated Years to FI:', styles:{fontStyle:'bold'}}, {content:`${projection.yearsToFi === Infinity ? '>100 years' : projection.yearsToFi + ' years'}`, styles:{fontStyle:'bold'}}], [{content:'Estimated Age at FI:', styles:{fontStyle:'bold'}}, {content:`${projection.ageAtFi === Infinity ? '>100+' : projection.ageAtFi + ' years old'}`, styles:{fontStyle:'bold'}}] ]; doc.autoTable({startY: yPos, body: projectionSummaryBody, theme:'plain', styles:{fontSize:9}, columnStyles:{0:{fontStyle:'bold'}}}); yPos = doc.lastAutoTable.finalY + 7; if (projection.fullTable && projection.fullTable.length > 0 && projection.yearsToFi !== Infinity) { checkY(10); doc.setFontSize(10); doc.setTextColor(textColor); doc.text("Year-by-Year Projection Details:", 14, yPos); yPos += 5; const tableHead = [['Year', 'Start Investments ($)', 'Savings Added ($)', 'Investment Growth ($)', 'End Investments ($)']]; const tableBody = projection.fullTable.map(row => [ row.year, row.startInvestments.toFixed(0), row.savingsAdded.toFixed(0), row.investmentGrowth.toFixed(0), row.endInvestments.toFixed(0) ]); doc.autoTable({ startY: yPos, head: tableHead, body: tableBody, theme: 'grid', headStyles: {fillColor: tableHeaderColor, textColor: textColor, fontStyle:'bold', fontSize:8}, styles: {fontSize:7.5, cellPadding:1.2, halign:'right'}, columnStyles: {0:{halign:'center'}} }); } else if (projection.yearsToFi === Infinity) { checkY(10); doc.setFontSize(9); doc.setTextColor(textColor); doc.text("Detailed year-by-year projection not shown as FI is estimated to take over 100 years with current inputs.", 14, yPos); yPos+=5; } doc.save("Financial_Independence_Report.pdf"); } // Initial calls updateFiNavButtons(); // Set default desired retirement spending on load document.getElementById('desiredRetirementSpending').value = document.getElementById('annualExpenses').value;