Stock Portfolio Diversification Planner

Stock Portfolio Diversification Planner

Analyze your portfolio's sector allocation and concentration.

Current Holdings

Total Value

$0

Holdings

0

Diversification Score

-

Sector Allocation

Largest Holdings

${h.ticker}

${h.sector}

${formatCurrency(h.value)}
`; }); // --- Calculate HHI for Diversification --- let hhi = 0; let diversificationText = 'N/A', diversificationClass = 'text-slate-800'; if (totalValue > 0) { for(const sector in sectorAllocation) { hhi += (sectorAllocation[sector] / totalValue)**2; } if (hhi < 0.25) { diversificationText = 'Well Diversified'; diversificationClass = 'text-green-600'; } else if (hhi < 0.40) { diversificationText = 'Moderate'; diversificationClass = 'text-yellow-600'; } else { diversificationText = 'Concentrated'; diversificationClass = 'text-red-600'; } } // --- Update Dashboard --- document.getElementById('total-value').textContent = formatCurrency(totalValue); document.getElementById('holding-count').textContent = portfolio.length; const scoreEl = document.getElementById('diversification-score'); scoreEl.textContent = diversificationText; scoreEl.className = `text-3xl font-bold ${diversificationClass}`; // --- Largest Holdings --- const largestHoldings = [...portfolio].sort((a,b) => b.value - a.value).slice(0, 5); const largestHoldingsEl = document.getElementById('largest-holdings'); largestHoldingsEl.innerHTML = ''; largestHoldings.forEach(h => { const percentage = totalValue > 0 ? (h.value / totalValue * 100).toFixed(1) : 0; largestHoldingsEl.innerHTML += `
${h.ticker} ${percentage}%
`; }); renderChart(sectorAllocation, totalValue); } function renderChart(allocationData, totalValue) { const ctx = document.getElementById('sector-chart').getContext('2d'); const labels = [], data = []; for(const sector in allocationData) { if (allocationData[sector] > 0) { labels.push(sector); data.push((allocationData[sector] / totalValue * 100).toFixed(2)); } } const chartData = { labels, datasets: [{ data, backgroundColor: ['#1e3a8a', '#3b82f6', '#93c5fd', '#334155', '#64748b', '#047857', '#34d399', '#f59e0b', '#fbbf24', '#b91c1c', '#f87171'] }]}; if (sectorChart) { sectorChart.data = chartData; sectorChart.update(); } else { sectorChart = new Chart(ctx, { type: 'doughnut', data: chartData, options: { responsive: true, plugins: { legend: { display: true, position: 'bottom', labels: { boxWidth: 12 } } } }}); } } const holdingModal = document.getElementById('holding-modal'); function openModal(holding = null) { document.getElementById('holding-form').reset(); if (holding) { document.getElementById('modal-title').textContent = 'Edit Holding'; document.getElementById('holding-id').value = holding.id; document.getElementById('ticker').value = holding.ticker; document.getElementById('sector').value = holding.sector; document.getElementById('value').value = holding.value; } else { document.getElementById('modal-title').textContent = 'Add New Holding'; } holdingModal.classList.remove('hidden'); } function closeModal() { holdingModal.classList.add('hidden'); } document.getElementById('holding-form').addEventListener('submit', (e) => { e.preventDefault(); const id = document.getElementById('holding-id').value; const newHolding = { id: id ? parseInt(id) : Date.now(), ticker: document.getElementById('ticker').value, sector: document.getElementById('sector').value, value: parseFloat(document.getElementById('value').value), }; if (id) { portfolio = portfolio.map(h => h.id === newHolding.id ? newHolding : h); } else { portfolio.push(newHolding); } closeModal(); analyzeAndRender(); }); document.getElementById('holdings-list').addEventListener('click', e => { if (e.target.classList.contains('delete-btn')) { portfolio = portfolio.filter(h => h.id !== parseInt(e.target.dataset.id)); analyzeAndRender(); } }); document.getElementById('add-holding-btn').addEventListener('click', () => openModal()); document.getElementById('cancel-btn').addEventListener('click', closeModal); function downloadPdf() { if (portfolio.length === 0) return; const { jsPDF } = window.jspdf; const pdf = new jsPDF(); pdf.setFont('helvetica', 'bold').setFontSize(22).text('Portfolio Diversification Report', 105, 20, { align: 'center' }); const totalValue = portfolio.reduce((sum, h) => sum + h.value, 0); const chartImg = sectorChart.toBase64Image('image/png', 1.0); pdf.autoTable({ startY: 30, theme: 'grid', headStyles: { fillColor: '#1e293b' }, head: [['Metric', 'Value']], body: [ ['Total Portfolio Value', formatCurrency(totalValue)], ['Number of Holdings', portfolio.length], ['Diversification Score', document.getElementById('diversification-score').textContent] ] }); pdf.addImage(chartImg, 'PNG', 15, pdf.autoTable.previous.finalY + 10, 180, 90); const body = portfolio.map(h => [h.ticker, h.sector, formatCurrency(h.value), `${(h.value / totalValue * 100).toFixed(2)}%`]); pdf.autoTable({ startY: pdf.autoTable.previous.finalY + 105, head: [['Ticker', 'Sector', 'Value', 'Weight']], body, theme: 'striped', headStyles: { fillColor: '#1e293b' }}); pdf.save('Portfolio_Diversification_Report.pdf'); } document.getElementById('download-pdf-btn').addEventListener('click', downloadPdf); function init() { const sectorSelect = document.getElementById('sector'); sectors.forEach(s => sectorSelect.innerHTML += ``); portfolio = [ {id: 1, ticker: 'AAPL', sector: 'Technology', value: 25000}, {id: 2, ticker: 'JNJ', sector: 'Healthcare', value: 15000}, {id: 3, ticker: 'JPM', sector: 'Financials', value: 18000}, {id: 4, ticker: 'MSFT', sector: 'Technology', value: 22000}, {id: 5, ticker: 'XOM', sector: 'Energy', value: 10000}, ]; analyzeAndRender(); } init(); });
Scroll to Top