// Shared JavaScript across all pages document.addEventListener('DOMContentLoaded', function() { // Initialize the log file upload functionality const logFileInput = document.getElementById('logFile'); if (logFileInput) { logFileInput.addEventListener('change', handleFileUpload); } // Sample data for demonstration updateSampleData(); }); function handleFileUpload(event) { const file = event.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = function(e) { try { const logData = JSON.parse(e.target.result); processLogData(logData); } catch (error) { console.error('Error parsing log file:', error); alert('Error parsing log file. Please check the file format.'); } }; reader.readAsText(file); } function processLogData(logData) { if (!Array.isArray(logData)) { logData = logData.split('\n').filter(line => line.trim()).map(line => { try { return JSON.parse(line); } catch { return { message: line }; } }); } console.log('Processed log data:', logData); // Here you would call functions to update the UI with the log data updateLogTable(logData); updateStats(logData); updateTradePerformance(logData); } function updateLogTable(logData) { const tableBody = document.getElementById('logTableBody'); if (!tableBody) return; // Clear existing rows tableBody.innerHTML = ''; // Add new rows logData.slice(0, 50).forEach(entry => { const row = document.createElement('tr'); row.className = 'log-entry'; if (entry.event === 'paper_buy') row.classList.add('trade-buy'); if (entry.event === 'paper_sell') row.classList.add('trade-sell'); if (entry.reason === 'TAKE_PROFIT') row.classList.add('trade-profit'); if (entry.reason === 'STOP_LOSS') row.classList.add('trade-loss'); const timeCell = document.createElement('td'); timeCell.className = 'px-6 py-4 whitespace-nowrap text-sm text-gray-500'; timeCell.textContent = entry.timestamp ? new Date(entry.timestamp).toLocaleTimeString() : '-'; const eventCell = document.createElement('td'); eventCell.className = 'px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900'; eventCell.textContent = entry.event || '-'; const symbolCell = document.createElement('td'); symbolCell.className = 'px-6 py-4 whitespace-nowrap text-sm text-gray-500'; symbolCell.textContent = entry.symbol || '-'; const detailsCell = document.createElement('td'); detailsCell.className = 'px-6 py-4 text-sm text-gray-500'; if (entry.event === 'entry_evaluation') { detailsCell.textContent = `Score: ${entry.score || '-'}, Confluence: ${entry.confluence || '-'}`; } else if (entry.event === 'position_closed') { detailsCell.textContent = `PNL: ${entry.pnl || '-'} (${entry.pnl_pct || '-'}) - ${entry.reason || ''}`; } else { detailsCell.textContent = JSON.stringify(entry, null, 2); } row.appendChild(timeCell); row.appendChild(eventCell); row.appendChild(symbolCell); row.appendChild(detailsCell); tableBody.appendChild(row); }); feather.replace(); } function updateStats(logData) { // Update statistics based on log data const entryEvaluations = logData.filter(entry => entry.event === 'entry_evaluation'); if (entryEvaluations.length > 0) { const avgScore = entryEvaluations.reduce((sum, entry) => sum + parseFloat(entry.score || 0), 0) / entryEvaluations.length; document.getElementById('scoreThreshold').textContent = entryEvaluations[0].threshold || '0.500'; document.getElementById('avgDeltaScore').textContent = avgScore.toFixed(3); const marketRegime = entryEvaluations[0].market_regime || 'UNKNOWN'; document.getElementById('marketRegime').textContent = marketRegime; const h1Trend = entryEvaluations[0].h1_trend || 'UNKNOWN'; document.getElementById('h1Trend').textContent = h1Trend; } } function updateTradePerformance(logData) { // Update trade performance metrics const trades = logData.filter(entry => entry.event === 'position_closed'); if (trades.length > 0) { const tradeStats = document.querySelector('trade-stats'); if (tradeStats) { tradeStats.setAttribute('total-trades', trades.length); const profitableTrades = trades.filter(trade => trade.pnl_pct && !trade.pnl_pct.startsWith('-')).length; tradeStats.setAttribute('win-rate', Math.round((profitableTrades / trades.length) * 100)); const totalPnl = trades.reduce((sum, trade) => { const pnl = parseFloat(trade.pnl_pct?.replace('%', '') || '0'); return sum + pnl; }, 0); tradeStats.setAttribute('avg-pnl', (totalPnl / trades.length).toFixed(2)); } } } function updateSampleData() { // For demo purposes, load sample data const sampleLogs = [ { "component": "strategy", "symbol": "BTCUSDT", "bar_time": "2025-10-23T14:30:00+00:00", "blocking_reason": "NO_SIGNAL", "score": "0.354", "threshold": "0.500", "delta_score": "-0.146", "event": "entry_evaluation", "timestamp": "2025-10-27T12:58:58.402047Z" }, { "component": "paper", "symbol": "BTCUSDT", "quantity": 0.000904, "price": 110758.52727600001, "event": "paper_buy", "timestamp": "2025-10-27T13:03:05.864671Z" }, { "symbol": "BTCUSDT", "loss": "-0.49%", "reason": "ATR_SL", "event": "stop_loss_triggered", "timestamp": "2025-10-27T13:06:00.383211Z" }, { "symbol": "BTCUSDT", "profit": "1.00%", "reason": "ATR_TP", "event": "take_profit_triggered", "timestamp": "2025-10-27T13:21:12.387101Z" } ]; processLogData(sampleLogs); }