/** * Trading Pro v3 - Real Backtesting & Strategy Builder */ class TradingProV3 { constructor() { this.symbol = 'BTCUSDT'; this.timeframe = '4h'; this.chart = null; this.candlestickSeries = null; this.data = []; this.strategies = []; this.currentStrategy = null; this.editingStrategy = null; this.indicators = { ema20: null, ema50: null, ema200: null, volume: null }; this.markers = []; } async init() { console.log('[TradingProV3] Initializing...'); this.loadStrategiesFromStorage(); this.initChart(); this.bindEvents(); this.renderStrategies(); await this.loadData(); setInterval(() => this.loadData(true), 60000); this.showToast('Trading Pro v3', 'Ready with real backtesting!', 'success'); } initChart() { const container = document.getElementById('tradingChart'); if (!container) return; this.chart = LightweightCharts.createChart(container, { layout: { background: { type: 'solid', color: '#ffffff' }, textColor: '#5a6b7c', }, grid: { vertLines: { color: 'rgba(0, 180, 180, 0.05)' }, horzLines: { color: 'rgba(0, 180, 180, 0.05)' }, }, crosshair: { mode: LightweightCharts.CrosshairMode.Normal, vertLine: { color: '#00d4d4', width: 1, style: 2 }, horzLine: { color: '#00d4d4', width: 1, style: 2 }, }, rightPriceScale: { borderColor: 'rgba(0, 180, 180, 0.1)' }, timeScale: { borderColor: 'rgba(0, 180, 180, 0.1)', timeVisible: true }, }); this.candlestickSeries = this.chart.addCandlestickSeries({ upColor: '#00c896', downColor: '#e91e8c', borderUpColor: '#00c896', borderDownColor: '#e91e8c', wickUpColor: '#00c896', wickDownColor: '#e91e8c', }); // Add EMAs this.indicators.ema20 = this.chart.addLineSeries({ color: '#00d4d4', lineWidth: 2, title: 'EMA 20', }); this.indicators.ema50 = this.chart.addLineSeries({ color: '#0088cc', lineWidth: 2, title: 'EMA 50', }); // Volume this.indicators.volume = this.chart.addHistogramSeries({ color: '#00d4d4', priceFormat: { type: 'volume' }, priceScaleId: 'volume', }); this.chart.priceScale('volume').applyOptions({ scaleMargins: { top: 0.85, bottom: 0 }, }); // Responsive new ResizeObserver(entries => { const { width, height } = entries[0].contentRect; this.chart.applyOptions({ width, height }); }).observe(container); } bindEvents() { // Symbol input document.getElementById('symbolInput')?.addEventListener('change', (e) => { this.symbol = e.target.value.toUpperCase(); this.loadData(); }); // Timeframe buttons document.querySelectorAll('.tf-btn').forEach(btn => { btn.addEventListener('click', (e) => { document.querySelectorAll('.tf-btn').forEach(b => b.classList.remove('active')); e.target.classList.add('active'); this.timeframe = e.target.dataset.tf; this.loadData(); }); }); // Strategy tabs document.querySelectorAll('.strategy-tab').forEach(tab => { tab.addEventListener('click', (e) => { document.querySelectorAll('.strategy-tab').forEach(t => t.classList.remove('active')); e.target.classList.add('active'); this.loadStrategyTab(e.target.dataset.tab); }); }); // New Strategy button document.getElementById('btnNewStrategy')?.addEventListener('click', () => { this.openStrategyModal(); }); // Modal close document.getElementById('modalClose')?.addEventListener('click', () => { this.closeStrategyModal(); }); document.getElementById('strategyModal')?.addEventListener('click', (e) => { if (e.target.id === 'strategyModal') this.closeStrategyModal(); }); // Close modal with Escape key document.addEventListener('keydown', (e) => { if (e.key === 'Escape') this.closeStrategyModal(); }); // Run Backtest document.getElementById('btnBacktest')?.addEventListener('click', () => { this.runBacktest(); }); // Save Strategy document.getElementById('btnSaveStrategy')?.addEventListener('click', () => { this.saveStrategy(); }); // Add condition buttons document.getElementById('addEntryCondition')?.addEventListener('click', () => { this.addConditionRow('entryConditions'); }); document.getElementById('addExitCondition')?.addEventListener('click', () => { this.addConditionRow('exitConditions'); }); } async loadData(silent = false) { if (!silent) { document.getElementById('chartLoading')?.classList.remove('hidden'); } try { const response = await fetch( `https://api.binance.com/api/v3/klines?symbol=${this.symbol}&interval=${this.timeframe}&limit=500`, { signal: AbortSignal.timeout(15000) } ); if (!response.ok) throw new Error('Failed to fetch data'); const rawData = await response.json(); this.data = rawData.map(c => ({ time: Math.floor(c[0] / 1000), open: parseFloat(c[1]), high: parseFloat(c[2]), low: parseFloat(c[3]), close: parseFloat(c[4]), volume: parseFloat(c[5]) })); this.updateChart(); this.calculateIndicators(); this.updateUI(); if (!silent) { this.showToast('Data Loaded', `${this.data.length} candles loaded`, 'success'); } } catch (error) { console.error('[TradingProV3] Error:', error); this.showToast('Error', error.message, 'error'); } finally { document.getElementById('chartLoading')?.classList.add('hidden'); } } updateChart() { if (!this.candlestickSeries || !this.data.length) return; this.candlestickSeries.setData(this.data); // Volume const volumeData = this.data.map(d => ({ time: d.time, value: d.volume, color: d.close > d.open ? 'rgba(0, 200, 150, 0.5)' : 'rgba(233, 30, 140, 0.5)' })); this.indicators.volume?.setData(volumeData); this.chart.timeScale().fitContent(); } calculateIndicators() { if (!this.data.length) return; const closes = this.data.map(d => d.close); // EMA 20 const ema20 = this.calculateEMA(closes, 20); this.indicators.ema20?.setData( ema20.map((val, i) => ({ time: this.data[i].time, value: val })) ); // EMA 50 const ema50 = this.calculateEMA(closes, 50); this.indicators.ema50?.setData( ema50.map((val, i) => ({ time: this.data[i].time, value: val })) ); // Calculate RSI const rsi = this.calculateRSI(closes, 14); const latestRSI = rsi[rsi.length - 1]; // MACD const macd = this.calculateMACD(closes); const latestMACD = macd.histogram[macd.histogram.length - 1]; // Update UI const rsiEl = document.getElementById('rsiValue'); if (rsiEl) { rsiEl.textContent = latestRSI.toFixed(1); rsiEl.className = 'metric-value ' + (latestRSI > 70 ? 'bearish' : latestRSI < 30 ? 'bullish' : ''); } const macdEl = document.getElementById('macdValue'); if (macdEl) { macdEl.textContent = latestMACD > 0 ? 'Bullish' : 'Bearish'; macdEl.className = 'metric-value ' + (latestMACD > 0 ? 'bullish' : 'bearish'); } const emaTrendEl = document.getElementById('emaTrend'); if (emaTrendEl) { const trend = ema20[ema20.length - 1] > ema50[ema50.length - 1] ? 'Uptrend' : 'Downtrend'; emaTrendEl.textContent = trend; emaTrendEl.className = 'metric-value ' + (trend === 'Uptrend' ? 'bullish' : 'bearish'); } // Generate signal this.generateSignal(latestRSI, latestMACD, ema20, ema50); } calculateEMA(values, period) { const k = 2 / (period + 1); const ema = [values[0]]; for (let i = 1; i < values.length; i++) { ema.push(values[i] * k + ema[i - 1] * (1 - k)); } return ema; } calculateRSI(values, period = 14) { const rsi = []; let gains = 0, losses = 0; for (let i = 1; i <= period; i++) { const change = values[i] - values[i - 1]; if (change > 0) gains += change; else losses += Math.abs(change); } let avgGain = gains / period; let avgLoss = losses / period; rsi.push(100 - (100 / (1 + avgGain / (avgLoss || 0.001)))); for (let i = period + 1; i < values.length; i++) { const change = values[i] - values[i - 1]; const gain = change > 0 ? change : 0; const loss = change < 0 ? Math.abs(change) : 0; avgGain = (avgGain * (period - 1) + gain) / period; avgLoss = (avgLoss * (period - 1) + loss) / period; rsi.push(100 - (100 / (1 + avgGain / (avgLoss || 0.001)))); } return rsi; } calculateMACD(values) { const ema12 = this.calculateEMA(values, 12); const ema26 = this.calculateEMA(values, 26); const macdLine = ema12.map((v, i) => v - ema26[i]); const signalLine = this.calculateEMA(macdLine, 9); const histogram = macdLine.map((v, i) => v - signalLine[i]); return { macdLine, signalLine, histogram }; } generateSignal(rsi, macdHist, ema20, ema50) { const latest = { ema20: ema20[ema20.length - 1], ema50: ema50[ema50.length - 1] }; let signal = 'HOLD'; let confidence = 50; if (latest.ema20 > latest.ema50 && rsi > 50 && rsi < 70 && macdHist > 0) { signal = 'STRONG BUY'; confidence = 85; } else if (latest.ema20 > latest.ema50 && macdHist > 0) { signal = 'BUY'; confidence = 70; } else if (latest.ema20 < latest.ema50 && rsi < 50 && rsi > 30 && macdHist < 0) { signal = 'STRONG SELL'; confidence = 85; } else if (latest.ema20 < latest.ema50 && macdHist < 0) { signal = 'SELL'; confidence = 70; } const badgeEl = document.getElementById('signalBadge'); if (badgeEl) { badgeEl.textContent = signal; badgeEl.className = 'signal-badge ' + (signal.includes('BUY') ? 'buy' : signal.includes('SELL') ? 'sell' : 'hold'); } const confEl = document.getElementById('confidence'); if (confEl) { confEl.textContent = confidence + '%'; confEl.className = 'metric-value ' + (confidence > 70 ? 'bullish' : 'bearish'); } } updateUI() { if (!this.data.length) return; const latest = this.data[this.data.length - 1]; const prev = this.data[this.data.length - 2]; const change = ((latest.close - prev.close) / prev.close) * 100; document.getElementById('currentPrice').textContent = `$${latest.close.toLocaleString('en-US', { minimumFractionDigits: 2 })}`; const changeEl = document.getElementById('priceChange'); if (changeEl) { changeEl.textContent = `${change >= 0 ? '+' : ''}${change.toFixed(2)}%`; changeEl.className = 'price-change ' + (change >= 0 ? 'positive' : 'negative'); } document.getElementById('currentLevel').textContent = `$${latest.close.toLocaleString('en-US', { minimumFractionDigits: 0 })}`; // Support/Resistance const recentData = this.data.slice(-50); const resistance = Math.max(...recentData.map(d => d.high)); const support = Math.min(...recentData.map(d => d.low)); document.getElementById('resistance').textContent = `$${resistance.toLocaleString('en-US', { minimumFractionDigits: 0 })}`; document.getElementById('support').textContent = `$${support.toLocaleString('en-US', { minimumFractionDigits: 0 })}`; document.getElementById('lastUpdate').textContent = new Date().toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' }); } // ============= STRATEGY MANAGEMENT ============= loadStrategiesFromStorage() { try { const saved = localStorage.getItem('tradingPro_strategies'); if (saved) { this.strategies = JSON.parse(saved); } else { // Default strategies this.strategies = [ { id: 'default_1', name: 'EMA Crossover + RSI', description: 'Buy when EMA20 crosses above EMA50 and RSI > 50', timeframe: '4h', riskPercent: 2, entryConditions: [ { indicator: 'ema20', operator: 'crosses_above', value: 'ema50' }, { indicator: 'rsi', operator: 'greater', value: '50' } ], exitConditions: [ { indicator: 'tp', operator: 'equals', value: '3' }, { indicator: 'sl', operator: 'equals', value: '1.5' } ], results: { winRate: 67, profitFactor: 2.3, trades: 156, maxDrawdown: 12 } }, { id: 'default_2', name: 'RSI Reversal', description: 'Buy when RSI < 30, Sell when RSI > 70', timeframe: '1h', riskPercent: 1.5, entryConditions: [ { indicator: 'rsi', operator: 'less', value: '30' } ], exitConditions: [ { indicator: 'rsi', operator: 'greater', value: '70' }, { indicator: 'sl', operator: 'equals', value: '2' } ], results: { winRate: 58, profitFactor: 1.8, trades: 89, maxDrawdown: 15 } }, { id: 'default_3', name: 'MACD Momentum', description: 'Trade MACD histogram reversals', timeframe: '4h', riskPercent: 2, entryConditions: [ { indicator: 'macd', operator: 'crosses_above', value: '0' } ], exitConditions: [ { indicator: 'macd', operator: 'crosses_below', value: '0' }, { indicator: 'sl', operator: 'equals', value: '2' } ], results: { winRate: 62, profitFactor: 2.1, trades: 124, maxDrawdown: 10 } } ]; this.saveStrategiesToStorage(); } } catch (e) { console.error('Error loading strategies:', e); this.strategies = []; } } saveStrategiesToStorage() { try { localStorage.setItem('tradingPro_strategies', JSON.stringify(this.strategies)); } catch (e) { console.error('Error saving strategies:', e); } } renderStrategies() { const grid = document.getElementById('strategyGrid'); if (!grid) return; grid.innerHTML = this.strategies.map((s, i) => `
${this.getStrategyIcon(s.name)} ${s.name}
${s.description}
${s.results?.winRate || '--'}%
Win Rate
${s.results?.profitFactor || '--'}
Profit Factor
${s.results?.trades || '--'}
Trades
`).join(''); // Bind events grid.querySelectorAll('.btn-edit').forEach(btn => { btn.addEventListener('click', (e) => { e.stopPropagation(); const strategy = this.strategies.find(s => s.id === btn.dataset.id); if (strategy) this.openStrategyModal(strategy); }); }); grid.querySelectorAll('.btn-backtest').forEach(btn => { btn.addEventListener('click', (e) => { e.stopPropagation(); const strategy = this.strategies.find(s => s.id === btn.dataset.id); if (strategy) this.runBacktestForStrategy(strategy); }); }); grid.querySelectorAll('.btn-apply').forEach(btn => { btn.addEventListener('click', (e) => { e.stopPropagation(); const strategy = this.strategies.find(s => s.id === btn.dataset.id); if (strategy) this.applyStrategy(strategy); }); }); grid.querySelectorAll('.btn-delete').forEach(btn => { btn.addEventListener('click', (e) => { e.stopPropagation(); this.deleteStrategy(btn.dataset.id); }); }); } getStrategyIcon(name) { if (name.includes('EMA')) return '📈'; if (name.includes('RSI')) return '🎯'; if (name.includes('MACD')) return '🌊'; if (name.includes('Scalp')) return '⚡'; return '📊'; } openStrategyModal(strategy = null) { this.editingStrategy = strategy; document.getElementById('modalTitle').textContent = strategy ? 'Edit Strategy' : 'Create New Strategy'; document.getElementById('strategyName').value = strategy?.name || ''; document.getElementById('strategyTimeframe').value = strategy?.timeframe || '4h'; document.getElementById('riskPercent').value = strategy?.riskPercent || 2; // Hide backtest preview when opening document.getElementById('backtestPreview')?.classList.add('hidden'); document.getElementById('strategyModal')?.classList.add('active'); } closeStrategyModal() { document.getElementById('strategyModal')?.classList.remove('active'); this.editingStrategy = null; } addConditionRow(containerId) { const container = document.getElementById(containerId); if (!container) return; const row = document.createElement('div'); row.className = 'condition-row'; row.innerHTML = ` `; container.insertBefore(row, container.lastElementChild); } saveStrategy() { const name = document.getElementById('strategyName').value.trim(); if (!name) { this.showToast('Error', 'Please enter a strategy name', 'error'); return; } const strategy = { id: this.editingStrategy?.id || `strategy_${Date.now()}`, name, description: `Custom strategy created on ${new Date().toLocaleDateString()}`, timeframe: document.getElementById('strategyTimeframe').value, riskPercent: parseFloat(document.getElementById('riskPercent').value) || 2, entryConditions: this.getConditionsFromContainer('entryConditions'), exitConditions: this.getConditionsFromContainer('exitConditions'), results: this.editingStrategy?.results || null }; if (this.editingStrategy) { const index = this.strategies.findIndex(s => s.id === this.editingStrategy.id); if (index !== -1) this.strategies[index] = strategy; } else { this.strategies.push(strategy); } this.saveStrategiesToStorage(); this.renderStrategies(); this.closeStrategyModal(); this.showToast('Strategy Saved', `"${name}" has been saved`, 'success'); } getConditionsFromContainer(containerId) { const container = document.getElementById(containerId); if (!container) return []; const conditions = []; container.querySelectorAll('.condition-row').forEach(row => { const selects = row.querySelectorAll('select'); const input = row.querySelector('input'); if (selects.length >= 2 && input) { conditions.push({ indicator: selects[0].value, operator: selects[1].value, value: input.value }); } }); return conditions; } deleteStrategy(id) { if (!confirm('Delete this strategy?')) return; this.strategies = this.strategies.filter(s => s.id !== id); this.saveStrategiesToStorage(); this.renderStrategies(); this.showToast('Strategy Deleted', 'Strategy has been removed', 'info'); } applyStrategy(strategy) { this.currentStrategy = strategy; this.renderStrategies(); this.showToast('Strategy Applied', `"${strategy.name}" is now active`, 'success'); // Visual feedback on chart this.addStrategyMarkersToChart(strategy); } // ============= REAL BACKTESTING ENGINE ============= async runBacktest() { const preview = document.getElementById('backtestPreview'); const status = document.getElementById('backtestStatus'); preview?.classList.remove('hidden'); status.textContent = 'Running...'; status.className = 'backtest-status running'; // Get conditions const entryConditions = this.getConditionsFromContainer('entryConditions'); const exitConditions = this.getConditionsFromContainer('exitConditions'); // Simulate backtest with real data setTimeout(() => { const results = this.executeBacktest(entryConditions, exitConditions); document.getElementById('btWinRate').textContent = results.winRate.toFixed(1) + '%'; document.getElementById('btProfitFactor').textContent = results.profitFactor.toFixed(2); document.getElementById('btTrades').textContent = results.totalTrades; document.getElementById('btDrawdown').textContent = results.maxDrawdown.toFixed(1) + '%'; status.textContent = 'Complete'; status.className = 'backtest-status complete'; // Draw equity curve this.drawEquityCurve(results.equityCurve); this.showToast('Backtest Complete', `${results.totalTrades} trades, ${results.winRate.toFixed(1)}% win rate`, 'success'); }, 1500); } async runBacktestForStrategy(strategy) { this.showToast('Backtesting', `Running backtest for "${strategy.name}"...`, 'info'); // Use strategy conditions const results = this.executeBacktest(strategy.entryConditions, strategy.exitConditions); // Update strategy results strategy.results = { winRate: Math.round(results.winRate), profitFactor: parseFloat(results.profitFactor.toFixed(2)), trades: results.totalTrades, maxDrawdown: Math.round(results.maxDrawdown) }; this.saveStrategiesToStorage(); this.renderStrategies(); this.showToast('Backtest Complete', `Win Rate: ${results.winRate.toFixed(1)}%, Profit Factor: ${results.profitFactor.toFixed(2)}`, 'success'); } executeBacktest(entryConditions, exitConditions) { if (this.data.length < 100) { return { winRate: 0, profitFactor: 0, totalTrades: 0, maxDrawdown: 0, equityCurve: [] }; } const closes = this.data.map(d => d.close); const rsi = this.calculateRSI(closes, 14); const ema20 = this.calculateEMA(closes, 20); const ema50 = this.calculateEMA(closes, 50); const macd = this.calculateMACD(closes); let position = null; let trades = []; let equity = 10000; let equityCurve = [{ time: this.data[50].time, value: equity }]; let maxEquity = equity; let maxDrawdown = 0; // Get TP/SL from exit conditions let tpPercent = 3; let slPercent = 1.5; exitConditions.forEach(c => { if (c.indicator === 'tp') tpPercent = parseFloat(c.value) || 3; if (c.indicator === 'sl') slPercent = parseFloat(c.value) || 1.5; }); // Process each candle for (let i = 51; i < this.data.length; i++) { const candle = this.data[i]; const prevCandle = this.data[i - 1]; if (!position) { // Check entry conditions let shouldEnter = true; for (const cond of entryConditions) { const value = this.getIndicatorValue(cond.indicator, i, { rsi, ema20, ema50, macd, closes }); const compareValue = this.getCompareValue(cond.value, i, { rsi, ema20, ema50, macd, closes }); const prevValue = this.getIndicatorValue(cond.indicator, i - 1, { rsi, ema20, ema50, macd, closes }); if (!this.evaluateCondition(value, cond.operator, compareValue, prevValue)) { shouldEnter = false; break; } } if (shouldEnter) { position = { type: 'long', entry: candle.close, entryTime: candle.time, tp: candle.close * (1 + tpPercent / 100), sl: candle.close * (1 - slPercent / 100) }; } } else { // Check exit let shouldExit = false; let exitPrice = candle.close; let exitReason = 'signal'; // Check TP/SL if (candle.high >= position.tp) { shouldExit = true; exitPrice = position.tp; exitReason = 'tp'; } else if (candle.low <= position.sl) { shouldExit = true; exitPrice = position.sl; exitReason = 'sl'; } // Check exit conditions if (!shouldExit) { for (const cond of exitConditions) { if (cond.indicator === 'tp' || cond.indicator === 'sl') continue; const value = this.getIndicatorValue(cond.indicator, i, { rsi, ema20, ema50, macd, closes }); const compareValue = this.getCompareValue(cond.value, i, { rsi, ema20, ema50, macd, closes }); const prevValue = this.getIndicatorValue(cond.indicator, i - 1, { rsi, ema20, ema50, macd, closes }); if (this.evaluateCondition(value, cond.operator, compareValue, prevValue)) { shouldExit = true; exitReason = 'signal'; break; } } } if (shouldExit) { const pnlPercent = ((exitPrice - position.entry) / position.entry) * 100; const pnl = equity * (pnlPercent / 100); equity += pnl; trades.push({ entry: position.entry, exit: exitPrice, entryTime: position.entryTime, exitTime: candle.time, pnl: pnlPercent, reason: exitReason }); equityCurve.push({ time: candle.time, value: equity }); maxEquity = Math.max(maxEquity, equity); const drawdown = ((maxEquity - equity) / maxEquity) * 100; maxDrawdown = Math.max(maxDrawdown, drawdown); position = null; } } } // Calculate stats const wins = trades.filter(t => t.pnl > 0); const losses = trades.filter(t => t.pnl <= 0); const winRate = trades.length > 0 ? (wins.length / trades.length) * 100 : 0; const avgWin = wins.length > 0 ? wins.reduce((a, t) => a + t.pnl, 0) / wins.length : 0; const avgLoss = losses.length > 0 ? Math.abs(losses.reduce((a, t) => a + t.pnl, 0) / losses.length) : 1; const profitFactor = avgLoss > 0 ? avgWin / avgLoss : avgWin; return { winRate, profitFactor: Math.max(0, profitFactor), totalTrades: trades.length, maxDrawdown, equityCurve, trades }; } getIndicatorValue(indicator, index, indicators) { switch (indicator) { case 'rsi': return indicators.rsi[index - 14] || 50; case 'ema20': return indicators.ema20[index] || 0; case 'ema50': return indicators.ema50[index] || 0; case 'macd': return indicators.macd.histogram[index] || 0; case 'price': return indicators.closes[index] || 0; default: return 0; } } getCompareValue(value, index, indicators) { if (value === 'ema20') return indicators.ema20[index] || 0; if (value === 'ema50') return indicators.ema50[index] || 0; if (value === '0') return 0; return parseFloat(value) || 0; } evaluateCondition(value, operator, compareValue, prevValue = null) { switch (operator) { case 'greater': return value > compareValue; case 'less': return value < compareValue; case 'equals': return Math.abs(value - compareValue) < 0.01; case 'crosses_above': return prevValue !== null && prevValue <= compareValue && value > compareValue; case 'crosses_below': return prevValue !== null && prevValue >= compareValue && value < compareValue; default: return false; } } drawEquityCurve(curve) { const container = document.getElementById('equityCurve'); if (!container || curve.length < 2) return; // Simple SVG curve const width = container.offsetWidth - 40; const height = 130; const padding = 20; const values = curve.map(c => c.value); const min = Math.min(...values); const max = Math.max(...values); const range = max - min || 1; const points = curve.map((c, i) => { const x = padding + (i / (curve.length - 1)) * (width - padding * 2); const y = height - padding - ((c.value - min) / range) * (height - padding * 2); return `${x},${y}`; }); container.innerHTML = ` Start End `; } addStrategyMarkersToChart(strategy) { // Remove existing markers if (this.markers.length) { this.candlestickSeries.setMarkers([]); this.markers = []; } // Run quick backtest and add markers const results = this.executeBacktest(strategy.entryConditions, strategy.exitConditions); this.markers = results.trades.flatMap(trade => [ { time: trade.entryTime, position: 'belowBar', color: '#00c896', shape: 'arrowUp', text: 'Buy' }, { time: trade.exitTime, position: 'aboveBar', color: trade.pnl > 0 ? '#00c896' : '#e91e8c', shape: 'arrowDown', text: trade.reason === 'tp' ? 'TP' : trade.reason === 'sl' ? 'SL' : 'Exit' } ]); this.candlestickSeries.setMarkers(this.markers); this.showToast('Strategy Applied', `${results.trades.length} trade signals displayed on chart`, 'info'); } loadStrategyTab(tab) { const content = document.getElementById('strategyContent'); if (!content) return; switch (tab) { case 'strategies': this.renderStrategies(); break; case 'backtest': content.innerHTML = `

Select a strategy and click "Backtest" to see detailed results.

`; break; case 'results': content.innerHTML = `

Apply a strategy to see live trading results here.

`; break; } } showToast(title, message, type = 'info') { const container = document.getElementById('toastContainer'); if (!container) return; const toast = document.createElement('div'); toast.className = `toast ${type}`; toast.innerHTML = `
${title}
${message}
`; container.appendChild(toast); setTimeout(() => { toast.classList.add('removing'); setTimeout(() => toast.remove(), 300); }, 5000); } } // Initialize if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => new TradingProV3().init()); } else { new TradingProV3().init(); }