Files
gogo2/web/cnn_dashboard.py
2025-06-13 11:48:03 +03:00

267 lines
11 KiB
Python

#!/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()