#!/usr/bin/env python3 """ CNN Trading Dashboard - Web UI Layer This is a lightweight Dash application that provides the web interface for CNN pivot predictions. All business logic is handled by core modules. """ import logging import sys import os from datetime import datetime # Add core modules to path sys.path.append(os.path.join(os.path.dirname(__file__), '..')) import dash from dash import dcc, html, Input, Output, callback import dash_bootstrap_components as dbc from core.chart_data_provider import ChartDataProvider # Setup logging with ASCII-only output logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) class CNNTradingDashboard: """Lightweight Dash web interface for CNN trading predictions""" def __init__(self): # Initialize Dash app self.app = dash.Dash( __name__, external_stylesheets=[dbc.themes.BOOTSTRAP], title="CNN Trading Dashboard" ) # Initialize core data provider self.data_provider = ChartDataProvider() # Setup web interface self._setup_layout() self._setup_callbacks() logger.info("CNN Trading Dashboard web interface initialized") def _setup_layout(self): """Setup the web dashboard layout""" self.app.layout = dbc.Container([ # Header dbc.Row([ dbc.Col([ html.H1("CNN Trading Dashboard", className="text-center text-primary mb-2"), html.P("Real-time CNN pivot predictions for ETH/USDT trading", className="text-center text-muted mb-4") ]) ]), # Main chart dbc.Row([ dbc.Col([ dbc.Card([ dbc.CardHeader([ html.H4("Price Chart with CNN Predictions", className="mb-0") ]), dbc.CardBody([ dcc.Graph( id='main-chart', style={'height': '600px'}, config={'displayModeBar': True} ) ]) ]) ], width=12) ], className="mb-4"), # Status panels dbc.Row([ # CNN Status dbc.Col([ dbc.Card([ dbc.CardHeader([ html.H5("CNN Prediction Status", className="mb-0") ]), dbc.CardBody([ html.Div(id='cnn-status') ]) ]) ], width=4), # Pivot Detection Status dbc.Col([ dbc.Card([ dbc.CardHeader([ html.H5("Pivot Detection Status", className="mb-0") ]), dbc.CardBody([ html.Div(id='pivot-status') ]) ]) ], width=4), # Training Data Status dbc.Col([ dbc.Card([ dbc.CardHeader([ html.H5("Training Data Capture", className="mb-0") ]), dbc.CardBody([ html.Div(id='training-status') ]) ]) ], width=4) ], className="mb-4"), # System info dbc.Row([ dbc.Col([ dbc.Alert([ html.H6("Legend:", className="mb-2"), html.Ul([ html.Li("Hollow Red Circles: CNN HIGH pivot predictions"), html.Li("Hollow Green Circles: CNN LOW pivot predictions"), html.Li("Red Triangles: Actual HIGH pivots detected"), html.Li("Green Triangles: Actual LOW pivots detected"), html.Li("Circle/Triangle size indicates confidence/strength") ], className="mb-0") ], color="info", className="mb-3") ]) ]), # Auto-refresh interval dcc.Interval( id='refresh-interval', interval=5000, # Update every 5 seconds n_intervals=0 ) ], fluid=True) def _setup_callbacks(self): """Setup Dash callbacks for web interface updates""" @self.app.callback( [Output('main-chart', 'figure'), Output('cnn-status', 'children'), Output('pivot-status', 'children'), Output('training-status', 'children')], [Input('refresh-interval', 'n_intervals')] ) def update_dashboard(n_intervals): """Main callback to update all dashboard components""" try: # Simulate price update self.data_provider.simulate_price_update() # Get updated predictions and pivots predictions, pivots = self.data_provider.update_predictions_and_pivots() # Create main chart fig = self.data_provider.create_price_chart() # Add predictions and pivots to chart fig = self.data_provider.add_cnn_predictions_to_chart(fig, predictions) fig = self.data_provider.add_actual_pivots_to_chart(fig, pivots) # Get status for info panels status = self.data_provider.get_current_status() # Create status displays cnn_status = self._create_cnn_status_display(status.get('predictions', {})) pivot_status = self._create_pivot_status_display(status.get('pivots', {})) training_status = self._create_training_status_display(status.get('training', {})) return fig, cnn_status, pivot_status, training_status except Exception as e: logger.error(f"Error updating dashboard: {e}") # Return empty/default values on error return {}, "Error loading CNN status", "Error loading pivot status", "Error loading training status" def _create_cnn_status_display(self, stats: dict) -> list: """Create CNN status display components""" try: active_predictions = stats.get('active_predictions', 0) high_confidence = stats.get('high_confidence', 0) avg_confidence = stats.get('avg_confidence', 0) return [ html.P(f"Active Predictions: {active_predictions}", className="mb-1"), html.P(f"High Confidence: {high_confidence}", className="mb-1"), html.P(f"Average Confidence: {avg_confidence:.1%}", className="mb-1"), dbc.Progress( value=avg_confidence * 100, color="success" if avg_confidence > 0.7 else "warning" if avg_confidence > 0.5 else "danger", className="mb-2" ), html.Small(f"Last Update: {datetime.now().strftime('%H:%M:%S')}", className="text-muted") ] except Exception as e: logger.error(f"Error creating CNN status display: {e}") return [html.P("Error loading CNN status")] def _create_pivot_status_display(self, stats: dict) -> list: """Create pivot detection status display components""" try: total_pivots = stats.get('total_pivots', 0) high_pivots = stats.get('high_pivots', 0) low_pivots = stats.get('low_pivots', 0) confirmed = stats.get('confirmed_pivots', 0) return [ html.P(f"Total Pivots: {total_pivots}", className="mb-1"), html.P(f"HIGH Pivots: {high_pivots}", className="mb-1"), html.P(f"LOW Pivots: {low_pivots}", className="mb-1"), html.P(f"Confirmed: {confirmed}", className="mb-1"), dbc.Progress( value=(confirmed / max(total_pivots, 1)) * 100, color="success", className="mb-2" ), html.Small("Williams Market Structure", className="text-muted") ] except Exception as e: logger.error(f"Error creating pivot status display: {e}") return [html.P("Error loading pivot status")] def _create_training_status_display(self, stats: dict) -> list: """Create training data status display components""" try: captured_points = stats.get('captured_points', 0) price_accuracy = stats.get('avg_price_accuracy', 0) time_accuracy = stats.get('avg_time_accuracy', 0) return [ html.P(f"Data Points: {captured_points}", className="mb-1"), html.P(f"Price Accuracy: {price_accuracy:.1%}", className="mb-1"), html.P(f"Time Accuracy: {time_accuracy:.1%}", className="mb-1"), dbc.Progress( value=price_accuracy * 100, color="success" if price_accuracy > 0.8 else "warning" if price_accuracy > 0.6 else "danger", className="mb-2" ), html.Small("Auto-saved every 5 points", className="text-muted") ] except Exception as e: logger.error(f"Error creating training status display: {e}") return [html.P("Error loading training status")] def run(self, host='127.0.0.1', port=8050, debug=False): """Run the dashboard web server""" try: logger.info(f"Starting CNN Trading Dashboard at http://{host}:{port}") self.app.run_server(host=host, port=port, debug=debug) except Exception as e: logger.error(f"Error starting dashboard server: {e}") raise def main(): """Main entry point""" dashboard = CNNTradingDashboard() dashboard.run(debug=True) if __name__ == "__main__": main()