/** * HTML Report Generator * Generates comprehensive HTML reports with full trading statement */ function generateHTMLReport(strategy, index) { const m = strategy.metrics; const name = `FxMath_${String(index + 1).padStart(3, '0')}_PF${(m.profitFactor || 0).toFixed(2).replace('.', '_')}_WR${Math.round(m.winRate || 0)}`; // Generate SELL rules (inverted operators) const sellRulesHTML = strategy.rules.map((rule, i) => { const invertedOp = rule.operator === '>' ? '<=' : rule.operator === '<' ? '>=' : rule.operator === '>=' ? '<' : rule.operator === '<=' ? '>' : rule.operator; let ruleText = ''; if (rule.type === 'simple') { ruleText = `${rule.left.price.toUpperCase()}[${rule.left.shift}] ${invertedOp} ${rule.right.price.toUpperCase()}[${rule.right.shift}]`; } else { ruleText = `(${rule.left.price1.toUpperCase()}[${rule.left.shift1}] ${rule.left.op} ${rule.left.price2.toUpperCase()}[${rule.left.shift2}]) ${invertedOp} (${rule.right.price.toUpperCase()}[${rule.right.shift}] × ${rule.right.multiplier})`; } return `
${i + 1}. ${ruleText}
`; }).join(''); // Generate BUY rules const buyRulesHTML = strategy.rules.map((rule, i) => { let ruleText = ''; if (rule.type === 'simple') { ruleText = `${rule.left.price.toUpperCase()}[${rule.left.shift}] ${rule.operator} ${rule.right.price.toUpperCase()}[${rule.right.shift}]`; } else { ruleText = `(${rule.left.price1.toUpperCase()}[${rule.left.shift1}] ${rule.left.op} ${rule.left.price2.toUpperCase()}[${rule.left.shift2}]) ${rule.operator} (${rule.right.price.toUpperCase()}[${rule.right.shift}] × ${rule.right.multiplier})`; } return `
${i + 1}. ${ruleText}
`; }).join(''); // Generate trades table const tradesHTML = m.trades.map((trade, i) => { const profitClass = trade.profit > 0 ? 'profit-positive' : 'profit-negative'; const typeClass = trade.type === 'BUY' ? 'type-buy' : 'type-sell'; return ` ${i + 1} ${trade.type} ${new Date(trade.openTime).toLocaleString()} ${new Date(trade.closeTime).toLocaleString()} $${trade.entry.toFixed(2)} $${trade.exit.toFixed(2)} $${trade.profit.toFixed(2)} ${trade.reason.toUpperCase()} `; }).join(''); // Generate hourly stats table let hourlyStatsHTML = ''; if (m.hourlyStats) { hourlyStatsHTML = m.hourlyStats.map((stats, hour) => { if (stats.trades === 0) return ''; const profitClass = stats.profit > 0 ? 'profit-positive' : 'profit-negative'; return ` ${String(hour).padStart(2, '0')}:00 ${stats.trades} ${stats.wins} ${stats.losses} $${stats.profit.toFixed(2)} ${stats.trades > 0 ? ((stats.wins / stats.trades) * 100).toFixed(1) : 0}% `; }).join(''); } const html = ` ${name} - Trading Strategy Report

${name}

FxMath Quant - Automated Trading Strategy Report

Generated: ${new Date().toLocaleString()}

Performance Metrics

Profit Factor
${(m.profitFactor || 0).toFixed(2)}
Win Rate
${(m.winRate || 0).toFixed(1)}%
Total Trades
${m.totalTrades || 0}
BUY Trades
${m.buyTrades || 0}
SELL Trades
${m.sellTrades || 0}
Max Drawdown
${(m.maxDrawdown || 0).toFixed(2)}%
Total Profit
$${(m.totalProfit || 0).toFixed(2)}
Avg Win
$${(m.avgWin || 0).toFixed(2)}
Avg Loss
$${Math.abs(m.avgLoss || 0).toFixed(2)}

Equity Curve

${m.hourlyStats ? `

Hourly Performance (24h)

` : ''} ${m.bestHour && m.worstHour ? `

Time-Based Performance

Best Trading Hour

${String(m.bestHour.hour).padStart(2, '0')}:00
$${m.bestHour.profit.toFixed(2)}

Worst Trading Hour

${String(m.worstHour.hour).padStart(2, '0')}:00
$${m.worstHour.profit.toFixed(2)}
` : ''}

Strategy Rules

BUY when ALL of the following conditions are true:

${buyRulesHTML}

SELL when ALL of the following conditions are true:

${sellRulesHTML}

Parameters

ATR Period: ${strategy.atrPeriod}
SL Multiplier: ${strategy.slMultiplier.toFixed(2)}
TP Multiplier: ${strategy.tpMultiplier.toFixed(2)}
${hourlyStatsHTML ? `

Hourly Performance Analysis

${hourlyStatsHTML}
Hour Trades Wins Losses Profit/Loss Win Rate
` : ''}

Complete Trading Statement

${tradesHTML}
# Type Open Time Close Time Entry Exit Profit/Loss Exit Reason
`; return html; } // Export function window.generateHTMLReport = generateHTMLReport;