267 lines
11 KiB
Python
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() |