Financial Independence (FI) Tracker

Step 1: Your Financial Snapshot & FI Goals

Personal & Income

Assets & Liabilities

Stocks, bonds, retirement accounts, rental equity generating income, etc.
E.g., primary home equity if considered separately, valuable collectibles.
Student loans, credit cards, personal loans.

FI Goal & Investment Plan

In today's dollars. Defaults to current expenses.
After inflation (e.g., 5-7%).

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.

Enter 0 if your annual savings amount will stay the same (in today's dollars).

Step 3: Your FI Progress Summary

Complete calculations on Tab 1 and Tab 2 to see your summary.

Progress to FI Number: 0%

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 = `YearStart Investments ($)Savings Added ($)Investment Growth ($)End Investments ($)`; summaryData.forEach(row => { tableHTML += ` ${row.year} ${typeof row.startInvestments === 'number' ? row.startInvestments.toFixed(0) : row.startInvestments} ${typeof row.savingsAdded === 'number' ? row.savingsAdded.toFixed(0) : row.savingsAdded} ${typeof row.investmentGrowth === 'number' ? row.investmentGrowth.toFixed(0) : row.investmentGrowth} ${typeof row.endInvestments === 'number' ? row.endInvestments.toFixed(0) : row.endInvestments} `; }); tableHTML += ``; tableBody.innerHTML = tableHTML; tableContainer.style.display = 'block'; fiReportData.projection.summaryTable = summaryData; // Save for PDF } function displayFiSummary() { if (!fiReportData.snapshot || !fiReportData.snapshot.fiNumber || !fiReportData.projection || fiReportData.projection.yearsToFi === undefined) { document.getElementById('fiProgressSummaryContainer').innerHTML = "

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;
Scroll to Top