From 3c23e4ec424d25498b67ce2561d8973ff3d22e59 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Sun, 25 May 2025 00:29:21 +0300 Subject: [PATCH] better dash --- run_scalping_dashboard.py | 11 ++++--- web/dashboard.py | 69 ++++++++++++++++++++++++--------------- 2 files changed, 50 insertions(+), 30 deletions(-) diff --git a/run_scalping_dashboard.py b/run_scalping_dashboard.py index 249e288..d48114b 100644 --- a/run_scalping_dashboard.py +++ b/run_scalping_dashboard.py @@ -1,10 +1,13 @@ #!/usr/bin/env python3 """ -Scalping Dashboard Runner - 100% REAL MARKET DATA ONLY +Run Ultra-Fast Scalping Dashboard (500x Leverage) -CRITICAL: This dashboard uses EXCLUSIVELY real market data. -NO synthetic, mock, or simulated data is allowed. -All trading decisions come from real market analysis. +This script starts the custom scalping dashboard with: +- Full-width 1s ETH/USDT candlestick chart +- 3 small ETH charts: 1m, 1h, 1d +- 1 small BTC 1s chart +- Ultra-fast 100ms updates for scalping +- Real-time PnL tracking and logging """ import logging diff --git a/web/dashboard.py b/web/dashboard.py index fdf6e74..cf23b70 100644 --- a/web/dashboard.py +++ b/web/dashboard.py @@ -48,6 +48,14 @@ class TradingDashboard: self.current_prices = {} self.last_update = datetime.now() + # Trading session tracking + self.session_start = datetime.now() + self.session_trades = [] + self.session_pnl = 0.0 + self.current_position = None # {'side': 'BUY', 'price': 3456.78, 'size': 0.1, 'timestamp': datetime} + self.total_realized_pnl = 0.0 + self.total_fees = 0.0 + # Create Dash app self.app = dash.Dash(__name__, external_stylesheets=[ 'https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css', @@ -76,7 +84,7 @@ class TradingDashboard: # Auto-refresh component dcc.Interval( id='interval-component', - interval=5000, # Update every 5 seconds for better real-time feel + interval=1000, # Update every 1 second for real-time tick updates n_intervals=0 ), @@ -189,24 +197,30 @@ class TradingDashboard: symbol = self.config.symbols[0] if self.config.symbols else "ETH/USDT" try: - # Try to get fresh current price from latest data - fresh_data = self.data_provider.get_historical_data(symbol, '1m', limit=1, refresh=True) + # Try to get fresh current price from latest data - OPTIMIZED FOR SPEED + fresh_data = self.data_provider.get_historical_data(symbol, '1s', limit=5, refresh=True) if fresh_data is not None and not fresh_data.empty: current_price = float(fresh_data['close'].iloc[-1]) - logger.debug(f"Got fresh price for {symbol}: ${current_price:.2f}") + logger.debug(f"[TICK] Fresh price for {symbol}: ${current_price:.2f}") else: - # Fallback to cached data - cached_data = self.data_provider.get_historical_data(symbol, '1m', limit=1, refresh=False) - if cached_data is not None and not cached_data.empty: - base_price = float(cached_data['close'].iloc[-1]) - # Apply small realistic price movement for demo - current_price = self._simulate_price_update(symbol, base_price) - logger.debug(f"Simulated price update for {symbol}: ${current_price:.2f} (base: ${base_price:.2f})") + # Quick fallback to 1m data + fresh_data = self.data_provider.get_historical_data(symbol, '1m', limit=1, refresh=True) + if fresh_data is not None and not fresh_data.empty: + current_price = float(fresh_data['close'].iloc[-1]) + logger.debug(f"[TICK] Fresh 1m price for {symbol}: ${current_price:.2f}") else: - current_price = None - logger.warning(f"No price data available for {symbol}") + # Use cached data with simulation + cached_data = self.data_provider.get_historical_data(symbol, '1m', limit=1, refresh=False) + if cached_data is not None and not cached_data.empty: + base_price = float(cached_data['close'].iloc[-1]) + # Apply small realistic price movement for demo + current_price = self._simulate_price_update(symbol, base_price) + logger.debug(f"[SIM] Simulated price update for {symbol}: ${current_price:.2f} (base: ${base_price:.2f})") + else: + current_price = None + logger.warning(f"[ERROR] No price data available for {symbol}") except Exception as e: - logger.warning(f"Error getting price for {symbol}: {e}") + logger.warning(f"[ERROR] Error getting price for {symbol}: {e}") current_price = None # Get model performance metrics with fallback @@ -233,10 +247,12 @@ class TradingDashboard: wins += 1 # Format outputs with safe defaults and update indicators - update_time = datetime.now().strftime("%H:%M:%S") + update_time = datetime.now().strftime("%H:%M:%S.%f")[:-3] # Include milliseconds price_text = f"${current_price:.2f}" if current_price else "No Data" if current_price: - price_text += f" @ {update_time}" + # Add tick indicator and precise timestamp (no emojis to avoid Unicode issues) + tick_indicator = "[LIVE]" if (datetime.now().microsecond // 100000) % 2 else "[TICK]" # Alternating indicator + price_text += f" {tick_indicator} @ {update_time}" pnl_text = f"${total_pnl:.2f}" pnl_class = "text-success mb-1" if total_pnl >= 0 else "text-danger mb-1" win_rate_text = f"{(wins/total_trades*100):.1f}%" if total_trades > 0 else "0.0%" @@ -348,30 +364,31 @@ class TradingDashboard: for tf in timeframes_to_try: try: - # FORCE FRESH DATA on each update for real-time charts - df = self.data_provider.get_historical_data(symbol, tf, limit=200, refresh=True) + # FORCE FRESH DATA on each update for real-time charts - OPTIMIZED FOR SPEED + limit = 100 if tf == '1s' else 50 if tf == '1m' else 30 # Smaller data for faster updates + df = self.data_provider.get_historical_data(symbol, tf, limit=limit, refresh=True) if df is not None and not df.empty and len(df) > 5: actual_timeframe = tf - logger.info(f"✅ Got FRESH {len(df)} candles for {symbol} {tf}") + logger.info(f"[FRESH] Got {len(df)} candles for {symbol} {tf}") break else: - logger.warning(f"⚠️ No fresh data for {symbol} {tf}") + logger.warning(f"[WARN] No fresh data for {symbol} {tf}") except Exception as e: - logger.warning(f"⚠️ Error getting fresh {symbol} {tf} data: {e}") + logger.warning(f"[ERROR] Error getting fresh {symbol} {tf} data: {e}") continue # If still no fresh data, try cached data as fallback if df is None or df.empty: - logger.warning(f"⚠️ No fresh data, trying cached data for {symbol}") + logger.warning(f"[WARN] No fresh data, trying cached data for {symbol}") for tf in timeframes_to_try: try: df = self.data_provider.get_historical_data(symbol, tf, limit=200, refresh=False) if df is not None and not df.empty and len(df) > 5: actual_timeframe = tf - logger.info(f"✅ Got cached {len(df)} candles for {symbol} {tf}") + logger.info(f"[CACHED] Got {len(df)} candles for {symbol} {tf}") break except Exception as e: - logger.warning(f"⚠️ Error getting cached {symbol} {tf} data: {e}") + logger.warning(f"[ERROR] Error getting cached {symbol} {tf} data: {e}") continue # If still no data, create empty chart @@ -427,11 +444,11 @@ class TradingDashboard: )) # Update layout with current timestamp - current_time = datetime.now().strftime("%H:%M:%S") + current_time = datetime.now().strftime("%H:%M:%S.%f")[:-3] # Include milliseconds latest_price = df['close'].iloc[-1] if not df.empty else 0 fig.update_layout( - title=f"{symbol} Price Chart ({actual_timeframe.upper()}) - {len(df)} candles | ${latest_price:.2f} @ {current_time}", + title=f"{symbol} LIVE CHART ({actual_timeframe.upper()}) | ${latest_price:.2f} | {len(df)} candles | {current_time}", template="plotly_dark", height=400, xaxis_rangeslider_visible=False,