Core-Satellite Portfolio Strategy Planner
Welcome to the Core-Satellite Portfolio Planner
This tool helps you plan your investment strategy using the **Core-Satellite approach**. This strategy aims to reduce risk and provide stable returns by investing a significant portion of the portfolio in passively managed, broad market index funds (the "Core"), while a smaller portion is actively managed with higher-risk, higher-reward investments (the "Satellites").
Use the tabs above to input your investment details and calculate your portfolio allocation.
Click "Next" to begin planning your portfolio.
Core Portfolio Inputs
The Core typically consists of low-cost, broadly diversified index funds or ETFs. This section helps define your core allocation.
Satellite Portfolio Inputs
Satellites are designed to enhance returns or provide exposure to specific market segments. You can define up to three satellite investments.
Satellite 1
Satellite 2
Satellite 3 (Optional)
Review Your Inputs & Calculate
Please review the details below. Once confirmed, click "Calculate Portfolio" to see your projected Core-Satellite strategy.
Portfolio Strategy Summary
Detailed Allocation
| Component | Allocation ($) | Allocation (%) | Expected Return (%) | Risk Level |
|---|
Overall Portfolio Expected Annual Return:
Overall Portfolio Risk Level:
Percentage of Satellite Portfolio: ${satellite3Percentage}%
Expected Annual Return: ${satellite3ExpectedReturn}%
Risk Level: ${satellite3RiskLevel}
`; } // Check if no satellites are defined but total investment is present if ((!satellite1Name || satellite1Percentage === 0) && (!satellite2Name || satellite2Percentage === 0) && (!satellite3Name || satellite3Percentage === 0) && totalInvestment > 0) { summaryHtml += `No active satellite investments defined.
`; } else if (totalInvestment === 0) { summaryHtml += `Please enter a Total Investment Amount to proceed.
`; } reviewSummaryDiv.innerHTML = summaryHtml; } /** * Calculates and displays the portfolio strategy results. */ function calculatePortfolio() { const totalInvestment = parseFloat(document.getElementById('totalInvestment').value); const corePercentage = parseFloat(document.getElementById('corePercentage').value); const coreExpectedReturn = parseFloat(document.getElementById('coreExpectedReturn').value); const coreRiskLevel = document.getElementById('coreRiskLevel').value; // Input validation if (isNaN(totalInvestment) || totalInvestment <= 0) { alert('Please enter a valid Total Investment Amount greater than 0.'); return; } if (isNaN(corePercentage) || corePercentage < 0 || corePercentage > 100) { alert('Please enter a valid Core Portfolio Percentage between 0 and 100.'); return; } let coreInvestment = totalInvestment * (corePercentage / 100); let satelliteInvestment = totalInvestment - coreInvestment; let portfolioComponents = []; portfolioComponents.push({ name: 'Core Portfolio', investment: coreInvestment, percentage: corePercentage, expectedReturn: coreExpectedReturn, risk: coreRiskLevel }); const satellites = [{ name: document.getElementById('satellite1Name').value.trim(), percentage: parseFloat(document.getElementById('satellite1Percentage').value) || 0, expectedReturn: parseFloat(document.getElementById('satellite1ExpectedReturn').value) || 0, risk: document.getElementById('satellite1RiskLevel').value }, { name: document.getElementById('satellite2Name').value.trim(), percentage: parseFloat(document.getElementById('satellite2Percentage').value) || 0, expectedReturn: parseFloat(document.getElementById('satellite2ExpectedReturn').value) || 0, risk: document.getElementById('satellite2RiskLevel').value }, { name: document.getElementById('satellite3Name').value.trim(), percentage: parseFloat(document.getElementById('satellite3Percentage').value) || 0, expectedReturn: parseFloat(document.getElementById('satellite3ExpectedReturn').value) || 0, risk: document.getElementById('satellite3RiskLevel').value }, ]; let totalSatellitePercentage = 0; satellites.forEach(s => { totalSatellitePercentage += s.percentage; }); if (totalSatellitePercentage > 0 && totalSatellitePercentage !== 100) { alert('The sum of Satellite Portfolio Percentages must be 100% or 0% if no satellites are desired. Currently it is ' + totalSatellitePercentage + '%.'); return; } satellites.forEach(s => { if (s.name && s.percentage > 0) { portfolioComponents.push({ name: s.name, investment: satelliteInvestment * (s.percentage / 100), percentage: (satelliteInvestment * (s.percentage / 100)) / totalInvestment * 100, expectedReturn: s.expectedReturn, risk: s.risk }); } else if (!s.name && s.percentage > 0) { alert('Please provide a name for all active Satellite Portfolio components.'); return; // Stop calculation if an unnamed satellite has a percentage } }); // Calculate overall expected return and risk let totalWeightedReturn = 0; let riskLevels = { 'Low': 0, 'Medium': 0, 'High': 0 }; portfolioComponents.forEach(comp => { totalWeightedReturn += comp.expectedReturn * (comp.investment / totalInvestment); riskLevels[comp.risk]++; }); // Determine overall risk level (simplified logic) let overallRisk = 'Medium'; // Default if (riskLevels['High'] > riskLevels['Low'] && riskLevels['High'] > riskLevels['Medium']) { overallRisk = 'High'; } else if (riskLevels['Low'] > riskLevels['High'] && riskLevels['Low'] > riskLevels['Medium']) { overallRisk = 'Low'; } // Display results document.getElementById('portfolioSummary').innerHTML = `Your total investment of $${totalInvestment.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} will be allocated as follows:
Core Portfolio: $${coreInvestment.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} (${corePercentage}%)
Satellite Portfolio: $${satelliteInvestment.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} (${(100 - corePercentage).toFixed(2)}%)
`; const tableBody = document.querySelector('#detailedAllocationTable tbody'); tableBody.innerHTML = ''; // Clear previous results portfolioComponents.forEach(comp => { const row = tableBody.insertRow(); row.insertCell().textContent = comp.name; row.insertCell().textContent = `$${comp.investment.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`; row.insertCell().textContent = `${comp.percentage.toFixed(2)}%`; row.insertCell().textContent = `${comp.expectedReturn.toFixed(2)}%`; row.insertCell().textContent = comp.risk; }); document.getElementById('overallExpectedReturn').textContent = `${totalWeightedReturn.toFixed(2)}%`; document.getElementById('overallRiskLevel').textContent = overallRisk; resultsDiv.style.display = 'block'; downloadPdfBtn.style.display = 'block'; } /** * Generates and downloads a PDF of the portfolio summary. */ function downloadPdf() { const { jsPDF } = window.jspdf; const doc = new jsPDF(); const totalInvestment = parseFloat(document.getElementById('totalInvestment').value) || 0; const corePercentage = parseFloat(document.getElementById('corePercentage').value) || 0; const satelliteInvestmentPercentage = (100 - corePercentage).toFixed(2); const overallExpectedReturn = document.getElementById('overallExpectedReturn').textContent; const overallRiskLevel = document.getElementById('overallRiskLevel').textContent; doc.setFontSize(22); doc.setTextColor(44, 62, 80); /* #2c3e50 */ doc.text("Core-Satellite Portfolio Strategy Summary", doc.internal.pageSize.width / 2, 20, { align: 'center' }); doc.setDrawColor(52, 152, 219); /* #3498db */ doc.setLineWidth(1.5); doc.line(20, 25, doc.internal.pageSize.width - 20, 25); doc.setFontSize(14); doc.setTextColor(51, 51, 51); /* #333 */ let y = 40; doc.text(`Total Investment Amount: $${totalInvestment.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`, 20, y); y += 10; doc.text(`Core Portfolio Allocation: ${corePercentage}%`, 20, y); y += 10; doc.text(`Satellite Portfolio Allocation: ${satelliteInvestmentPercentage}%`, 20, y); y += 20; doc.setFontSize(16); doc.setTextColor(44, 62, 80); /* #2c3e50 */ doc.text("Detailed Allocation", 20, y); y += 5; doc.setLineWidth(0.5); doc.line(20, y, doc.internal.pageSize.width - 20, y); y += 5; const tableData = []; const tableRows = document.querySelectorAll('#detailedAllocationTable tbody tr'); tableRows.forEach(row => { const rowData = []; row.querySelectorAll('td').forEach(cell => { rowData.push(cell.textContent); }); tableData.push(rowData); }); doc.autoTable({ head: [ ['Component', 'Allocation ($)', 'Allocation (%)', 'Expected Return (%)', 'Risk Level'] ], body: tableData, startY: y, theme: 'striped', styles: { font: 'Helvetica', fontSize: 10, cellPadding: 3, textColor: 51, lineColor: 221, lineWidth: 0.1, }, headStyles: { fillColor: [52, 152, 219], /* #3498db */ textColor: 255, fontStyle: 'bold', }, alternateRowStyles: { fillColor: [242, 242, 242], /* #f2f2f2 */ }, didDrawPage: function(data) { // Footer let pageCount = doc.internal.number; doc.setFontSize(10); doc.text('Page ' + pageCount, doc.internal.pageSize.width - 20, doc.internal.pageSize.height - 10, { align: 'right' }); } }); y = doc.autoTable.previous.finalY + 15; doc.setFontSize(14); doc.setTextColor(44, 62, 80); /* #2c3e50 */ doc.text(`Overall Portfolio Expected Annual Return: ${overallExpectedReturn}`, 20, y); y += 10; doc.text(`Overall Portfolio Risk Level: ${overallRiskLevel}`, 20, y); doc.save('Core-Satellite_Portfolio_Summary.pdf'); } // Event Listeners tabButtons.forEach(button => { button.addEventListener('click', function() { const tabId = this.dataset.tab; showTab(tabId); if (tabId === 'review-calculate') { populateReviewSummary(); } }); }); prevTabBtn.addEventListener('click', prevTab); nextTabBtn.addEventListener('click', nextTab); calculateBtn.addEventListener('click', calculatePortfolio); downloadPdfBtn.addEventListener('click', downloadPdf); // Initial tab display showTab(tabNames[0]); });