diff --git a/web/cob_dashboard.html b/web/cob_dashboard.html index af844ba..d962d24 100644 --- a/web/cob_dashboard.html +++ b/web/cob_dashboard.html @@ -545,12 +545,16 @@ ws.onmessage = function(event) { try { const data = JSON.parse(event.data); + console.log(`🔌 WebSocket message received:`, data.type, data.symbol || 'no symbol'); if (data.type === 'cob_update') { handleCOBUpdate(data); + } else { + console.log(`🔌 Unhandled WebSocket message type:`, data.type); } } catch (error) { - console.error('Error parsing WebSocket message:', error); + console.error('❌ Error parsing WebSocket message:', error); + console.error('Raw message:', event.data); } }; @@ -580,7 +584,8 @@ } // Debug logging to understand data structure - console.log(`${symbol} COB Update:`, { + console.log(`🔄 ${symbol} COB Update:`, { + source: data.type || 'Unknown', bidsCount: (cobData.bids || []).length, asksCount: (cobData.asks || []).length, sampleBid: (cobData.bids || [])[0], @@ -588,7 +593,8 @@ stats: cobData.stats, hasOHLCV: !!cobData.ohlcv, ohlcvCount: cobData.ohlcv ? cobData.ohlcv.length : 0, - sampleOHLCV: cobData.ohlcv ? cobData.ohlcv[0] : null + sampleOHLCV: cobData.ohlcv ? cobData.ohlcv[0] : null, + ohlcvStructure: cobData.ohlcv ? Object.keys(cobData.ohlcv[0] || {}) : 'none' }); // Check if WebSocket data has insufficient depth, fetch REST data @@ -596,7 +602,7 @@ const asks = cobData.asks || []; if (bids.length <= 1 && asks.length <= 1) { - console.log(`Insufficient WS depth for ${symbol}, fetching REST data...`); + console.log(`⚠️ Insufficient WS depth for ${symbol}, fetching REST data...`); fetchRESTData(symbol); return; } @@ -604,17 +610,31 @@ currentData[symbol] = cobData; // Process OHLCV data if available - if (cobData.ohlcv && Array.isArray(cobData.ohlcv)) { + if (cobData.ohlcv && Array.isArray(cobData.ohlcv) && cobData.ohlcv.length > 0) { ohlcvData[symbol] = cobData.ohlcv; - console.log(`${symbol} OHLCV data received:`, cobData.ohlcv.length, 'candles'); + console.log(`📈 ${symbol} OHLCV data received:`, cobData.ohlcv.length, 'candles'); + + // Log first and last candle for debugging + const firstCandle = cobData.ohlcv[0]; + const lastCandle = cobData.ohlcv[cobData.ohlcv.length - 1]; + console.log(`📊 ${symbol} OHLCV range:`, { + first: firstCandle, + last: lastCandle, + priceRange: `${Math.min(...cobData.ohlcv.map(c => c.low))} - ${Math.max(...cobData.ohlcv.map(c => c.high))}` + }); // Update mini chart after order book update setTimeout(() => { const prefix = symbol === 'BTC/USDT' ? 'btc' : 'eth'; + console.log(`🎨 Drawing chart for ${prefix} with ${cobData.ohlcv.length} candles`); drawMiniChart(prefix, cobData.ohlcv); }, 100); } else { - console.log(`${symbol}: No OHLCV data in update`); + console.log(`❌ ${symbol}: No valid OHLCV data in update (${cobData.ohlcv ? cobData.ohlcv.length : 'null'} items)`); + + // Try to get OHLCV from REST endpoint + console.log(`🔍 Trying to fetch OHLCV from REST for ${symbol}...`); + fetchRESTData(symbol); } // Track imbalance for aggregation @@ -636,15 +656,28 @@ } function fetchRESTData(symbol) { + console.log(`🔍 Fetching REST data for ${symbol}...`); fetch(`/api/cob/${encodeURIComponent(symbol)}`) - .then(response => response.json()) + .then(response => { + console.log(`📡 REST response for ${symbol}:`, response.status, response.statusText); + return response.json(); + }) .then(data => { + console.log(`📦 REST data received for ${symbol}:`, { + hasData: !!data.data, + dataKeys: data.data ? Object.keys(data.data) : [], + hasOHLCV: !!(data.data && data.data.ohlcv), + ohlcvCount: data.data && data.data.ohlcv ? data.data.ohlcv.length : 0 + }); + if (data.data) { - console.log(`REST fallback data for ${symbol}:`, data.data); - handleCOBUpdate({symbol: symbol, data: data.data}); + console.log(`✅ Processing REST fallback data for ${symbol}`); + handleCOBUpdate({symbol: symbol, data: data.data, type: 'rest_api'}); + } else { + console.error(`❌ No data in REST response for ${symbol}`); } }) - .catch(error => console.error(`Error fetching REST data for ${symbol}:`, error)); + .catch(error => console.error(`❌ Error fetching REST data for ${symbol}:`, error)); } function trackImbalance(symbol, imbalance) { @@ -1028,7 +1061,7 @@ try { const canvas = document.getElementById(`${prefix}-mini-chart`); if (!canvas) { - console.log(`Canvas not found for ${prefix}-mini-chart`); + console.error(`❌ Canvas not found for ${prefix}-mini-chart`); return; } @@ -1036,10 +1069,11 @@ const width = canvas.width; const height = canvas.height; - console.log(`Drawing ${prefix} chart with ${ohlcvArray ? ohlcvArray.length : 0} candles`); + console.log(`🎨 Drawing ${prefix} chart with ${ohlcvArray ? ohlcvArray.length : 0} candles (${width}x${height})`); - // Clear canvas - ctx.clearRect(0, 0, width, height); + // Clear canvas with background + ctx.fillStyle = '#111'; + ctx.fillRect(0, 0, width, height); if (!ohlcvArray || ohlcvArray.length === 0) { // Draw "No Data" message @@ -1047,7 +1081,18 @@ ctx.font = '12px Courier New'; ctx.textAlign = 'center'; ctx.fillText('No Data', width / 2, height / 2); - console.log(`${prefix}: No OHLCV data to draw`); + console.log(`❌ ${prefix}: No OHLCV data to draw`); + return; + } + + // Validate OHLCV data structure + const firstCandle = ohlcvArray[0]; + if (!firstCandle || typeof firstCandle.open === 'undefined' || typeof firstCandle.close === 'undefined') { + console.error(`❌ ${prefix}: Invalid OHLCV data structure:`, firstCandle); + ctx.fillStyle = '#ff6b6b'; + ctx.font = '10px Courier New'; + ctx.textAlign = 'center'; + ctx.fillText('Invalid Data', width / 2, height / 2); return; } @@ -1061,7 +1106,16 @@ const maxPrice = Math.max(...prices); const priceRange = maxPrice - minPrice; - if (priceRange === 0) return; + console.log(`📊 ${prefix} price range: $${minPrice.toFixed(2)} - $${maxPrice.toFixed(2)} (range: $${priceRange.toFixed(2)})`); + + if (priceRange === 0) { + console.warn(`⚠️ ${prefix}: Zero price range, cannot draw chart`); + ctx.fillStyle = '#ff6b6b'; + ctx.font = '10px Courier New'; + ctx.textAlign = 'center'; + ctx.fillText('Zero Range', width / 2, height / 2); + return; + } // Calculate candle width and spacing const candleWidth = Math.max(1, Math.floor(width / ohlcvArray.length) - 1); @@ -1124,8 +1178,11 @@ ctx.setLineDash([]); } + console.log(`✅ Successfully drew ${prefix} chart with ${ohlcvArray.length} candles`); + } catch (error) { - console.error(`Error drawing mini chart for ${prefix}:`, error); + console.error(`❌ Error drawing mini chart for ${prefix}:`, error); + console.error(error.stack); } } diff --git a/web/cob_realtime_dashboard.py b/web/cob_realtime_dashboard.py index 1565712..ab56fdd 100644 --- a/web/cob_realtime_dashboard.py +++ b/web/cob_realtime_dashboard.py @@ -194,7 +194,11 @@ class COBDashboardServer: # Get latest data from cache or COB integration if symbol in self.latest_cob_data: - data = self.latest_cob_data[symbol] + data = self.latest_cob_data[symbol].copy() + # Add OHLCV data to REST response + if symbol in self.ohlcv_data: + data['ohlcv'] = list(self.ohlcv_data[symbol]) + logger.debug(f"REST API: Added {len(data['ohlcv'])} OHLCV candles for {symbol}") elif self.cob_integration: data = await self._generate_dashboard_data(symbol) else: