Sovereign Wealth Fund Risk & Return Forecasting Model

Sovereign Wealth Fund Risk & Return Forecasting Model

Project fund performance and analyze sensitivity to key drivers over time. This is a deterministic model based on expected values and simplified risk metrics.

1. Enter Fund Details & Investment Assumptions

General Fund Information

Enter a positive value for contribution, negative for withdrawal.

Commonly 95% or 99%. Higher means more extreme potential loss.

Asset Allocation & Expected Performance (Base Case)

Allocation percentages must sum to 100%.

Total Allocation: 100.0%

Run sensitivity analysis to see results.

'; // Reset to the first tab openTab('inputs'); hideMessage(); } /** * Downloads the Sovereign Wealth Fund analysis as a PDF. */ function downloadPDF() { if (!window.swfAnalysisResults) { showMessage('Please perform the analysis first.', 'info'); return; } const { jsPDF } = window.jspdf; const pdf = new jsPDF('l', 'mm', 'a4'); // 'l' for landscape, 'mm', 'a4' size (better for wide tables) const BLACK_COLOR = [31, 41, 55]; // Tailwind gray-900 equivalent const BLUE_HEADER_COLOR = [29, 78, 216]; // Tailwind blue-700 equivalent let y = 15; // Y-coordinate for placing content // Title pdf.setFontSize(22); pdf.setFont('helvetica', 'bold'); pdf.setTextColor(BLACK_COLOR[0], BLACK_COLOR[1], BLACK_COLOR[2]); pdf.text('Sovereign Wealth Fund Risk & Return Report', 148, y, { align: 'center' }); // Centered for landscape y += 15; // --- 1. Input Parameters & Base Case Assumptions Section --- pdf.setFontSize(16); pdf.setFont('helvetica', 'bold'); pdf.text('1. Input Parameters & Base Case Assumptions', 15, y); y += 8; const inputs = window.swfAnalysisResults.inputs; const inputData = [ ['Initial AUM', formatCurrency(inputs.initialAum)], ['Projection Years', inputs.projectionYears], ['Annual Net Contribution / (Withdrawal)', formatCurrency(inputs.annualContribution)], ['Annual Inflation Rate', formatPercentage(inputs.inflationRate)], ['Risk-Free Rate', formatPercentage(inputs.riskFreeRate)], ['VaR Confidence Level', `${inputs.varConfidenceLevel}%`], ['Portfolio Expected Return (Derived)', formatPercentage(inputs.portfolioExpectedReturn)], ['Portfolio Volatility (Derived)', formatPercentage(inputs.portfolioVolatility)], ]; pdf.autoTable({ startY: y, head: [['Parameter', 'Value']], body: inputData, theme: 'grid', styles: { fontSize: 8, cellPadding: 2, overflow: 'linebreak', lineColor: 200, lineWidth: 0.1 }, headStyles: { fillColor: BLUE_HEADER_COLOR, textColor: 255, fontStyle: 'bold' }, margin: { left: 15, right: 15 }, columnStyles: { 0: { cellWidth: 100 }, 1: { cellWidth: 'auto' } } }); y = pdf.autoTable.previous.finalY + 10; // Asset Class Details Table pdf.setFontSize(14); pdf.setFont('helvetica', 'bold'); pdf.text('Asset Class Allocation & Performance:', 15, y); y += 7; const assetData = [ ['Asset Class', 'Allocation (%)', 'Expected Return (%)', 'Volatility (%)'], ['Public Equities', (inputs.allocations.equities * 100).toFixed(1), (inputs.returns.equities * 100).toFixed(1), (inputs.volatilities.equities * 100).toFixed(1)], ['Fixed Income', (inputs.allocations.fixedIncome * 100).toFixed(1), (inputs.returns.fixedIncome * 100).toFixed(1), (inputs.volatilities.fixedIncome * 100).toFixed(1)], ['Real Estate', (inputs.allocations.realEstate * 100).toFixed(1), (inputs.returns.realEstate * 100).toFixed(1), (inputs.volatilities.realEstate * 100).toFixed(1)], ['Private Equity/Alts', (inputs.allocations.alternatives * 100).toFixed(1), (inputs.returns.alternatives * 100).toFixed(1), (inputs.volatilities.alternatives * 100).toFixed(1)], ]; pdf.autoTable({ startY: y, head: [assetData[0]], body: assetData.slice(1), theme: 'grid', styles: { fontSize: 8, cellPadding: 2, overflow: 'linebreak', lineColor: 200, lineWidth: 0.1 }, headStyles: { fillColor: BLUE_HEADER_COLOR, textColor: 255, fontStyle: 'bold' }, margin: { left: 15, right: 15 }, columnStyles: { 0: { cellWidth: 50 }, 1: { cellWidth: 40, halign: 'right' }, 2: { cellWidth: 40, halign: 'right' }, 3: { cellWidth: 40, halign: 'right' } } }); y = pdf.autoTable.previous.finalY + 15; // --- 2. Base Case Projections Section --- const baseCaseData = window.swfAnalysisResults.baseCaseProjections; const addBaseCaseTable = (data, startY) => { if (startY + 30 + (data.length * 7) > pdf.internal.pageSize.height - 15) { pdf.addPage('l', 'a4'); startY = 15; } pdf.setFontSize(16); pdf.setFont('helvetica', 'bold'); pdf.text('2. Base Case Fund Projections', 15, startY); startY += 8; const headers = [ 'Year', 'Starting AUM', 'Net Contribution', 'Investment Return', 'Ending AUM', 'Annual Return (Nominal)', 'Annual Return (Real)', 'Cumulative Return (Nominal)', 'Cumulative Return (Real)', 'Portfolio Volatility', `VaR (${inputs.varConfidenceLevel}%)` ]; const tableBody = data.map(yearData => [ yearData.year, { content: formatCurrency(yearData.startingAUM), styles: { halign: 'right' } }, { content: formatCurrency(yearData.netContribution), styles: { halign: 'right' } }, { content: formatCurrency(yearData.investmentReturn), styles: { halign: 'right' } }, { content: formatCurrency(yearData.endingAUM), styles: { halign: 'right', fontStyle: 'bold' } }, { content: yearData.annualReturnNominal !== null ? formatPercentage(yearData.annualReturnNominal) : 'N/A', styles: { halign: 'right' } }, { content: yearData.annualReturnReal !== null ? formatPercentage(yearData.annualReturnReal) : 'N/A', styles: { halign: 'right' } }, { content: yearData.cumulativeReturnNominal !== null ? formatPercentage(yearData.cumulativeReturnNominal) : 'N/A', styles: { halign: 'right' } }, { content: yearData.cumulativeReturnReal !== null ? formatPercentage(yearData.cumulativeReturnReal) : 'N/A', styles: { halign: 'right' } }, { content: yearData.portfolioVolatility !== null ? formatPercentage(yearData.portfolioVolatility) : 'N/A', styles: { halign: 'right' } }, { content: yearData.varValue !== null ? formatPercentage(yearData.varValue) : 'N/A', styles: { halign: 'right' } } ]); pdf.autoTable({ startY: startY, head: [headers], body: tableBody, theme: 'grid', styles: { fontSize: 6, cellPadding: 1.5, overflow: 'linebreak', lineColor: 200, lineWidth: 0.1 }, headStyles: { fillColor: BLUE_HEADER_COLOR, textColor: 255, fontStyle: 'bold' }, margin: { left: 15, right: 15 }, columnStyles: { 0: { cellWidth: 10 }, 1: { cellWidth: 25 }, 2: { cellWidth: 25 }, 3: { cellWidth: 25 }, 4: { cellWidth: 25 }, 5: { cellWidth: 20 }, 6: { cellWidth: 20 }, 7: { cellWidth: 20 }, 8: { cellWidth: 20 }, 9: { cellWidth: 20 }, 10: { cellWidth: 20 } } }); return pdf.autoTable.previous.finalY + 15; }; y = addBaseCaseTable(baseCaseData, y); // --- 3. Sensitivity Analysis Section --- const sensitivityAnalysis = window.swfAnalysisResults.sensitivityAnalysis; for (const variable in sensitivityAnalysis) { // Determine display name and format function let displayVarName = ''; let formatFunc = formatPercentage; // Default for rates/percentages if (variable === 'portfolioReturn') { displayVarName = 'Overall Portfolio Expected Return (%)'; } else if (variable === 'annualContribution') { displayVarName = 'Annual Net Contribution ($)'; formatFunc = formatCurrency; // Override for currency } else if (variable === 'inflationRate') { displayVarName = 'Annual Inflation Rate (%)'; } else if (variable === 'publicEquitiesReturn') { displayVarName = 'Public Equities Expected Return (%)'; } else if (variable === 'fixedIncomeReturn') { displayVarName = 'Fixed Income Expected Return (%)'; } else if (variable === 'realEstateReturn') { displayVarName = 'Real Estate Expected Return (%)'; } else if (variable === 'alternativesReturn') { displayVarName = 'Private Equity/Alts Expected Return (%)'; } if (y + 30 + (sensitivityAnalysis[variable].length * 7) > pdf.internal.pageSize.height - 15) { pdf.addPage('l', 'a4'); y = 15; } pdf.setFontSize(16); pdf.setFont('helvetica', 'bold'); pdf.text(`3. Sensitivity to ${displayVarName}`, 15, y); y += 8; const headers = [displayVarName, 'Total Ending AUM']; const tableBody = sensitivityAnalysis[variable].map(scenario => { const formattedValue = formatFunc(scenario.value / (variable.includes('Return') || variable.includes('Rate') ? 100 : 1)); return [formattedValue, { content: formatCurrency(scenario.endingAUM), styles: { halign: 'right' } }]; }); pdf.autoTable({ startY: y, head: [headers], body: tableBody, theme: 'grid', styles: { fontSize: 8, cellPadding: 2, overflow: 'linebreak', lineColor: 200, lineWidth: 0.1 }, headStyles: { fillColor: BLUE_HEADER_COLOR, textColor: 255, fontStyle: 'bold' }, margin: { left: 15, right: 15 }, columnStyles: { 0: { cellWidth: 100 }, 1: { cellWidth: 'auto' } } }); y = pdf.autoTable.previous.finalY + 10; } pdf.save('SWF_Risk_Return_Forecast_Report.pdf'); } /** * Initializes DOM element references once the document is fully loaded. */ document.addEventListener('DOMContentLoaded', () => { // General Fund Information Inputs initialAumInput = document.getElementById('initialAum'); projectionYearsInput = document.getElementById('projectionYears'); annualContributionInput = document.getElementById('annualContribution'); inflationRateInput = document.getElementById('inflationRate'); riskFreeRateInput = document.getElementById('riskFreeRate'); varConfidenceLevelInput = document.getElementById('varConfidenceLevel'); // Asset Allocation & Expected Performance Inputs allocEquitiesInput = document.getElementById('allocEquities'); retEquitiesInput = document.getElementById('retEquities'); volEquitiesInput = document.getElementById('volEquities'); allocFixedIncomeInput = document.getElementById('allocFixedIncome'); retFixedIncomeInput = document.getElementById('retFixedIncome'); volFixedIncomeInput = document.getElementById('volFixedIncome'); allocRealEstateInput = document.getElementById('allocRealEstate'); retRealEstateInput = document.getElementById('retRealEstate'); volRealEstateInput = document.getElementById('volRealEstate'); allocAlternativesInput = document.getElementById('allocAlternatives'); retAlternativesInput = document.getElementById('retAlternatives'); volAlternativesInput = document.getElementById('volAlternatives'); totalAllocationValueSpan = document.getElementById('totalAllocationValue'); // Add event listeners for allocation inputs to update total sum document.querySelectorAll('#assetAllocationInputs input[id^="alloc"]').forEach(input => { input.addEventListener('input', updateTotalAllocation); }); updateTotalAllocation(); // Initial call to set the sum on load // Sensitivity Variables Inputs sensitivityVariableSelect = document.getElementById('sensitivityVariable'); sensMinInput = document.getElementById('sensMin'); sensMaxInput = document.getElementById('sensMax'); sensStepInput = document.getElementById('sensStep'); // Output Elements baseCaseOutputDiv = document.getElementById('baseCaseOutput'); sensitivityOutputDiv = document.getElementById('sensitivityOutput'); messageBox = document.getElementById('messageBox'); // Initialize navigation button states updateNavigationButtons(); });
Scroll to Top