added models and cob data
This commit is contained in:
@ -3,7 +3,7 @@ Dashboard Component Manager - Clean Trading Dashboard
|
||||
Manages the formatting and creation of dashboard components
|
||||
"""
|
||||
|
||||
from dash import html
|
||||
from dash import html, dcc
|
||||
from datetime import datetime
|
||||
import logging
|
||||
|
||||
@ -208,30 +208,88 @@ class DashboardComponentManager:
|
||||
if not cob_snapshot:
|
||||
return [html.P("No COB data", className="text-muted small")]
|
||||
|
||||
# Basic COB info
|
||||
# Real COB data display
|
||||
cob_info = []
|
||||
|
||||
# Symbol and update count
|
||||
# Symbol header
|
||||
cob_info.append(html.Div([
|
||||
html.Strong(f"{symbol}", className="text-info"),
|
||||
html.Span(" - COB Snapshot", className="small text-muted")
|
||||
], className="mb-2"))
|
||||
|
||||
# Mock COB data display (since we don't have real COB structure)
|
||||
cob_info.append(html.Div([
|
||||
html.Div([
|
||||
html.I(className="fas fa-chart-bar text-success me-2"),
|
||||
html.Span("Order Book: Active", className="small")
|
||||
], className="mb-1"),
|
||||
html.Div([
|
||||
html.I(className="fas fa-coins text-warning me-2"),
|
||||
html.Span("Liquidity: Good", className="small")
|
||||
], className="mb-1"),
|
||||
html.Div([
|
||||
html.I(className="fas fa-balance-scale text-info me-2"),
|
||||
html.Span("Imbalance: Neutral", className="small")
|
||||
])
|
||||
]))
|
||||
# Check if we have a real COB snapshot object
|
||||
if hasattr(cob_snapshot, 'volume_weighted_mid'):
|
||||
# Real COB snapshot data
|
||||
mid_price = getattr(cob_snapshot, 'volume_weighted_mid', 0)
|
||||
spread_bps = getattr(cob_snapshot, 'spread_bps', 0)
|
||||
bid_liquidity = getattr(cob_snapshot, 'total_bid_liquidity', 0)
|
||||
ask_liquidity = getattr(cob_snapshot, 'total_ask_liquidity', 0)
|
||||
imbalance = getattr(cob_snapshot, 'liquidity_imbalance', 0)
|
||||
bid_levels = len(getattr(cob_snapshot, 'consolidated_bids', []))
|
||||
ask_levels = len(getattr(cob_snapshot, 'consolidated_asks', []))
|
||||
|
||||
# Price and spread
|
||||
cob_info.append(html.Div([
|
||||
html.Div([
|
||||
html.I(className="fas fa-dollar-sign text-success me-2"),
|
||||
html.Span(f"Mid: ${mid_price:.2f}", className="small fw-bold")
|
||||
], className="mb-1"),
|
||||
html.Div([
|
||||
html.I(className="fas fa-arrows-alt-h text-warning me-2"),
|
||||
html.Span(f"Spread: {spread_bps:.1f} bps", className="small")
|
||||
], className="mb-1")
|
||||
]))
|
||||
|
||||
# Liquidity info
|
||||
total_liquidity = bid_liquidity + ask_liquidity
|
||||
bid_pct = (bid_liquidity / total_liquidity * 100) if total_liquidity > 0 else 0
|
||||
ask_pct = (ask_liquidity / total_liquidity * 100) if total_liquidity > 0 else 0
|
||||
|
||||
cob_info.append(html.Div([
|
||||
html.Div([
|
||||
html.I(className="fas fa-layer-group text-info me-2"),
|
||||
html.Span(f"Liquidity: ${total_liquidity:,.0f}", className="small")
|
||||
], className="mb-1"),
|
||||
html.Div([
|
||||
html.Span(f"Bids: {bid_pct:.0f}% ", className="small text-success"),
|
||||
html.Span(f"Asks: {ask_pct:.0f}%", className="small text-danger")
|
||||
], className="mb-1")
|
||||
]))
|
||||
|
||||
# Order book depth
|
||||
cob_info.append(html.Div([
|
||||
html.Div([
|
||||
html.I(className="fas fa-list text-secondary me-2"),
|
||||
html.Span(f"Levels: {bid_levels} bids, {ask_levels} asks", className="small")
|
||||
], className="mb-1")
|
||||
]))
|
||||
|
||||
# Imbalance indicator
|
||||
imbalance_color = "text-success" if imbalance > 0.1 else "text-danger" if imbalance < -0.1 else "text-muted"
|
||||
imbalance_text = "Bid Heavy" if imbalance > 0.1 else "Ask Heavy" if imbalance < -0.1 else "Balanced"
|
||||
|
||||
cob_info.append(html.Div([
|
||||
html.I(className="fas fa-balance-scale me-2"),
|
||||
html.Span(f"Imbalance: ", className="small text-muted"),
|
||||
html.Span(f"{imbalance_text} ({imbalance:.3f})", className=f"small {imbalance_color}")
|
||||
], className="mb-1"))
|
||||
|
||||
else:
|
||||
# Fallback display for other data formats
|
||||
cob_info.append(html.Div([
|
||||
html.Div([
|
||||
html.I(className="fas fa-chart-bar text-success me-2"),
|
||||
html.Span("Order Book: Active", className="small")
|
||||
], className="mb-1"),
|
||||
html.Div([
|
||||
html.I(className="fas fa-coins text-warning me-2"),
|
||||
html.Span("Liquidity: Good", className="small")
|
||||
], className="mb-1"),
|
||||
html.Div([
|
||||
html.I(className="fas fa-balance-scale text-info me-2"),
|
||||
html.Span("Imbalance: Neutral", className="small")
|
||||
])
|
||||
]))
|
||||
|
||||
return cob_info
|
||||
|
||||
@ -240,36 +298,144 @@ class DashboardComponentManager:
|
||||
return [html.P(f"Error: {str(e)}", className="text-danger small")]
|
||||
|
||||
def format_training_metrics(self, metrics_data):
|
||||
"""Format training metrics for display"""
|
||||
"""Format training metrics for display - Enhanced with loaded models"""
|
||||
try:
|
||||
if not metrics_data or 'error' in metrics_data:
|
||||
return [html.P("No training data", className="text-muted small")]
|
||||
|
||||
metrics_info = []
|
||||
content = []
|
||||
|
||||
# CNN metrics
|
||||
if 'cnn_metrics' in metrics_data:
|
||||
cnn_data = metrics_data['cnn_metrics']
|
||||
metrics_info.append(html.Div([
|
||||
html.Strong("CNN Model", className="text-primary"),
|
||||
html.Br(),
|
||||
html.Span(f"Status: Active", className="small text-success")
|
||||
# Loaded Models Section
|
||||
if 'loaded_models' in metrics_data:
|
||||
loaded_models = metrics_data['loaded_models']
|
||||
|
||||
content.append(html.H6([
|
||||
html.I(className="fas fa-microchip me-2 text-primary"),
|
||||
"Loaded Models"
|
||||
], className="mb-2"))
|
||||
|
||||
if loaded_models:
|
||||
for model_name, model_info in loaded_models.items():
|
||||
# Model status badge
|
||||
is_active = model_info.get('active', True)
|
||||
status_class = "text-success" if is_active else "text-muted"
|
||||
status_icon = "fas fa-check-circle" if is_active else "fas fa-pause-circle"
|
||||
|
||||
# Last prediction info
|
||||
last_prediction = model_info.get('last_prediction', {})
|
||||
pred_time = last_prediction.get('timestamp', 'N/A')
|
||||
pred_action = last_prediction.get('action', 'NONE')
|
||||
pred_confidence = last_prediction.get('confidence', 0)
|
||||
|
||||
# 5MA Loss
|
||||
loss_5ma = model_info.get('loss_5ma', 0.0)
|
||||
loss_class = "text-success" if loss_5ma < 0.1 else "text-warning" if loss_5ma < 0.5 else "text-danger"
|
||||
|
||||
# Model size/parameters
|
||||
model_size = model_info.get('parameters', 0)
|
||||
if model_size > 1e9:
|
||||
size_str = f"{model_size/1e9:.1f}B"
|
||||
elif model_size > 1e6:
|
||||
size_str = f"{model_size/1e6:.1f}M"
|
||||
elif model_size > 1e3:
|
||||
size_str = f"{model_size/1e3:.1f}K"
|
||||
else:
|
||||
size_str = str(model_size)
|
||||
|
||||
# Model card
|
||||
model_card = html.Div([
|
||||
# Header with model name and toggle
|
||||
html.Div([
|
||||
html.Div([
|
||||
html.I(className=f"{status_icon} me-2 {status_class}"),
|
||||
html.Strong(f"{model_name.upper()}", className=status_class),
|
||||
html.Span(f" ({size_str} params)", className="text-muted small ms-2")
|
||||
], style={"flex": "1"}),
|
||||
|
||||
# Activation toggle (if easy to implement)
|
||||
html.Div([
|
||||
dcc.Checklist(
|
||||
id=f"toggle-{model_name}",
|
||||
options=[{"label": "", "value": "active"}],
|
||||
value=["active"] if is_active else [],
|
||||
className="form-check-input",
|
||||
style={"transform": "scale(0.8)"}
|
||||
)
|
||||
], className="form-check form-switch")
|
||||
], className="d-flex align-items-center mb-1"),
|
||||
|
||||
# Model metrics
|
||||
html.Div([
|
||||
# Last prediction
|
||||
html.Div([
|
||||
html.Span("Last: ", className="text-muted small"),
|
||||
html.Span(f"{pred_action}",
|
||||
className=f"small fw-bold {'text-success' if pred_action == 'BUY' else 'text-danger' if pred_action == 'SELL' else 'text-muted'}"),
|
||||
html.Span(f" ({pred_confidence:.1f}%)", className="text-muted small"),
|
||||
html.Span(f" @ {pred_time}", className="text-muted small")
|
||||
], className="mb-1"),
|
||||
|
||||
# 5MA Loss
|
||||
html.Div([
|
||||
html.Span("5MA Loss: ", className="text-muted small"),
|
||||
html.Span(f"{loss_5ma:.4f}", className=f"small fw-bold {loss_class}")
|
||||
])
|
||||
])
|
||||
], className="border rounded p-2 mb-2",
|
||||
style={"backgroundColor": "rgba(255,255,255,0.05)" if is_active else "rgba(128,128,128,0.1)"})
|
||||
|
||||
content.append(model_card)
|
||||
else:
|
||||
content.append(html.P("No models loaded", className="text-warning small"))
|
||||
|
||||
# RL metrics
|
||||
if 'rl_metrics' in metrics_data:
|
||||
rl_data = metrics_data['rl_metrics']
|
||||
metrics_info.append(html.Div([
|
||||
html.Strong("RL Model", className="text-warning"),
|
||||
html.Br(),
|
||||
html.Span(f"Status: Training", className="small text-info")
|
||||
# COB $1 Buckets Section
|
||||
content.append(html.Hr())
|
||||
content.append(html.H6([
|
||||
html.I(className="fas fa-layer-group me-2 text-info"),
|
||||
"COB $1 Buckets"
|
||||
], className="mb-2"))
|
||||
|
||||
if 'cob_buckets' in metrics_data:
|
||||
cob_buckets = metrics_data['cob_buckets']
|
||||
if cob_buckets:
|
||||
for i, bucket in enumerate(cob_buckets[:3]): # Top 3 buckets
|
||||
price_range = f"${bucket['price']:.0f}-${bucket['price']+1:.0f}"
|
||||
volume = bucket.get('total_volume', 0)
|
||||
bid_pct = bucket.get('bid_pct', 0)
|
||||
ask_pct = bucket.get('ask_pct', 0)
|
||||
|
||||
content.append(html.P([
|
||||
html.Span(price_range, className="text-warning small fw-bold"),
|
||||
html.Br(),
|
||||
html.Span(f"Vol: ${volume:,.0f} ", className="text-muted small"),
|
||||
html.Span(f"B:{bid_pct:.0f}% ", className="text-success small"),
|
||||
html.Span(f"A:{ask_pct:.0f}%", className="text-danger small")
|
||||
], className="mb-1"))
|
||||
else:
|
||||
content.append(html.P("COB buckets loading...", className="text-muted small"))
|
||||
else:
|
||||
content.append(html.P("COB data not available", className="text-warning small"))
|
||||
|
||||
# Training Status (if available)
|
||||
if 'training_status' in metrics_data:
|
||||
training_status = metrics_data['training_status']
|
||||
content.append(html.Hr())
|
||||
content.append(html.H6([
|
||||
html.I(className="fas fa-brain me-2 text-secondary"),
|
||||
"Training Status"
|
||||
], className="mb-2"))
|
||||
|
||||
content.append(html.P([
|
||||
html.Span("Active Sessions: ", className="text-muted small"),
|
||||
html.Span(f"{training_status.get('active_sessions', 0)}", className="text-info small fw-bold")
|
||||
], className="mb-1"))
|
||||
|
||||
content.append(html.P([
|
||||
html.Span("Last Update: ", className="text-muted small"),
|
||||
html.Span(f"{training_status.get('last_update', 'N/A')}", className="text-muted small")
|
||||
]))
|
||||
|
||||
# Default message if no metrics
|
||||
if not metrics_info:
|
||||
metrics_info.append(html.P("Training metrics not available", className="text-muted small"))
|
||||
|
||||
return metrics_info
|
||||
return content
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error formatting training metrics: {e}")
|
||||
|
Reference in New Issue
Block a user