gogo2/minimal_dashboard.py
2025-05-26 16:02:40 +03:00

230 lines
8.1 KiB
Python

#!/usr/bin/env python3
"""
Minimal Scalping Dashboard - Test callback functionality without emoji issues
"""
import logging
import sys
from pathlib import Path
from datetime import datetime
import pandas as pd
import numpy as np
# Add project root to path
project_root = Path(__file__).parent
sys.path.insert(0, str(project_root))
import dash
from dash import dcc, html, Input, Output
import plotly.graph_objects as go
from core.config import setup_logging
from core.data_provider import DataProvider
# Setup logging without emojis
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
class MinimalDashboard:
"""Minimal dashboard to test callback functionality"""
def __init__(self):
self.data_provider = DataProvider()
self.app = dash.Dash(__name__)
self.chart_data = {}
# Setup layout and callbacks
self._setup_layout()
self._setup_callbacks()
logger.info("Minimal dashboard initialized")
def _setup_layout(self):
"""Setup minimal layout"""
self.app.layout = html.Div([
html.H1("Minimal Scalping Dashboard - Callback Test", className="text-center"),
# Metrics row
html.Div([
html.Div([
html.H3(id="current-time", className="text-center"),
html.P("Current Time", className="text-center")
], className="col-md-3"),
html.Div([
html.H3(id="update-counter", className="text-center"),
html.P("Update Count", className="text-center")
], className="col-md-3"),
html.Div([
html.H3(id="eth-price", className="text-center"),
html.P("ETH Price", className="text-center")
], className="col-md-3"),
html.Div([
html.H3(id="status", className="text-center"),
html.P("Status", className="text-center")
], className="col-md-3")
], className="row mb-4"),
# Chart
html.Div([
dcc.Graph(id="main-chart", style={"height": "400px"})
]),
# Fast refresh interval
dcc.Interval(
id='fast-interval',
interval=1000, # 1 second
n_intervals=0
)
], className="container-fluid")
def _setup_callbacks(self):
"""Setup callbacks with proper scoping"""
# Store reference to self for callback access
dashboard_instance = self
@self.app.callback(
[
Output('current-time', 'children'),
Output('update-counter', 'children'),
Output('eth-price', 'children'),
Output('status', 'children'),
Output('main-chart', 'figure')
],
[Input('fast-interval', 'n_intervals')]
)
def update_dashboard(n_intervals):
"""Update dashboard components"""
try:
logger.info(f"Callback triggered, interval: {n_intervals}")
# Get current time
current_time = datetime.now().strftime("%H:%M:%S")
# Update counter
counter = f"Updates: {n_intervals}"
# Try to get ETH price
try:
eth_price_data = dashboard_instance.data_provider.get_current_price('ETH/USDT')
eth_price = f"${eth_price_data:.2f}" if eth_price_data else "Loading..."
except Exception as e:
logger.warning(f"Error getting ETH price: {e}")
eth_price = "Error"
# Status
status = "Running" if n_intervals > 0 else "Starting"
# Create chart
try:
chart = dashboard_instance._create_chart(n_intervals)
except Exception as e:
logger.error(f"Error creating chart: {e}")
chart = dashboard_instance._create_error_chart()
logger.info(f"Callback returning: time={current_time}, counter={counter}, price={eth_price}")
return current_time, counter, eth_price, status, chart
except Exception as e:
logger.error(f"Error in callback: {e}")
import traceback
logger.error(f"Traceback: {traceback.format_exc()}")
# Return safe fallback values
return "Error", "Error", "Error", "Error", dashboard_instance._create_error_chart()
def _create_chart(self, n_intervals):
"""Create a simple test chart"""
try:
# Try to get real data
if n_intervals % 5 == 0: # Refresh data every 5 seconds
try:
df = self.data_provider.get_historical_data('ETH/USDT', '1m', limit=50)
if df is not None and not df.empty:
self.chart_data = df
logger.info(f"Fetched {len(df)} candles for chart")
except Exception as e:
logger.warning(f"Error fetching data: {e}")
# Create chart
fig = go.Figure()
if hasattr(self, 'chart_data') and not self.chart_data.empty:
# Real data chart
fig.add_trace(go.Candlestick(
x=self.chart_data['timestamp'],
open=self.chart_data['open'],
high=self.chart_data['high'],
low=self.chart_data['low'],
close=self.chart_data['close'],
name='ETH/USDT'
))
title = f"ETH/USDT Real Data - Update #{n_intervals}"
else:
# Mock data chart
x_data = list(range(max(0, n_intervals-20), n_intervals + 1))
y_data = [3500 + 50 * np.sin(i/5) + 10 * np.random.randn() for i in x_data]
fig.add_trace(go.Scatter(
x=x_data,
y=y_data,
mode='lines',
name='Mock ETH Price',
line=dict(color='#00ff88')
))
title = f"Mock ETH Data - Update #{n_intervals}"
fig.update_layout(
title=title,
template="plotly_dark",
paper_bgcolor='#1e1e1e',
plot_bgcolor='#1e1e1e',
showlegend=False
)
return fig
except Exception as e:
logger.error(f"Error in _create_chart: {e}")
return self._create_error_chart()
def _create_error_chart(self):
"""Create error chart"""
fig = go.Figure()
fig.add_annotation(
text="Error loading chart data",
xref="paper", yref="paper",
x=0.5, y=0.5, showarrow=False,
font=dict(size=16, color="#ff4444")
)
fig.update_layout(
template="plotly_dark",
paper_bgcolor='#1e1e1e',
plot_bgcolor='#1e1e1e'
)
return fig
def run(self, host='127.0.0.1', port=8052, debug=True):
"""Run the dashboard"""
logger.info(f"Starting minimal dashboard at http://{host}:{port}")
logger.info("This tests callback functionality without emoji issues")
self.app.run(host=host, port=port, debug=debug)
def main():
"""Main function"""
try:
dashboard = MinimalDashboard()
dashboard.run()
except KeyboardInterrupt:
logger.info("Dashboard stopped by user")
except Exception as e:
logger.error(f"Error: {e}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
main()