From 36d4c543c38a2b799d3e529372355483bcfa9370 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 24 Jun 2025 19:33:13 +0300 Subject: [PATCH] fixes --- core/enhanced_orchestrator.py | 7 +- web/dashboard.py | 156 +++++++++++++++++++++++++++------- 2 files changed, 130 insertions(+), 33 deletions(-) diff --git a/core/enhanced_orchestrator.py b/core/enhanced_orchestrator.py index 780715e..9a084b5 100644 --- a/core/enhanced_orchestrator.py +++ b/core/enhanced_orchestrator.py @@ -170,6 +170,9 @@ class EnhancedTradingOrchestrator(TradingOrchestrator): self.williams_features = {} # Symbol -> Williams features self.symbol_correlation_matrix = {} # Pre-computed correlations + # Initialize pivot RL trainer (if available) + self.pivot_rl_trainer = None # Will be initialized if enhanced pivot training is needed + # Initialize COB Integration for real-time market microstructure # PROPERLY INITIALIZED: Create the COB integration instance synchronously try: @@ -2478,7 +2481,7 @@ class EnhancedTradingOrchestrator(TradingOrchestrator): threshold_type = "ENTRY" # For entries, check if CNN predicts favorable pivot - if hasattr(self.pivot_rl_trainer, 'williams') and self.pivot_rl_trainer.williams.cnn_model: + if hasattr(self, 'pivot_rl_trainer') and self.pivot_rl_trainer and hasattr(self.pivot_rl_trainer, 'williams') and self.pivot_rl_trainer.williams.cnn_model: try: # Get market data for CNN analysis current_price = market_state.prices.get(self.timeframes[0], 0) @@ -2524,7 +2527,7 @@ class EnhancedTradingOrchestrator(TradingOrchestrator): 'action_type': threshold_type, 'threshold_used': threshold, 'pivot_enhanced': True, - 'cnn_integrated': hasattr(self.pivot_rl_trainer, 'williams') and self.pivot_rl_trainer.williams.cnn_model is not None, + 'cnn_integrated': hasattr(self, 'pivot_rl_trainer') and self.pivot_rl_trainer and hasattr(self.pivot_rl_trainer, 'williams') and self.pivot_rl_trainer.williams.cnn_model is not None, 'timeframe_breakdown': [(tf.timeframe, tf.action, tf.confidence) for tf in best_pred.timeframe_predictions], 'market_regime': market_state.market_regime diff --git a/web/dashboard.py b/web/dashboard.py index a5eaaf9..1300a8b 100644 --- a/web/dashboard.py +++ b/web/dashboard.py @@ -841,21 +841,35 @@ class TradingDashboard: ], className="card bg-light", style={"height": "60px"}), ], style={"display": "grid", "gridTemplateColumns": "repeat(4, 1fr)", "gap": "8px", "width": "60%"}), - # Right side - Recent Signals & Executions + # Right side - Merged: Recent Signals & Model Training - 2 columns html.Div([ + # Recent Trading Signals Column (50%) html.Div([ - html.H6([ - html.I(className="fas fa-robot me-2"), - "Recent Trading Signals & Executions" - ], className="card-title mb-2"), - html.Div(id="recent-decisions", style={"height": "160px", "overflowY": "auto"}) - ], className="card-body p-2") - ], className="card", style={"width": "48%", "marginLeft": "2%"}) + html.Div([ + html.H6([ + html.I(className="fas fa-robot me-2"), + "Recent Trading Signals" + ], className="card-title mb-2"), + html.Div(id="recent-decisions", style={"height": "160px", "overflowY": "auto"}) + ], className="card-body p-2") + ], className="card", style={"width": "48%"}), + + # Model Training + COB Buckets Column (50%) + html.Div([ + html.Div([ + html.H6([ + html.I(className="fas fa-brain me-2"), + "Training Progress & COB $1 Buckets" + ], className="card-title mb-2"), + html.Div(id="training-metrics", style={"height": "160px", "overflowY": "auto"}) + ], className="card-body p-2") + ], className="card", style={"width": "48%", "marginLeft": "4%"}), + ], style={"width": "48%", "marginLeft": "2%", "display": "flex"}) ], className="d-flex mb-3"), - # Charts row - More compact + # Charts row - Now full width since training moved up html.Div([ - # Price chart - 70% width + # Price chart - Full width html.Div([ html.Div([ html.H6([ @@ -864,18 +878,7 @@ class TradingDashboard: ], className="card-title mb-2"), dcc.Graph(id="price-chart", style={"height": "400px"}) ], className="card-body p-2") - ], className="card", style={"width": "70%"}), - - # Model Training Metrics - 30% width - html.Div([ - html.Div([ - html.H6([ - html.I(className="fas fa-brain me-2"), - "Model Training Progress" - ], className="card-title mb-2"), - html.Div(id="training-metrics", style={"height": "400px", "overflowY": "auto"}) - ], className="card-body p-2") - ], className="card", style={"width": "28%", "marginLeft": "2%"}), + ], className="card", style={"width": "100%"}), ], className="row g-2 mb-3"), # CNN Model Monitoring & COB Integration - MERGED into 1 row with 4 columns @@ -6070,17 +6073,108 @@ class TradingDashboard: return self._create_empty_chart("Chart Error", "Chart temporarily unavailable") def _create_training_metrics_cached(self): - """Cached training metrics with reduced computation""" + """Enhanced training metrics with COB $1 buckets""" try: - return [ - html.H6("Training Status", className="text-success"), - html.P(f"Models Active: {len(getattr(self.model_registry, 'models', {})) if self.model_registry else 0}", - className="text-muted small"), - html.P(f"Last Update: {datetime.now().strftime('%H:%M:%S')}", - className="text-muted small") - ] - except: + content = [] + + # Training Status Section + content.append(html.H6("Training Status", className="text-success mb-2")) + content.append(html.P(f"Models Active: {len(getattr(self.model_registry, 'models', {})) if self.model_registry else 0}", + className="text-muted small")) + content.append(html.P(f"Last Update: {datetime.now().strftime('%H:%M:%S')}", + className="text-muted small")) + + # COB $1 Buckets Section + content.append(html.Hr()) + content.append(html.H6("COB $1 Buckets", className="text-info mb-2")) + + # Get COB bucket data if available + try: + if hasattr(self.orchestrator, 'cob_integration') and self.orchestrator.cob_integration: + cob_buckets = self._get_cob_dollar_buckets() + if cob_buckets: + # Show top 5 buckets by volume + for i, bucket in enumerate(cob_buckets[:5]): + price_range = f"${bucket['price']:.0f}-${bucket['price']+1:.0f}" + volume = bucket['total_volume'] + bid_pct = (bucket['bid_volume'] / volume * 100) if volume > 0 else 0 + ask_pct = (bucket['ask_volume'] / volume * 100) if volume > 0 else 0 + + content.append(html.P([ + html.Span(price_range, className="text-warning small fw-bold"), + html.Br(), + html.Span(f"Vol: ${volume:,.0f} ", className="text-muted small"), + html.Span(f"B:{bid_pct:.0f}% ", className="text-success small"), + html.Span(f"A:{ask_pct:.0f}%", className="text-danger small") + ], className="mb-1")) + else: + content.append(html.P("COB buckets loading...", className="text-muted small")) + else: + content.append(html.P("COB integration inactive", className="text-warning small")) + except Exception as e: + content.append(html.P(f"COB error: {str(e)[:30]}...", className="text-danger small")) + + return content + + except Exception as e: return [html.P("Training metrics unavailable", className="text-muted")] + + def _get_cob_dollar_buckets(self) -> List[Dict]: + """Get COB data grouped into $1 buckets""" + try: + buckets = [] + + # Get COB data for primary symbols + for symbol in ['ETH/USDT', 'BTC/USDT']: + if hasattr(self.orchestrator, 'cob_integration') and self.orchestrator.cob_integration: + try: + cob_snapshot = self.orchestrator.cob_integration.get_cob_snapshot(symbol) + if cob_snapshot: + mid_price = cob_snapshot.volume_weighted_mid + + # Create $1 buckets around mid price (±$50 range) + price_buckets = {} + for i in range(-50, 51): + bucket_price = int(mid_price) + i + price_buckets[bucket_price] = { + 'price': bucket_price, + 'bid_volume': 0, + 'ask_volume': 0, + 'total_volume': 0 + } + + # Aggregate bid data into buckets + for level in cob_snapshot.consolidated_bids: + bucket_price = int(level.price) + if bucket_price in price_buckets: + price_buckets[bucket_price]['bid_volume'] += level.total_volume_usd + price_buckets[bucket_price]['total_volume'] += level.total_volume_usd + + # Aggregate ask data into buckets + for level in cob_snapshot.consolidated_asks: + bucket_price = int(level.price) + if bucket_price in price_buckets: + price_buckets[bucket_price]['ask_volume'] += level.total_volume_usd + price_buckets[bucket_price]['total_volume'] += level.total_volume_usd + + # Convert to list and sort by volume + symbol_buckets = [bucket for bucket in price_buckets.values() if bucket['total_volume'] > 0] + symbol_buckets.sort(key=lambda x: x['total_volume'], reverse=True) + + # Add symbol info and take top buckets + for bucket in symbol_buckets[:10]: + bucket['symbol'] = symbol + buckets.append(bucket) + except Exception as e: + logger.debug(f"Error getting COB buckets for {symbol}: {e}") + + # Sort all buckets by total volume and return top 10 + buckets.sort(key=lambda x: x['total_volume'], reverse=True) + return buckets[:10] + + except Exception as e: + logger.error(f"Error creating COB dollar buckets: {e}") + return [] def _create_decisions_list_cached(self): """Cached decisions list with limited entries"""