/** * Display Monte Carlo results in a professional modal with Chart.js visualization */ function displayMonteCarloModal(strategy, index, results) { const m = strategy.metrics; const stats = results.statistics.equity; const expectedReturn = ((stats.mean - 10000) / 10000 * 100); // Determine risk level let riskLevel, riskClass, riskEmoji, riskMessage; if (results.riskOfRuin < 5) { riskLevel = 'LOW RISK'; riskClass = 'good'; riskEmoji = '✅'; riskMessage = 'Excellent robustness. This strategy shows consistent performance across different trade sequences. Safe to trade!'; } else if (results.riskOfRuin < 15) { riskLevel = 'MODERATE RISK'; riskClass = 'warning'; riskEmoji = '⚠️'; riskMessage = 'Acceptable but monitor closely. Strategy has some variability. Consider reducing position size or using tighter risk management.'; } else { riskLevel = 'HIGH RISK'; riskClass = 'bad'; riskEmoji = '❌'; riskMessage = 'High variance. Strategy shows significant variability in outcomes. Consider avoiding or significantly reducing position size.'; } // Create modal if it doesn't exist let modal = document.getElementById('montecarlo-modal'); if (!modal) { modal = document.createElement('div'); modal.id = 'montecarlo-modal'; modal.className = 'modal'; document.body.appendChild(modal); } modal.innerHTML = ` `; modal.style.display = 'flex'; // Draw histogram after modal is visible setTimeout(() => { drawMonteCarloHistogram(results, stats); }, 100); } /** * Draw Monte Carlo histogram using Chart.js */ function drawMonteCarloHistogram(results, stats) { const canvas = document.getElementById('mc-histogram'); if (!canvas) return; const ctx = canvas.getContext('2d'); // Create histogram bins for DRAWDOWN distribution const numBins = 30; const drawdownData = results.drawdownDistribution; const min = Math.min(...drawdownData); const max = Math.max(...drawdownData); const binWidth = (max - min) / numBins; const bins = new Array(numBins).fill(0); const binLabels = []; for (let i = 0; i < numBins; i++) { binLabels.push((min + i * binWidth).toFixed(1)); } // Fill bins with drawdown data drawdownData.forEach(value => { const binIndex = Math.min(Math.floor((value - min) / binWidth), numBins - 1); bins[binIndex]++; }); // Create gradient colors based on drawdown value (GREEN = low DD, RED = high DD) const ddStats = results.statistics.drawdown; const backgroundColors = bins.map((_, i) => { const value = min + (i + 0.5) * binWidth; if (value < ddStats.percentile25) return 'rgba(72, 187, 120, 0.7)'; // Green for best 25% if (value < ddStats.percentile50) return 'rgba(56, 178, 172, 0.7)'; // Teal if (value < ddStats.percentile75) return 'rgba(237, 137, 54, 0.7)'; // Orange return 'rgba(245, 101, 101, 0.7)'; // Red for worst 25% }); new Chart(ctx, { type: 'bar', data: { labels: binLabels, datasets: [{ label: 'Frequency', data: bins, backgroundColor: backgroundColors, borderColor: backgroundColors.map(c => c.replace('0.7', '1')), borderWidth: 1 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false }, tooltip: { backgroundColor: '#1a1f3a', titleColor: '#fff', bodyColor: '#a0aec0', borderColor: '#2d3748', borderWidth: 1, callbacks: { title: function (context) { const binStart = parseFloat(context[0].label); const binEnd = binStart + binWidth; return `${binStart.toFixed(1)}% - ${binEnd.toFixed(1)}%`; }, label: function (context) { const percentage = (context.parsed.y / results.iterations * 100).toFixed(1); return `${context.parsed.y} outcomes (${percentage}%)`; } } }, annotation: { annotations: { medianLine: { type: 'line', xMin: ((ddStats.median - min) / binWidth), xMax: ((ddStats.median - min) / binWidth), borderColor: '#667eea', borderWidth: 2, borderDash: [5, 5], label: { content: 'Median', enabled: true, position: 'top' } } } } }, scales: { y: { beginAtZero: true, grid: { color: '#2d3748' }, ticks: { color: '#a0aec0' }, title: { display: true, text: 'Frequency', color: '#a0aec0' } }, x: { grid: { display: false }, ticks: { color: '#a0aec0', maxRotation: 45, minRotation: 45, autoSkip: true, maxTicksLimit: 10 }, title: { display: true, text: 'Maximum Drawdown (%)', color: '#a0aec0' } } } } }); } /** * Close Monte Carlo modal */ function closeMonteCarloModal() { const modal = document.getElementById('montecarlo-modal'); if (modal) { modal.style.display = 'none'; } } // Close modal when clicking outside window.addEventListener('click', function (event) { const modal = document.getElementById('montecarlo-modal'); if (event.target === modal) { closeMonteCarloModal(); } }); // Expose functions globally window.displayMonteCarloModal = displayMonteCarloModal; window.closeMonteCarloModal = closeMonteCarloModal;