Hedge Fund Strategy Replication Tool
Replication Parameters
Please fill in all required fields and ensure valid numerical inputs.
Replication Results
Run the replication in the Input tab to see results.
Simulated Performance Chart
Run the replication in the Input tab to generate charts.
Note: This tool provides *simulated* performance data based on generalized strategy characteristics for educational purposes. It does not reflect actual hedge fund returns or guarantee future results.
`; resultsOutput.innerHTML = tableHtml; } /** * Renders the cumulative performance chart of the simulated strategies. * @param {Object} results - Results from replicateStrategy. */ function renderChart(results) { if (!results || !results.chartData || !results.chartData.strategy || results.chartData.strategy.length === 0) { chartPlaceholder.classList.remove('hidden'); if (performanceChartInstance) { performanceChartInstance.destroy(); performanceChartInstance = null; } return; } chartPlaceholder.classList.add('hidden'); // Hide placeholder if chart can be rendered const ctx = document.getElementById('performanceChart').getContext('2d'); // Destroy existing chart instance if it exists to prevent overlap if (performanceChartInstance) { performanceChartInstance.destroy(); } performanceChartInstance = new Chart(ctx, { type: 'line', // Line chart for cumulative performance data: { labels: results.chartDates, datasets: [ { label: `${results.strategyType} (Simulated)`, data: results.chartData.strategy, borderColor: '#3B82F6', // Blue 500 backgroundColor: 'rgba(59, 130, 246, 0.2)', // Light blue fill borderWidth: 2, tension: 0.3, // Smooth curve pointRadius: 0, // Hide points fill: false, }, { label: `${results.benchmarkIndex} (Simulated)`, data: results.chartData.benchmark, borderColor: '#F59E0B', // Amber 500 backgroundColor: 'rgba(245, 158, 11, 0.2)', borderWidth: 2, tension: 0.3, pointRadius: 0, fill: false, } ] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: true, position: 'top', labels: { font: { size: 14, family: 'Inter', }, color: '#333' } }, title: { display: true, text: `Simulated Cumulative Performance (Starting with $${results.initialInvestment.toFixed(2)})`, font: { size: 18, family: 'Inter', weight: 'bold' }, color: '#1F2937' }, tooltip: { mode: 'index', intersect: false, callbacks: { label: function(context) { let label = context.dataset.label || ''; if (label) { label += ': '; } if (context.parsed.y !== null) { label += `$${parseFloat(context.parsed.y).toFixed(2)}`; } return label; }, title: function(context) { return context[0].label; // Date } } } }, scales: { y: { beginAtZero: false, title: { display: true, text: 'Cumulative Value ($)', font: { size: 14, family: 'Inter' }, color: '#333' }, ticks: { callback: function(value) { return '$' + value; }, font: { family: 'Inter' } } }, x: { title: { display: true, text: 'Date', font: { size: 14, family: 'Inter' }, color: '#333' }, ticks: { font: { family: 'Inter' } } } } } }); } /** * Handles the PDF download functionality. * Captures the results output and chart canvas to generate a PDF report. */ window.downloadPdf = async function() { // Ensure jsPDF and html2canvas libraries are loaded if (typeof html2canvas === 'undefined' || typeof jspdf === 'undefined' || typeof jspdf.jsPDF === 'undefined') { displayMessage('PDF generation libraries not loaded. Please try again or refresh.'); return; } hideMessage(); // Clear any existing messages const { jsPDF } = jspdf; const doc = new jsPDF('p', 'pt', 'a4'); // 'p' for portrait, 'pt' for points, 'a4' for A4 size // Define the elements to be captured for the PDF report const elementsToCapture = [ document.getElementById('resultsOutput'), document.getElementById('performanceChart') ]; // Create promises for capturing each element as a canvas image const promises = elementsToCapture.map(element => { // Temporarily make the element visible if it's currently hidden const wasHidden = element.classList.contains('hidden'); if (wasHidden) { element.classList.remove('hidden'); } return html2canvas(element, { scale: 2, // Increase scale for better resolution in PDF useCORS: true, // Required for images/fonts loaded from other origins if any backgroundColor: '#ffffff' // Ensure white background for captured content }).then(canvas => { // Restore hidden state if it was temporarily made visible if (wasHidden) { element.classList.add('hidden'); } return canvas; }); }); let yPos = 40; // Initial Y position for content in the PDF // Add a main title to the PDF report doc.setFontSize(22); doc.setTextColor(51, 51, 51); // Dark gray doc.text('Hedge Fund Strategy Replication Report', doc.internal.pageSize.getWidth() / 2, yPos, { align: 'center' }); yPos += 30; // Move down for next element // Add generation date doc.setFontSize(12); doc.setTextColor(100, 100, 100); // Medium gray doc.text(`Generated on: ${new Date().toLocaleDateString()}`, doc.internal.pageSize.getWidth() / 2, yPos, { align: 'center' }); yPos += 40; // Move down for next element // Iterate through the captured canvases and add them to the PDF for (const promise of promises) { try { const canvas = await promise; const imgData = canvas.toDataURL('image/png'); // Convert canvas to PNG data URL const imgWidth = 550; // Desired width for the image in the PDF (A4 is approx 595pt wide) const imgHeight = (canvas.height * imgWidth) / canvas.width; // Maintain aspect ratio // Check if the image fits on the current page. If not, add a new page. if (yPos + imgHeight > doc.internal.pageSize.getHeight() - 40) { // Check against a 40pt bottom margin doc.addPage(); // Add a new page yPos = 40; // Reset Y position for the new page } // Add the image to the PDF, centered horizontally doc.addImage(imgData, 'PNG', (doc.internal.pageSize.getWidth() - imgWidth) / 2, yPos, imgWidth, imgHeight); yPos += imgHeight + 30; // Move Y position down, adding some padding } catch (error) { console.error('Error capturing element for PDF:', error); displayMessage('Failed to generate part of the PDF. Please ensure all data is loaded.'); } } // Save the generated PDF file doc.save('Hedge_Fund_Replication_Report.pdf'); }; // Initial setup: Show the input tab and update navigation buttons when the DOM is ready showTab('input'); });