a bit of cleanup

This commit is contained in:
Dobromir Popov
2025-05-30 19:35:11 +03:00
parent c6386a3718
commit 249ec6f5a7
9 changed files with 1739 additions and 510 deletions

View File

@ -308,6 +308,32 @@ class TradingDashboard:
'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css'
])
# # Add custom CSS for model data charts
# self.app.index_string = '''
# <!DOCTYPE html>
# <html>
# <head>
# {%metas%}
# <title>{%title%}</title>
# {%favicon%}
# {%css%}
# <style>
# .tiny { font-size: 10px !important; }
# .model-data-chart .js-plotly-plot .plotly .modebar { display: none !important; }
# .model-data-chart .js-plotly-plot .plotly .svg-container { border: 1px solid #444; border-radius: 4px; }
# </style>
# </head>
# <body>
# {%app_entry%}
# <footer>
# {%config%}
# {%scripts%}
# {%renderer%}
# </footer>
# </body>
# </html>
# '''
# Setup layout and callbacks
self._setup_layout()
self._setup_callbacks()
@ -757,6 +783,46 @@ class TradingDashboard:
], className="card", style={"width": "28%", "marginLeft": "2%"}),
], className="row g-2 mb-3"),
# # Model Data Feed Charts - Small charts showing data fed to models
# html.Div([
# html.Div([
# html.Div([
# html.H6([
# html.I(className="fas fa-database me-1"),
# "Model Data Feeds"
# ], className="card-title mb-2 small"),
# html.Div([
# # Row of 4 small charts
# html.Div([
# # 1m Chart
# html.Div([
# html.P("ETH 1m OHLCV", className="text-center mb-1 tiny text-muted"),
# dcc.Graph(id="model-data-1m", style={"height": "120px"}, config={'displayModeBar': False}, className="model-data-chart")
# ], style={"width": "24%"}),
# # 1h Chart
# html.Div([
# html.P("ETH 1h OHLCV", className="text-center mb-1 tiny text-muted"),
# dcc.Graph(id="model-data-1h", style={"height": "120px"}, config={'displayModeBar': False}, className="model-data-chart")
# ], style={"width": "24%", "marginLeft": "1%"}),
# # 1d Chart
# html.Div([
# html.P("ETH 1d OHLCV", className="text-center mb-1 tiny text-muted"),
# dcc.Graph(id="model-data-1d", style={"height": "120px"}, config={'displayModeBar': False}, className="model-data-chart")
# ], style={"width": "24%", "marginLeft": "1%"}),
# # BTC Reference Chart
# html.Div([
# html.P("BTC Reference", className="text-center mb-1 tiny text-muted"),
# dcc.Graph(id="model-data-btc", style={"height": "120px"}, config={'displayModeBar': False}, className="model-data-chart")
# ], style={"width": "24%", "marginLeft": "1%"})
# ], className="d-flex")
# ])
# ], className="card-body p-2")
# ], className="card")
# ], className="mb-3"),
# Bottom row - Session performance and system status
html.Div([
@ -836,7 +902,12 @@ class TradingDashboard:
Output('closed-trades-table', 'children'),
Output('system-status-icon', 'className'),
Output('system-status-icon', 'title'),
Output('system-status-details', 'children')
Output('system-status-details', 'children'),
# Model data feed charts
# Output('model-data-1m', 'figure'),
# Output('model-data-1h', 'figure'),
# Output('model-data-1d', 'figure'),
# Output('model-data-btc', 'figure')
],
[Input('interval-component', 'n_intervals')]
)
@ -1085,7 +1156,12 @@ class TradingDashboard:
return (
price_text, pnl_text, pnl_class, fees_text, position_text, position_class, trade_count_text, portfolio_text, mexc_status,
price_chart, training_metrics, decisions_list, session_perf, closed_trades_table,
system_status['icon_class'], system_status['title'], system_status['details']
system_status['icon_class'], system_status['title'], system_status['details'],
# # Model data feed charts
# self._create_model_data_chart('ETH/USDT', '1m'),
# self._create_model_data_chart('ETH/USDT', '1h'),
# self._create_model_data_chart('ETH/USDT', '1d'),
# self._create_model_data_chart('BTC/USDT', '1s')
)
except Exception as e:
@ -1102,7 +1178,12 @@ class TradingDashboard:
[html.P("Error loading closed trades", className="text-danger")],
"fas fa-circle text-danger fa-2x",
"Error: Dashboard error - check logs",
[html.P(f"Error: {str(e)}", className="text-danger")]
[html.P(f"Error: {str(e)}", className="text-danger")],
# Model data feed charts
self._create_model_data_chart('ETH/USDT', '1m'),
self._create_model_data_chart('ETH/USDT', '1h'),
self._create_model_data_chart('ETH/USDT', '1d'),
self._create_model_data_chart('BTC/USDT', '1s')
)
# Clear history callback
@ -1561,47 +1642,9 @@ class TradingDashboard:
row=1, col=1
)
# Add losing trade markers (border only triangles)
if losing_entries_x:
# Entry markers (triangle-up for LONG, triangle-down for SHORT - border only)
fig.add_trace(
go.Scatter(
x=losing_entries_x,
y=losing_entries_y,
mode='markers',
marker=dict(
color='rgba(255, 107, 107, 0)', # Transparent fill
size=12,
symbol='triangle-up',
line=dict(color='#ff6b6b', width=2) # Red border for losing
),
name="Losing Entry",
showlegend=True,
hovertemplate="<b>LOSING ENTRY</b><br>Price: $%{y:.2f}<br>Time: %{x}<extra></extra>"
),
row=1, col=1
)
# Add losing trade markers (border only triangles) - REMOVED for cleaner UI
# Only dashed lines are sufficient for visualization
if losing_exits_x:
# Exit markers (triangle-down for LONG, triangle-up for SHORT - border only)
fig.add_trace(
go.Scatter(
x=losing_exits_x,
y=losing_exits_y,
mode='markers',
marker=dict(
color='rgba(255, 107, 107, 0)', # Transparent fill
size=12,
symbol='triangle-down',
line=dict(color='#ff6b6b', width=2) # Red border for losing
),
name="Losing Exit",
showlegend=True,
hovertemplate="<b>LOSING EXIT</b><br>Price: $%{y:.2f}<br>Time: %{x}<extra></extra>"
),
row=1, col=1
)
# Update layout with current timestamp and streaming status
current_time = datetime.now().strftime("%H:%M:%S.%f")[:-3]
latest_price = df['close'].iloc[-1] if not df.empty else 0
@ -5291,6 +5334,124 @@ class TradingDashboard:
except Exception as e:
logger.warning(f"Error queuing signal for training: {e}")
def _create_model_data_chart(self, symbol, timeframe):
"""Create a detailed model data chart for a specific symbol and timeframe"""
try:
# Determine the number of candles based on timeframe
if timeframe == '1s':
limit = 300 # Last 5 minutes of 1s data
chart_title = f"{symbol} {timeframe} Ticks"
elif timeframe == '1m':
limit = 100 # Last 100 minutes
chart_title = f"{symbol} {timeframe} OHLCV"
elif timeframe == '1h':
limit = 72 # Last 3 days
chart_title = f"{symbol} {timeframe} OHLCV"
elif timeframe == '1d':
limit = 30 # Last 30 days
chart_title = f"{symbol} {timeframe} OHLCV"
else:
limit = 50
chart_title = f"{symbol} {timeframe}"
# Get historical data for the specified timeframe
df = self.data_provider.get_historical_data(symbol, timeframe, limit=limit, refresh=True)
if df is not None and not df.empty:
# Create candlestick chart with minimal styling for small charts
fig = go.Figure()
# Add candlestick data
fig.add_trace(go.Candlestick(
x=df.index,
open=df['open'],
high=df['high'],
low=df['low'],
close=df['close'],
name=f'{symbol}',
showlegend=False,
increasing_line_color='#00ff88',
decreasing_line_color='#ff6b6b'
))
# Minimal layout for small charts
fig.update_layout(
title=dict(
text=f"{chart_title}<br><span style='font-size:8px'>({len(df)} bars)</span>",
font=dict(size=10),
x=0.5
),
template="plotly_dark",
height=120,
margin=dict(l=5, r=5, t=25, b=5),
xaxis=dict(
showgrid=False,
showticklabels=False,
fixedrange=True
),
yaxis=dict(
showgrid=False,
showticklabels=False,
fixedrange=True
),
dragmode=False,
font=dict(size=8)
)
# Add annotation showing data freshness
current_time = df.index[-1] if len(df) > 0 else datetime.now()
data_age = (datetime.now() - current_time).total_seconds() if hasattr(current_time, 'timestamp') else 0
if data_age < 60:
freshness_color = "#00ff88" # Green - fresh
freshness_text = "LIVE"
elif data_age < 300:
freshness_color = "#ffaa00" # Orange - recent
freshness_text = f"{int(data_age)}s"
else:
freshness_color = "#ff6b6b" # Red - stale
freshness_text = f"{int(data_age/60)}m"
fig.add_annotation(
x=0.95, y=0.95,
xref="paper", yref="paper",
text=freshness_text,
showarrow=False,
font=dict(color=freshness_color, size=8),
bgcolor="rgba(0,0,0,0.3)",
bordercolor=freshness_color,
borderwidth=1
)
return fig
else:
return self._create_empty_model_chart(chart_title, "No data")
except Exception as e:
logger.error(f"Error creating model data chart for {symbol} {timeframe}: {e}")
return self._create_empty_model_chart(f"{symbol} {timeframe}", f"Error: {str(e)}")
def _create_empty_model_chart(self, title, message):
"""Create an empty chart for model data feeds"""
fig = go.Figure()
fig.add_annotation(
x=0.5, y=0.5,
xref="paper", yref="paper",
text=message,
showarrow=False,
font=dict(size=10, color="#888888")
)
fig.update_layout(
title=dict(text=title, font=dict(size=10), x=0.5),
template="plotly_dark",
height=120,
margin=dict(l=5, r=5, t=25, b=5),
xaxis=dict(showgrid=False, showticklabels=False, fixedrange=True),
yaxis=dict(showgrid=False, showticklabels=False, fixedrange=True),
dragmode=False
)
return fig
def create_dashboard(data_provider: DataProvider = None, orchestrator: TradingOrchestrator = None, trading_executor: TradingExecutor = None) -> TradingDashboard:
"""Factory function to create a trading dashboard"""
return TradingDashboard(data_provider=data_provider, orchestrator=orchestrator, trading_executor=trading_executor)