771 lines
38 KiB
Python
771 lines
38 KiB
Python
"""
|
|
Dashboard Layout Manager - Clean Trading Dashboard
|
|
Manages the layout and structure of the trading dashboard
|
|
"""
|
|
|
|
import dash
|
|
from dash import dcc, html
|
|
from datetime import datetime
|
|
|
|
class DashboardLayoutManager:
|
|
"""Manages dashboard layout and structure"""
|
|
|
|
def __init__(self, starting_balance: float = 100.0, trading_executor=None, dashboard=None):
|
|
self.starting_balance = starting_balance
|
|
self.trading_executor = trading_executor
|
|
self.dashboard = dashboard
|
|
|
|
def create_main_layout(self):
|
|
"""Create the main dashboard layout"""
|
|
return html.Div([
|
|
self._create_header(),
|
|
self._create_main_content(),
|
|
self._create_interval_component()
|
|
], className="container-fluid bg-dark text-light min-vh-100")
|
|
|
|
def _create_prediction_tracking_section(self):
|
|
"""Create prediction tracking and model performance section"""
|
|
return html.Div([
|
|
html.Div([
|
|
html.Div([
|
|
html.H6([
|
|
html.I(className="fas fa-brain me-2"),
|
|
"🧠 Model Predictions & Performance Tracking"
|
|
], className="text-light mb-3"),
|
|
|
|
# Summary cards row - Enhanced with real metrics
|
|
html.Div([
|
|
html.Div([
|
|
html.Div([
|
|
html.H6("0", id="total-predictions-count", className="mb-0 text-primary"),
|
|
html.Small("Recent Signals", className="text-light"),
|
|
html.Small("", id="predictions-trend", className="d-block text-xs text-muted")
|
|
], className="card-body text-center p-2 bg-dark")
|
|
], className="card col-md-3 mx-1 bg-dark border-secondary"),
|
|
|
|
html.Div([
|
|
html.Div([
|
|
html.H6("0", id="active-models-count", className="mb-0 text-info"),
|
|
html.Small("Loaded Models", className="text-light"),
|
|
html.Small("", id="models-status", className="d-block text-xs text-success")
|
|
], className="card-body text-center p-2 bg-dark")
|
|
], className="card col-md-3 mx-1 bg-dark border-secondary"),
|
|
|
|
html.Div([
|
|
html.Div([
|
|
html.H6("0.00", id="avg-confidence", className="mb-0 text-warning"),
|
|
html.Small("Avg Confidence", className="text-light"),
|
|
html.Small("", id="confidence-trend", className="d-block text-xs text-muted")
|
|
], className="card-body text-center p-2 bg-dark")
|
|
], className="card col-md-3 mx-1 bg-dark border-secondary"),
|
|
|
|
html.Div([
|
|
html.Div([
|
|
html.H6("+0.00", id="total-rewards-sum", className="mb-0 text-success"),
|
|
html.Small("Total Rewards", className="text-light"),
|
|
html.Small("", id="rewards-trend", className="d-block text-xs text-muted")
|
|
], className="card-body text-center p-2 bg-dark")
|
|
], className="card col-md-3 mx-1 bg-dark border-secondary")
|
|
], className="row mb-3"),
|
|
|
|
# Charts row
|
|
html.Div([
|
|
html.Div([
|
|
html.H6("Recent Predictions Timeline", className="mb-2 text-light"),
|
|
dcc.Graph(id="prediction-timeline-chart", style={"height": "300px"})
|
|
], className="col-md-6"),
|
|
|
|
html.Div([
|
|
html.H6("Model Performance", className="mb-2 text-light"),
|
|
dcc.Graph(id="model-performance-chart", style={"height": "300px"})
|
|
], className="col-md-6")
|
|
], className="row")
|
|
|
|
], className="p-3")
|
|
], className="card bg-dark border-secondary mb-3")
|
|
], className="mt-3")
|
|
|
|
def _create_backtest_training_panel(self):
|
|
"""Create the backtest training control panel"""
|
|
return html.Div([
|
|
html.Div([
|
|
html.Div([
|
|
html.H6([
|
|
html.I(className="fas fa-robot me-2"),
|
|
"🤖 Backtest Training Control"
|
|
], className="text-light mb-3"),
|
|
|
|
# Control buttons
|
|
html.Div([
|
|
html.Div([
|
|
html.Label("Training Control", className="text-light small"),
|
|
html.Div([
|
|
html.Button(
|
|
"Start Training",
|
|
id="backtest-start-training-btn",
|
|
className="btn btn-success btn-sm me-2"
|
|
),
|
|
html.Button(
|
|
"Stop Training",
|
|
id="backtest-stop-training-btn",
|
|
className="btn btn-danger btn-sm me-2"
|
|
),
|
|
html.Button(
|
|
"Run Backtest",
|
|
id="backtest-run-backtest-btn",
|
|
className="btn btn-primary btn-sm"
|
|
)
|
|
], className="btn-group")
|
|
], className="col-md-6"),
|
|
|
|
html.Div([
|
|
html.Label("Backtest Data Window (hours)", className="text-light small"),
|
|
dcc.Slider(
|
|
id="backtest-training-duration-slider",
|
|
min=6,
|
|
max=72,
|
|
step=6,
|
|
value=24,
|
|
marks={i: f"{i}h" for i in range(0, 73, 12)},
|
|
className="mt-2"
|
|
),
|
|
html.Small("Uses N hours of data, tests predictions for each minute in first N-1 hours", className="text-muted")
|
|
], className="col-md-6")
|
|
], className="row mb-3"),
|
|
|
|
# Status display
|
|
html.Div([
|
|
html.Div([
|
|
html.Label("Training Status", className="text-light small"),
|
|
html.Div(id="backtest-training-status", children=[
|
|
html.Span("Inactive", style={"color": "red"})
|
|
], className="h5")
|
|
], className="col-md-3"),
|
|
|
|
html.Div([
|
|
html.Label("Current Accuracy", className="text-light small"),
|
|
html.H5(id="backtest-current-accuracy", children="0.00%", className="text-info")
|
|
], className="col-md-3"),
|
|
|
|
html.Div([
|
|
html.Label("Training Cycles", className="text-light small"),
|
|
html.H5(id="backtest-training-cycles", children="0", className="text-warning")
|
|
], className="col-md-3"),
|
|
|
|
html.Div([
|
|
html.Label("GPU/NPU Status", className="text-light small"),
|
|
html.Div(id="backtest-gpu-status", children=[
|
|
html.Span("Checking...", style={"color": "orange"})
|
|
], className="h5")
|
|
], className="col-md-3")
|
|
], className="row mb-3"),
|
|
|
|
# Progress and charts
|
|
html.Div([
|
|
html.Div([
|
|
html.Label("Training Progress", className="text-light small"),
|
|
html.Div([
|
|
html.Div(
|
|
id="backtest-training-progress-bar",
|
|
style={
|
|
"width": "0%",
|
|
"height": "20px",
|
|
"backgroundColor": "#007bff",
|
|
"borderRadius": "4px",
|
|
"transition": "width 0.3s ease"
|
|
}
|
|
)
|
|
], style={
|
|
"width": "100%",
|
|
"height": "20px",
|
|
"backgroundColor": "#374151",
|
|
"borderRadius": "4px",
|
|
"marginBottom": "8px"
|
|
}),
|
|
html.Div(id="backtest-progress-text", children="Ready to start", className="text-muted small")
|
|
], className="col-md-6"),
|
|
|
|
html.Div([
|
|
html.Label("Accuracy Trend", className="text-light small"),
|
|
dcc.Graph(
|
|
id="backtest-accuracy-chart",
|
|
style={"height": "150px"},
|
|
config={"displayModeBar": False}
|
|
)
|
|
], className="col-md-6")
|
|
], className="row"),
|
|
|
|
# Mini Candlestick Chart and Best Predictions
|
|
html.Div([
|
|
html.Div([
|
|
html.Label("Mini Candlestick Chart", className="text-light small"),
|
|
dcc.Graph(
|
|
id="backtest-candlestick-chart",
|
|
style={"height": "200px"},
|
|
config={"displayModeBar": False}
|
|
)
|
|
], className="col-md-6"),
|
|
|
|
html.Div([
|
|
html.Label("Best Predictions", className="text-light small"),
|
|
html.Div(
|
|
id="backtest-best-predictions",
|
|
style={
|
|
"height": "200px",
|
|
"overflowY": "auto",
|
|
"backgroundColor": "#1f2937",
|
|
"borderRadius": "8px",
|
|
"padding": "10px"
|
|
},
|
|
children=[html.Div("No predictions yet", className="text-muted small")]
|
|
)
|
|
], className="col-md-6")
|
|
], className="row mb-3"),
|
|
|
|
# Model status
|
|
html.Div([
|
|
html.Label("Active Models", className="text-light small mt-2"),
|
|
html.Div(id="backtest-model-status", children="Initializing...", className="text-muted small")
|
|
], className="mt-2")
|
|
|
|
], className="p-3")
|
|
], className="card bg-dark border-secondary mb-3")
|
|
], className="mt-3")
|
|
|
|
def _create_header(self):
|
|
"""Create the dashboard header"""
|
|
trading_mode = "SIMULATION" if (not self.trading_executor or
|
|
getattr(self.trading_executor, 'simulation_mode', True)) else "LIVE"
|
|
|
|
return html.Div([
|
|
html.H2([
|
|
html.I(className="fas fa-chart-line me-2"),
|
|
"Clean Trading Dashboard"
|
|
], className="text-light mb-0"),
|
|
html.P(
|
|
f"Ultra-Fast Updates • Live Account Balance Sync • {trading_mode}",
|
|
className="text-light mb-0 opacity-75 small"
|
|
)
|
|
], className="bg-dark p-2 mb-2")
|
|
|
|
def _create_chained_inference_status(self):
|
|
"""Create chained inference status display"""
|
|
return html.Div([
|
|
html.H6("🔗 Chained Inference Status", className="text-warning mb-1"),
|
|
html.Div(id="chained-inference-status", className="text-light small", children="Initializing...")
|
|
], className="bg-dark p-2 mb-2")
|
|
|
|
def _create_interval_component(self):
|
|
"""Create the interval component for auto-refresh"""
|
|
return dcc.Interval(
|
|
id='interval-component',
|
|
interval=2000, # Update every 2 seconds
|
|
n_intervals=0
|
|
)
|
|
|
|
def _create_main_content(self):
|
|
"""Create the main content area"""
|
|
return html.Div([
|
|
self._create_metrics_and_signals_row(),
|
|
self._create_charts_row(),
|
|
self._create_cob_and_trades_row(),
|
|
self._create_backtest_training_panel()
|
|
])
|
|
|
|
def _create_metrics_and_signals_row(self):
|
|
"""Create the top row with key metrics, recent signals, and session controls"""
|
|
return html.Div([
|
|
# Left side - Key metrics (compact cards)
|
|
self._create_metrics_grid(),
|
|
# Middle - Recent Signals
|
|
self._create_signals_panel(),
|
|
# Right side - Session Controls
|
|
self._create_session_controls_panel()
|
|
], className="d-flex mb-3")
|
|
|
|
def _create_metrics_grid(self):
|
|
"""Create the metrics grid with compact cards"""
|
|
# Get exchange name dynamically
|
|
exchange_name = "Exchange"
|
|
if self.trading_executor:
|
|
if hasattr(self.trading_executor, 'primary_name'):
|
|
exchange_name = self.trading_executor.primary_name.upper()
|
|
elif hasattr(self.trading_executor, 'exchange') and self.trading_executor.exchange:
|
|
# Try to get exchange name from exchange interface
|
|
exchange_class_name = self.trading_executor.exchange.__class__.__name__
|
|
if 'Bybit' in exchange_class_name:
|
|
exchange_name = "BYBIT"
|
|
elif 'Mexc' in exchange_class_name or 'MEXC' in exchange_class_name:
|
|
exchange_name = "MEXC"
|
|
elif 'Binance' in exchange_class_name:
|
|
exchange_name = "BINANCE"
|
|
elif 'Deribit' in exchange_class_name:
|
|
exchange_name = "DERIBIT"
|
|
else:
|
|
exchange_name = "EXCHANGE"
|
|
|
|
metrics_cards = [
|
|
("current-price", "Live Price", "text-success"),
|
|
("session-pnl", "Session P&L", ""),
|
|
("current-position", "Position", "text-info"),
|
|
# ("leverage-info", "Leverage", "text-primary"),
|
|
("trade-count", "Trades", "text-warning"),
|
|
("portfolio-value", "Portfolio", "text-secondary"),
|
|
("profitability-multiplier", "Profit Boost", "text-primary"),
|
|
("cob-websocket-status", "COB WebSocket", "text-warning"),
|
|
("mexc-status", f"{exchange_name} API", "text-info")
|
|
]
|
|
|
|
cards = []
|
|
for card_id, label, text_class in metrics_cards:
|
|
card = html.Div([
|
|
html.Div([
|
|
html.H5(id=card_id, className=f"{text_class} mb-0 small"),
|
|
html.P(label, className="text-muted mb-0 tiny")
|
|
], className="card-body text-center p-2")
|
|
], className="card", style={
|
|
"height": "60px",
|
|
"backgroundColor": "#1f2937",
|
|
"border": "1px solid #374151",
|
|
"color": "#f8f9fa"
|
|
})
|
|
cards.append(card)
|
|
|
|
return html.Div(
|
|
cards,
|
|
style={
|
|
"display": "grid",
|
|
"gridTemplateColumns": "repeat(4, 1fr)",
|
|
"gap": "8px",
|
|
"width": "60%"
|
|
}
|
|
)
|
|
|
|
def _create_signals_panel(self):
|
|
"""Create the signals panel"""
|
|
return html.Div([
|
|
html.Div([
|
|
html.Div([
|
|
html.H6([
|
|
html.I(className="fas fa-robot me-2"),
|
|
"Recent Trading Signals"
|
|
], className="card-title mb-2"),
|
|
html.Div(id="recent-decisions", style={"height": "160px", "overflowY": "auto"})
|
|
], className="card-body p-2")
|
|
], className="card")
|
|
], style={"width": "35%", "marginLeft": "2%"})
|
|
|
|
def _create_session_controls_panel(self):
|
|
"""Create the session controls panel"""
|
|
return html.Div([
|
|
html.Div([
|
|
html.Div([
|
|
html.H6([
|
|
html.I(className="fas fa-cog me-2"),
|
|
"Session Controls"
|
|
], className="card-title mb-2"),
|
|
|
|
# Trading Agent Mode Toggle
|
|
html.Div([
|
|
html.Label([
|
|
html.I(className="fas fa-robot me-1"),
|
|
"Trading Agent: ",
|
|
html.Span(
|
|
id="trading-mode-display",
|
|
children="LIVE" if getattr(self.dashboard, 'trading_mode_live', False) else "SIM",
|
|
className="fw-bold text-danger" if getattr(self.dashboard, 'trading_mode_live', False) else "fw-bold text-warning"
|
|
)
|
|
], className="form-label small mb-1"),
|
|
dcc.Checklist(
|
|
id='trading-mode-switch',
|
|
options=[{'label': '', 'value': 'live'}],
|
|
value=['live'] if getattr(self.dashboard, 'trading_mode_live', False) else [],
|
|
className="form-check-input"
|
|
),
|
|
html.Small("SIM = Simulation Mode, LIVE = Real Trading", className="text-muted d-block")
|
|
], className="mb-2"),
|
|
|
|
# Cold Start Training Toggle
|
|
html.Div([
|
|
html.Label([
|
|
html.I(className="fas fa-fire me-1"),
|
|
"Cold Start Training: ",
|
|
html.Span(
|
|
id="cold-start-display",
|
|
children="ON" if getattr(self.dashboard, 'cold_start_enabled', True) else "OFF",
|
|
className="fw-bold text-success" if getattr(self.dashboard, 'cold_start_enabled', True) else "fw-bold text-secondary"
|
|
)
|
|
], className="form-label small mb-1"),
|
|
dcc.Checklist(
|
|
id='cold-start-switch',
|
|
options=[{'label': '', 'value': 'enabled'}],
|
|
value=['enabled'] if getattr(self.dashboard, 'cold_start_enabled', True) else [],
|
|
className="form-check-input"
|
|
),
|
|
html.Small("Excessive training during cold start", className="text-muted d-block")
|
|
], className="mb-2"),
|
|
|
|
html.Hr(className="my-2"),
|
|
|
|
# Leverage Control
|
|
html.Div([
|
|
html.Label([
|
|
html.I(className="fas fa-compass me-1"),
|
|
"Show Pivot Points: ",
|
|
html.Span(id="pivots-display", children="ON", className="fw-bold text-success")
|
|
], className="form-label small mb-1"),
|
|
dcc.Checklist(
|
|
id='show-pivots-switch',
|
|
options=[{'label': '', 'value': 'enabled'}],
|
|
value=['enabled'],
|
|
className="form-check-input"
|
|
),
|
|
html.Small("Toggle pivot overlays on the chart", className="text-muted d-block")
|
|
], className="mb-2"),
|
|
|
|
html.Div([
|
|
html.Label([
|
|
html.I(className="fas fa-sliders-h me-1"),
|
|
"Leverage: ",
|
|
html.Span(id="leverage-display", children="x50", className="fw-bold text-primary")
|
|
], className="form-label small mb-1"),
|
|
dcc.Slider(
|
|
id='leverage-slider',
|
|
min=1,
|
|
max=100,
|
|
step=1,
|
|
value=50,
|
|
marks={
|
|
1: {'label': 'x1', 'style': {'fontSize': '8px'}},
|
|
25: {'label': 'x25', 'style': {'fontSize': '8px'}},
|
|
50: {'label': 'x50', 'style': {'fontSize': '8px'}},
|
|
75: {'label': 'x75', 'style': {'fontSize': '8px'}},
|
|
100: {'label': 'x100', 'style': {'fontSize': '8px'}}
|
|
},
|
|
tooltip={"placement": "bottom", "always_visible": False}
|
|
)
|
|
], className="mb-2"),
|
|
# Training Controls
|
|
html.Div([
|
|
html.Label([
|
|
html.I(className="fas fa-play me-1"),
|
|
"Training Controls"
|
|
], className="form-label small mb-1"),
|
|
html.Div([
|
|
html.Button([
|
|
html.I(className="fas fa-play me-1"),
|
|
"Start Training"
|
|
], id="start-training-btn", className="btn btn-success btn-sm me-2",
|
|
style={"fontSize": "10px", "padding": "2px 8px"}),
|
|
html.Button([
|
|
html.I(className="fas fa-stop me-1"),
|
|
"Stop Training"
|
|
], id="stop-training-btn", className="btn btn-danger btn-sm",
|
|
style={"fontSize": "10px", "padding": "2px 8px"})
|
|
], className="d-flex align-items-center mb-1"),
|
|
html.Div([
|
|
html.Span("Training:", className="small me-1"),
|
|
html.Span(id="training-status", children="Starting...", className="badge bg-primary small")
|
|
])
|
|
], className="mb-2"),
|
|
|
|
# Entry Aggressiveness Control
|
|
html.Div([
|
|
html.Label([
|
|
html.I(className="fas fa-bullseye me-1"),
|
|
"Entry Aggressiveness: ",
|
|
html.Span(id="entry-agg-display", children="0.5", className="fw-bold text-success")
|
|
], className="form-label small mb-1"),
|
|
dcc.Slider(
|
|
id='entry-aggressiveness-slider',
|
|
min=0.0,
|
|
max=1.0,
|
|
step=0.1,
|
|
value=0.5,
|
|
marks={
|
|
0.0: {'label': 'Conservative', 'style': {'fontSize': '7px'}},
|
|
0.5: {'label': 'Balanced', 'style': {'fontSize': '7px'}},
|
|
1.0: {'label': 'Aggressive', 'style': {'fontSize': '7px'}}
|
|
},
|
|
tooltip={"placement": "bottom", "always_visible": False}
|
|
)
|
|
], className="mb-2"),
|
|
|
|
# Exit Aggressiveness Control
|
|
html.Div([
|
|
html.Label([
|
|
html.I(className="fas fa-sign-out-alt me-1"),
|
|
"Exit Aggressiveness: ",
|
|
html.Span(id="exit-agg-display", children="0.5", className="fw-bold text-danger")
|
|
], className="form-label small mb-1"),
|
|
dcc.Slider(
|
|
id='exit-aggressiveness-slider',
|
|
min=0.0,
|
|
max=1.0,
|
|
step=0.1,
|
|
value=0.5,
|
|
marks={
|
|
0.0: {'label': 'Conservative', 'style': {'fontSize': '7px'}},
|
|
0.5: {'label': 'Balanced', 'style': {'fontSize': '7px'}},
|
|
1.0: {'label': 'Aggressive', 'style': {'fontSize': '7px'}}
|
|
},
|
|
tooltip={"placement": "bottom", "always_visible": False}
|
|
)
|
|
], className="mb-2"),
|
|
|
|
html.Button([
|
|
html.I(className="fas fa-trash me-1"),
|
|
"Clear Session"
|
|
], id="clear-session-btn", className="btn btn-warning btn-sm w-100"),
|
|
html.Button([
|
|
html.I(className="fas fa-save me-1"),
|
|
"Store All Models"
|
|
], id="store-models-btn", className="btn btn-info btn-sm w-100 mt-2"),
|
|
html.Button([
|
|
html.I(className="fas fa-arrows-rotate me-1"),
|
|
"Sync Positions/Orders"
|
|
], id="manual-sync-btn", className="btn btn-primary btn-sm w-100 mt-2"),
|
|
|
|
# Text Export Controls
|
|
html.Hr(className="my-2"),
|
|
html.Small("Text Export & LLM", className="text-muted d-block mb-1"),
|
|
html.Div([
|
|
html.Button([
|
|
html.I(className="fas fa-file-export me-1"),
|
|
"Start Text Export"
|
|
], id="start-text-export-btn", className="btn btn-success btn-sm me-1", style={"fontSize": "10px"}),
|
|
html.Button([
|
|
html.I(className="fas fa-stop me-1"),
|
|
"Stop"
|
|
], id="stop-text-export-btn", className="btn btn-danger btn-sm", style={"fontSize": "10px"})
|
|
], className="d-flex mb-2"),
|
|
html.Div([
|
|
html.Button([
|
|
html.I(className="fas fa-robot me-1"),
|
|
"Start LLM"
|
|
], id="start-llm-btn", className="btn btn-info btn-sm me-1", style={"fontSize": "10px"}),
|
|
html.Button([
|
|
html.I(className="fas fa-stop me-1"),
|
|
"Stop"
|
|
], id="stop-llm-btn", className="btn btn-warning btn-sm", style={"fontSize": "10px"})
|
|
], className="d-flex mb-2"),
|
|
html.Small(id="text-export-status", children="Export: Stopped", className="text-muted d-block"),
|
|
html.Small(id="llm-status", children="LLM: Stopped", className="text-muted d-block"),
|
|
|
|
html.Hr(className="my-2"),
|
|
html.Small("System Status", className="text-muted d-block mb-1"),
|
|
html.Div([
|
|
html.Span("Trading: ", className="small"),
|
|
html.Span("SIMULATION", className="badge bg-info small")
|
|
], className="mb-1"),
|
|
html.Div([
|
|
html.Span("Data: ", className="small"),
|
|
html.Span("Active", className="badge bg-success small")
|
|
], className="mb-1"),
|
|
html.Div([
|
|
html.Span("WebSocket: ", className="small"),
|
|
html.Span("Connected", className="badge bg-success small")
|
|
])
|
|
], className="card-body p-2")
|
|
], className="card")
|
|
], style={"width": "23%", "marginLeft": "2%"})
|
|
|
|
def _create_charts_row(self):
|
|
"""Create the charts row with price chart and manual trading buttons"""
|
|
return html.Div([
|
|
html.Div([
|
|
html.Div([
|
|
# Chart header with manual trading buttons and live price
|
|
html.Div([
|
|
html.H6([
|
|
html.I(className="fas fa-chart-candlestick me-2"),
|
|
"Live Price (WebSocket): ",
|
|
html.Span(id="chart-current-price", className="ms-2 text-primary", style={"fontWeight": "bold", "fontSize": "1.2em"})
|
|
], className="card-title mb-0"),
|
|
html.Div([
|
|
html.Button([
|
|
html.I(className="fas fa-arrow-up me-1"),
|
|
"BUY"
|
|
], id="manual-buy-btn", className="btn btn-success btn-sm me-2",
|
|
style={"fontSize": "10px", "padding": "2px 8px"}),
|
|
html.Button([
|
|
html.I(className="fas fa-arrow-down me-1"),
|
|
"SELL"
|
|
], id="manual-sell-btn", className="btn btn-danger btn-sm me-2",
|
|
style={"fontSize": "10px", "padding": "2px 8px"}),
|
|
html.Button([
|
|
html.I(className="fas fa-times me-1"),
|
|
"CLOSE"
|
|
], id="manual-close-btn", className="btn btn-secondary btn-sm",
|
|
style={"fontSize": "10px", "padding": "2px 8px"})
|
|
], className="d-flex")
|
|
], className="d-flex justify-content-between align-items-center mb-2"),
|
|
|
|
html.Div([
|
|
dcc.Graph(id="price-chart", style={"height": "500px"})
|
|
]),
|
|
html.Hr(className="my-2"),
|
|
html.Div([
|
|
html.H6([
|
|
html.I(className="fas fa-chart-line me-2"),
|
|
"Polymarket vs CoinGecko (BTC/ETH, next 5 days)"
|
|
], className="card-title mb-2"),
|
|
dcc.Graph(id="polymarket-eth-btc-chart", style={"height": "350px"})
|
|
])
|
|
], className="card-body p-2")
|
|
], className="card")
|
|
])
|
|
|
|
def _create_cob_and_trades_row(self):
|
|
"""Creates the row for COB ladders, closed trades, pending orders, and model status"""
|
|
return html.Div([
|
|
# Top row: COB Ladders (left) and Models/Training (right)
|
|
html.Div([
|
|
# Left side: COB Ladders (60% width)
|
|
html.Div([
|
|
html.Div([
|
|
# ETH/USDT COB
|
|
html.Div([
|
|
html.Div(
|
|
id="eth-cob-content",
|
|
className="card-body p-2",
|
|
)
|
|
], className="card", style={"flex": "1"}),
|
|
|
|
# BTC/USDT COB
|
|
html.Div([
|
|
html.Div(
|
|
id="btc-cob-content",
|
|
className="card-body p-2",
|
|
)
|
|
], className="card", style={"flex": "1", "marginLeft": "1rem"}),
|
|
], className="d-flex")
|
|
], style={"width": "60%"}),
|
|
|
|
# Right side: Models & Training Progress (40% width)
|
|
html.Div([
|
|
html.Div([
|
|
html.Div([
|
|
html.Div([
|
|
html.H6([
|
|
html.I(className="fas fa-brain me-2"),
|
|
"Models & Training Progress",
|
|
], className="card-title mb-2"),
|
|
html.Button([
|
|
html.I(className="fas fa-sync-alt me-1"),
|
|
"Refresh"
|
|
], id="refresh-training-metrics-btn", className="btn btn-sm btn-outline-primary")
|
|
], className="d-flex justify-content-between align-items-center mb-2"),
|
|
html.Div(
|
|
id="training-metrics",
|
|
style={"height": "300px", "overflowY": "auto"},
|
|
),
|
|
], className="card-body p-2")
|
|
], className="card")
|
|
], style={"width": "38%", "marginLeft": "2%"}),
|
|
], className="d-flex mb-3"),
|
|
|
|
# Mini COB Heatmaps (ETH and BTC)
|
|
html.Div([
|
|
html.Div([
|
|
html.Div([
|
|
html.H6([html.I(className="fas fa-fire me-2"), "ETH Heatmap"], className="card-title mb-2"),
|
|
dcc.Graph(id='cob-heatmap-eth', config={'displayModeBar': False}, style={"height": "220px"})
|
|
], className="card-body p-2", style={"flex": "1"}),
|
|
html.Div([
|
|
html.H6([html.I(className="fas fa-fire me-2"), "BTC Heatmap"], className="card-title mb-2"),
|
|
dcc.Graph(id='cob-heatmap-btc', config={'displayModeBar': False}, style={"height": "220px"})
|
|
], className="card-body p-2", style={"flex": "1", "marginLeft": "1rem"})
|
|
], className="d-flex")
|
|
], className="card"),
|
|
|
|
# Second row: Pending Orders (left) and Closed Trades (right)
|
|
html.Div([
|
|
# Left side: Pending Orders (40% width)
|
|
html.Div([
|
|
html.Div([
|
|
html.Div([
|
|
html.H6([
|
|
html.I(className="fas fa-clock me-2"),
|
|
"Pending Orders & Position Sync",
|
|
], className="card-title mb-2"),
|
|
html.Div(
|
|
id="pending-orders-content",
|
|
style={"height": "200px", "overflowY": "auto"},
|
|
),
|
|
], className="card-body p-2")
|
|
], className="card")
|
|
], style={"width": "40%"}),
|
|
|
|
# Right side: Closed Trades (58% width)
|
|
html.Div([
|
|
html.Div([
|
|
html.Div([
|
|
html.H6([
|
|
html.I(className="fas fa-history me-2"),
|
|
"Recent Closed Trades",
|
|
], className="card-title mb-2"),
|
|
html.Div(
|
|
id="closed-trades-table",
|
|
style={"height": "200px", "overflowY": "auto"},
|
|
),
|
|
], className="card-body p-2")
|
|
], className="card")
|
|
], style={"width": "58%", "marginLeft": "2%"}),
|
|
], className="d-flex")
|
|
])
|
|
|
|
def _create_analytics_and_performance_row(self):
|
|
"""Create the combined analytics and performance row with COB data, trades, and training progress"""
|
|
return html.Div([
|
|
# Left side - COB panels and trades (68% width)
|
|
html.Div([
|
|
# Top section - COB panels
|
|
html.Div([
|
|
# ETH/USDT COB
|
|
html.Div([
|
|
html.Div([
|
|
html.H6([
|
|
html.I(className="fab fa-ethereum me-2"),
|
|
"ETH/USDT COB"
|
|
], className="card-title mb-2"),
|
|
html.Div(id="eth-cob-content")
|
|
], className="card-body p-2")
|
|
], className="card", style={"width": "48%"}),
|
|
|
|
# BTC/USDT COB
|
|
html.Div([
|
|
html.Div([
|
|
html.H6([
|
|
html.I(className="fab fa-bitcoin me-2"),
|
|
"BTC/USDT COB"
|
|
], className="card-title mb-2"),
|
|
html.Div(id="btc-cob-content")
|
|
], className="card-body p-2")
|
|
], className="card", style={"width": "48%", "marginLeft": "4%"})
|
|
], className="d-flex mb-3"),
|
|
|
|
# Bottom section - Closed Trades
|
|
html.Div([
|
|
html.Div([
|
|
html.H6([
|
|
html.I(className="fas fa-history me-2"),
|
|
"Closed Trades"
|
|
], className="card-title mb-2"),
|
|
html.Div(id="closed-trades-table", style={"height": "250px", "overflowY": "auto"})
|
|
], className="card-body p-2")
|
|
], className="card")
|
|
], style={"width": "68%"}),
|
|
|
|
# Right side - Training Progress & COB $1 Buckets (30% width, spans full height)
|
|
html.Div([
|
|
html.Div([
|
|
html.H6([
|
|
html.I(className="fas fa-brain me-2"),
|
|
"Models & Training Progress"
|
|
], className="card-title mb-2"),
|
|
html.Div(id="training-metrics", style={"height": "550px", "overflowY": "auto"})
|
|
], className="card-body p-2")
|
|
], className="card", style={"width": "30%", "marginLeft": "2%"})
|
|
], className="d-flex")
|