Tax Optimization for Investment Gains

Tax Optimizer for Investment Gains

Based on 2024 U.S. Federal Tax Brackets

Enter your income and investment details on the next tabs, then click 'Calculate' to see your estimated tax impact.

`; } return `

Total Capital Gains Tax

$${taxResults.totalTax.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}

Effective Tax Rate on Gains

${taxResults.effectiveRate.toFixed(2)}%

Tax Savings From Long-Term

$${taxResults.savings.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}

Tax Breakdown by Gain Type

Gain Type Total Gain Tax Owed
Short-Term Gains $${taxResults.shortTerm.gain.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})} $${taxResults.shortTerm.tax.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}
Long-Term Gains $${taxResults.longTerm.gain.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})} $${taxResults.longTerm.tax.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}
`; }; const renderProfileTab = () => { return `
$
`; }; const renderInvestmentsTab = () => { let investmentForms = investments.map(inv => `
`).join(''); return `
${investmentForms}
`; }; // --- DATA MANIPULATION & EVENT HANDLERS --- window.updateProfile = (key, value) => userProfile[key] = (key === 'taxableIncome') ? parseFloat(value) || 0 : value; window.addInvestment = () => { const today = new Date().toISOString().split('T')[0]; investments.push({ id: Date.now(), description: 'New Investment', purchasePrice: 0, salePrice: 0, purchaseDate: today, saleDate: today }); renderCurrentTab(); }; window.updateInvestment = (id, key, value) => { const inv = investments.find(i => i.id === id); if(inv) inv[key] = (key.includes('Price')) ? parseFloat(value) || 0 : value; }; window.deleteInvestment = (id) => { investments = investments.filter(i => i.id !== id); renderCurrentTab(); }; // --- TAX CALCULATION LOGIC --- const calculateTax = (income, brackets) => { let tax = 0; let remainingIncome = income; let prevMax = 0; for (const bracket of brackets) { if (remainingIncome <= 0) break; const taxableInBracket = Math.min(remainingIncome, bracket.max - prevMax); tax += taxableInBracket * bracket.rate; remainingIncome -= taxableInBracket; prevMax = bracket.max; } return tax; }; const handleCalculation = () => { const status = userProfile.filingStatus; const income = userProfile.taxableIncome; let totalShortTermGain = 0; let totalLongTermGain = 0; investments.forEach(inv => { const gain = inv.salePrice - inv.purchasePrice; if (gain <= 0) return; const holdingPeriod = (new Date(inv.saleDate) - new Date(inv.purchaseDate)) / (1000 * 60 * 60 * 24); if (holdingPeriod > 365) { totalLongTermGain += gain; } else { totalShortTermGain += gain; } }); // 1. Calculate tax on Long-Term Gains const longTermBrackets = taxData.longTerm[status]; let taxOnLongTerm = 0; let remainingLongTermGain = totalLongTermGain; let incomeLevel = income; for (const bracket of longTermBrackets) { if (remainingLongTermGain <= 0) break; const bracketRoom = bracket.max - incomeLevel; if (bracketRoom > 0) { const taxableInBracket = Math.min(remainingLongTermGain, bracketRoom); taxOnLongTerm += taxableInBracket * bracket.rate; remainingLongTermGain -= taxableInBracket; } incomeLevel = bracket.max; // Move to next bracket threshold } // 2. Calculate tax on Short-Term Gains const ordinaryBrackets = taxData.ordinary[status]; const taxOnBaseIncome = calculateTax(income, ordinaryBrackets); const taxOnTotalIncome = calculateTax(income + totalShortTermGain, ordinaryBrackets); const taxOnShortTerm = taxOnTotalIncome - taxOnBaseIncome; // 3. Calculate potential savings const taxIfAllShortTerm = calculateTax(income + totalShortTermGain + totalLongTermGain, ordinaryBrackets) - taxOnBaseIncome; const savings = taxIfAllShortTerm - (taxOnShortTerm + taxOnLongTerm); taxResults = { shortTerm: { gain: totalShortTermGain, tax: taxOnShortTerm }, longTerm: { gain: totalLongTermGain, tax: taxOnLongTerm }, totalTax: taxOnShortTerm + taxOnLongTerm, effectiveRate: (totalShortTermGain + totalLongTermGain > 0) ? ((taxOnShortTerm + taxOnLongTerm) / (totalShortTermGain + totalLongTermGain)) * 100 : 0, savings: savings > 0 ? savings : 0 }; switchTab(0); }; // --- CHART & PDF --- const renderChart = () => { if (taxChart) taxChart.destroy(); const ctx = document.getElementById('taxChart')?.getContext('2d'); if (!ctx || !taxResults) return; taxChart = new Chart(ctx, { type: 'pie', data: { labels: ['Short-Term Gains Tax', 'Long-Term Gains Tax'], datasets: [{ data: [taxResults.shortTerm.tax, taxResults.longTerm.tax], backgroundColor: ['#ef4444', '#10b981'], // Red, Green }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { title: { display: true, text: 'Tax Apportionment by Gain Type' } } } }); }; window.downloadPDF = () => { if (!taxResults) return; const { jsPDF } = window.jspdf; const doc = new jsPDF(); doc.setFontSize(20); doc.text("Investment Gains Tax Report", doc.internal.pageSize.getWidth() / 2, 20, { align: 'center' }); doc.setFontSize(11); doc.text(`Based on ${userProfile.filingStatus} status and $${userProfile.taxableIncome.toLocaleString()} income.`, doc.internal.pageSize.getWidth() / 2, 28, { align: 'center' }); const summaryText = ` Total Tax on Gains: $${taxResults.totalTax.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})} Tax Savings from Long-Term Gains: $${taxResults.savings.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})} Effective Tax Rate on Gains: ${taxResults.effectiveRate.toFixed(2)}% `; doc.text(summaryText, 14, 45); const finalY = taxChart ? 75 : 45; if(taxChart) { const chartImage = taxChart.toBase64Image(); doc.addImage(chartImage, 'PNG', 14, finalY, 180, 80); } const head = [['Description', 'Gain/Loss ($)', 'Holding Period', 'Gain Type', 'Estimated Tax ($)']]; const body = investments.map(inv => { const gain = inv.salePrice - inv.purchasePrice; const pDate = new Date(inv.purchaseDate); const sDate = new Date(inv.saleDate); const holdingDays = Math.round((sDate - pDate) / (1000 * 60 * 60 * 24)); const type = holdingDays > 365 ? 'Long-Term' : 'Short-Term'; // This is a simplified tax attribution for the PDF, not the precise calculation const estTax = type === 'Long-Term' ? (gain / taxResults.longTerm.gain) * taxResults.longTerm.tax : (gain / taxResults.shortTerm.gain) * taxResults.shortTerm.tax; return [ inv.description, gain.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2}), `${holdingDays} days`, type, gain > 0 ? (isNaN(estTax) ? 0 : estTax).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2}) : 'N/A' ]; }); doc.autoTable({ startY: finalY + (taxChart ? 90 : 10), head: head, body: body, theme: 'striped', headStyles: { fillColor: [5, 150, 105] } }); doc.save('Tax-Optimization-Report.pdf'); }; // --- INITIALIZATION --- DOM.nextBtn.addEventListener('click', () => switchTab(currentTab + 1)); DOM.prevBtn.addEventListener('click', () => switchTab(currentTab - 1)); DOM.tabButtons.forEach((btn, i) => btn.addEventListener('click', () => switchTab(i))); renderCurrentTab(); updateNavButtons(); });
Scroll to Top