Hedge Fund Replication Strategy Simulator (Conceptual Analyzer)

Define Target Hedge Fund/Strategy Profile

%
%

Define Replicating Portfolio Asset Classes

Add liquid asset classes for your replicating portfolio. Define their allocations (must sum to 100%) and financial assumptions.

Total Allocation: 0%

Market & Economic Assumptions

%
%
Used for conceptual replicating portfolio volatility.

Replication Analysis & Comparison

Replication analysis and comparison will appear here.

Replicating Portfolio Asset Allocation

Performance Metrics Comparison Chart

Comparison chart appears here.

Comparison chart.

'; return; } const res = hfrs_model.analysisResults; let tableHTML = `

Performance & Risk Comparison

MetricTarget (${res.target.name})Replicating PortfolioDifference
Expected Return (%)${hfrs_formatPercent(res.target.expReturn)}${hfrs_formatPercent(res.replicating.expReturn)}${hfrs_formatPercent(res.replicating.expReturn - res.target.expReturn)}
Volatility (%)${hfrs_formatPercent(res.target.volatility)}${hfrs_formatPercent(res.replicating.volatility)}${hfrs_formatPercent(res.replicating.volatility - res.target.volatility)}
Beta (to ${res.marketAssumptions.marketIndexName})${hfrs_formatDecimal(res.target.beta)}${hfrs_formatDecimal(res.replicating.beta)}${hfrs_formatDecimal(res.replicating.beta - res.target.beta)}
Sharpe Ratio${hfrs_formatDecimal(res.target.sharpe)}${hfrs_formatDecimal(res.replicating.sharpe)}${hfrs_formatDecimal(res.replicating.sharpe - res.target.sharpe)}
Conceptual Alpha (%)${hfrs_formatPercent(res.target.alpha)}${hfrs_formatPercent(res.replicating.alpha)}${hfrs_formatPercent(res.replicating.alpha - res.target.alpha)}
`; resultsSection.innerHTML = tableHTML; hfrs_renderPieChart(res.replicating.assetClasses, 'hfrs_replicatingAllocationPieChartSvg'); hfrs_renderComparisonBarChart(res, barChartContainer); const pdfBtn = document.getElementById('hfrs_downloadPdfButton'); if(pdfBtn) pdfBtn.style.display = 'block'; } function hfrs_renderPieChart(assetClasses, svgId) { /* Same as empa_renderPieChart */ const svg = hfrs_getEl(svgId); if (!svg) return; svg.innerHTML = ''; const filteredAC = assetClasses.filter(ac => (ac.allocationPercent || 0) > 0.01); if(filteredAC.length === 0) { svg.parentElement.innerHTML = '

No allocations to display.

'; return; } const boxSize = Math.min(svg.parentElement.offsetWidth, svg.parentElement.offsetHeight, 260) || 260; svg.setAttribute('viewBox', `0 0 ${boxSize} ${boxSize}`); const radius = boxSize / 2 * 0.85; const cx = boxSize / 2; const cy = boxSize / 2; let cumulativePercent = 0; filteredAC.forEach(ac => { const percent = (ac.allocationPercent || 0) / 100; const startAngle = cumulativePercent * 2 * Math.PI - Math.PI / 2; const endAngle = (cumulativePercent + percent) * 2 * Math.PI - Math.PI / 2; const x1 = cx + radius * Math.cos(startAngle); const y1 = cy + radius * Math.sin(startAngle); const x2 = cx + radius * Math.cos(endAngle); const y2 = cy + radius * Math.sin(endAngle); const largeArcFlag = percent > 0.5 ? 1 : 0; const pathData = `M ${cx},${cy} L ${x1},${y1} A ${radius},${radius} 0 ${largeArcFlag},1 ${x2},${y2} Z`; const path = document.createElementNS("http://www.w3.org/2000/svg", "path"); path.setAttribute("d", pathData); path.setAttribute("fill", ac.color || '#ccc'); path.setAttribute("stroke", "#1F2937"); path.setAttribute("stroke-width", "1"); const title = document.createElementNS("http://www.w3.org/2000/svg", "title"); title.textContent = `${ac.name}: ${ac.allocationPercent.toFixed(1)}%`; path.appendChild(title); svg.appendChild(path); cumulativePercent += percent; }); } function hfrs_renderComparisonBarChart(results, container) { /* Similar to ftpc_renderReturnVolBarChart */ container.innerHTML = ''; const svgWidth = Math.min(600, (hfrs_getEl('hfrsContainer_main').offsetWidth || 400) - 80); const svgHeight = 280; const m = {top: 20, right: 20, bottom: 70, left: 50}; // Increased bottom for longer labels const w = svgWidth - m.left - m.right; const h = svgHeight - m.top - m.bottom; const data = [ { group: 'E(Return)', target: results.target.expReturn, replicating: results.replicating.expReturn }, { group: 'Volatility', target: results.target.volatility, replicating: results.replicating.volatility }, { group: 'Beta', target: results.target.beta, replicating: results.replicating.beta }, { group: 'Sharpe', target: results.target.sharpe, replicating: results.replicating.sharpe }, { group: 'Alpha (%)', target: results.target.alpha, replicating: results.replicating.alpha } ]; const allYValues = data.flatMap(d => [d.target, d.replicating]); const yMin = Math.min(0, ...allYValues.filter(v=>!isNaN(v))); // Ensure 0 is in range if all positive const yMax = Math.max(...allYValues.filter(v=>!isNaN(v))); const numGroups = data.length; const groupWidth = w / numGroups; const barWidth = groupWidth / 3; // Width for each bar (target/replicating) const barPadding = groupWidth / 6; const xScale = i => i * groupWidth + barPadding / 2; // Start of group const yScale = y => h - ((y - yMin) / (yMax - yMin === 0 ? 1 : yMax - yMin)) * h; let chartHTML = ` {/* Zero line */} {/* Y-axis */} {/* X-axis base */} Value / Ratio ${yMax.toFixed(2)} ${yMin.toFixed(2)} ${ (yMin < 0 && yMax > 0 && yScale(0) > 0 && yScale(0) < h ) ? `0.00` : ''} `; data.forEach((d,i) => { const xPosGroup = xScale(i); // Target Bar const targetBarY = d.target >= 0 ? yScale(d.target) : yScale(0); const targetBarHeight = Math.abs(yScale(0) - yScale(d.target)); chartHTML += `Target ${d.group}: ${d.target.toFixed(2)}`; // Replicating Bar const replBarY = d.replicating >= 0 ? yScale(d.replicating) : yScale(0); const replBarHeight = Math.abs(yScale(0) - yScale(d.replicating)); chartHTML += `Replicating ${d.group}: ${d.replicating.toFixed(2)}`; // Label const labelLines = d.group.split(' '); // Split label for multi-line labelLines.forEach((line, lineIdx) => { chartHTML += `${line}`; }); }); // Legend chartHTML += ` Target Fund`; chartHTML += ` Replicating`; chartHTML += ``; container.innerHTML = chartHTML; } // --- PDF Generation --- function hfrs_downloadPDF() { if (!hfrs_model.analysisResults) { alert("Please analyze portfolio first."); return; } if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined') { alert('Core PDF library (jsPDF) is not loaded.'); console.error('jsPDF library not found.'); return; } const { jsPDF: JSPDF } = window.jspdf; const doc = new JSPDF(); if (typeof doc.autoTable !== 'function') { alert('PDF Table plugin (jsPDF-AutoTable) not loaded correctly. Tables in PDF may be missing.'); console.error('doc.autoTable is not a function.'); } let y = 15; const m = 15; const cw = doc.internal.pageSize.getWidth() - (2 * m); const res = hfrs_model.analysisResults; const inputs = res.inputsSnapshot || hfrs_model; function addLine(text, size, style = 'normal', indent = 0, spacing = 2.5) { if (y > 275) { doc.addPage(); y = m; } doc.setFontSize(size); doc.setFont(undefined, style); const lines = doc.splitTextToSize(text, cw - indent); doc.text(lines, m + indent, y); y += (lines.length * (size * 0.35)) + spacing; } addLine(`Hedge Fund Replication Strategy Analysis: ${inputs.targetProfile.name || 'N/A'}`, 16, 'bold', 0, 5); addLine(`Report Date: ${new Date().toLocaleDateString()}`, 9, 'italic', 0, 5); addLine("Market Assumptions:", 11, 'bold', 0, 3); let marketData = [ ["Market Index:", inputs.marketAssumptions.marketIndexName], ["Market Index Expected Return:", hfrs_formatPercent(inputs.marketAssumptions.marketIndexReturn*100)], ["Risk-Free Rate:", hfrs_formatPercent(inputs.marketAssumptions.riskFreeRate*100)], ["Avg. Correlation (Replicating Assets):", inputs.marketAssumptions.avgCorrelationReplicatingAssets.toFixed(2)], ]; if (typeof doc.autoTable === 'function') { doc.autoTable({startY: y, body: marketData, theme: 'plain', styles:{fontSize:9, cellPadding:1.2}, columnStyles:{0:{fontStyle:'bold'}}}); y = doc.lastAutoTable.finalY + 5; } else { marketData.forEach(row => addLine(`${row[0]} ${row[1]}`, 9)); y+=5; } addLine("Replicating Portfolio Asset Allocation:", 11, 'bold', 0, 3); const repHead = [['Asset Class', 'Alloc. (%)', 'E(R) (%)', 'Vol. (%)', 'Beta']]; const repBody = res.replicating.assetClasses.map(ac => [ac.name, (ac.allocationPercent||0).toFixed(1), (ac.expReturn||0).toFixed(1), (ac.expVolatility||0).toFixed(1), (ac.betaToMarket||0).toFixed(2)]); if (typeof doc.autoTable === 'function') { doc.autoTable({startY: y, head: repHead, body: repBody, theme: 'striped', headStyles:{fillColor:[79,70,229]}, styles:{fontSize:8.5, halign:'right'}, columnStyles:{0:{halign:'left',fontStyle:'bold'}}}); y = doc.lastAutoTable.finalY + 6; } else { addLine("Replicating portfolio table could not be generated.", 8, 'italic'); y+=5; } addLine("Performance & Risk Comparison:", 12, 'bold', 0, 4); const compHead = [['Metric', `Target (${res.target.name})`, 'Replicating Portfolio', 'Difference']]; const compBody = [ ['Expected Return (%)', hfrs_formatPercent(res.target.expReturn), hfrs_formatPercent(res.replicating.expReturn), hfrs_formatPercent(res.replicating.expReturn - res.target.expReturn)], ['Volatility (%)', hfrs_formatPercent(res.target.volatility), hfrs_formatPercent(res.replicating.volatility), hfrs_formatPercent(res.replicating.volatility - res.target.volatility)], ['Beta', hfrs_formatDecimal(res.target.beta), hfrs_formatDecimal(res.replicating.beta), hfrs_formatDecimal(res.replicating.beta - res.target.beta)], ['Sharpe Ratio', hfrs_formatDecimal(res.target.sharpe), hfrs_formatDecimal(res.replicating.sharpe), hfrs_formatDecimal(res.replicating.sharpe - res.target.sharpe)], ['Conceptual Alpha (%)', hfrs_formatPercent(res.target.alpha), hfrs_formatPercent(res.replicating.alpha), hfrs_formatPercent(res.replicating.alpha - res.target.alpha)] ]; if (typeof doc.autoTable === 'function') { doc.autoTable({startY: y, head: compHead, body: compBody, theme: 'grid', headStyles:{fillColor:[99,102,241]}, styles:{fontSize:9, halign:'right'}, columnStyles:{0:{halign:'left',fontStyle:'bold'}}}); y = doc.lastAutoTable.finalY + 7; } else { addLine("Comparison table could not be generated.", 8, 'italic'); y+=5; } addLine("Note: This is a conceptual simulator. All returns, volatilities, betas, and correlations are user-defined assumptions. It does not constitute investment advice.", 7, 'italic'); doc.save(`${(inputs.targetProfile.name || 'HedgeFundReplication').replace(/\s+/g, '_')}_Analysis.pdf`); }
Scroll to Top