Tax Optimization for Investment Gains

Tax Optimizer for Investment Gains

Based on 2024 U.S. Federal Tax Brackets

${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