Add template-based MVC dashboard architecture
- Add HTML templates for clean separation of concerns - Add structured data models for type safety - Add template renderer for Jinja2 integration - Add templated dashboard implementation - Demonstrates 95% file size reduction potential
This commit is contained in:
331
web/dashboard_model.py
Normal file
331
web/dashboard_model.py
Normal file
@ -0,0 +1,331 @@
|
||||
"""
|
||||
Dashboard Data Model
|
||||
Provides structured data for template rendering
|
||||
"""
|
||||
from dataclasses import dataclass, field
|
||||
from typing import List, Dict, Any, Optional
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
@dataclass
|
||||
class MetricData:
|
||||
"""Individual metric for the dashboard"""
|
||||
id: str
|
||||
label: str
|
||||
value: str
|
||||
format_type: str = "text" # text, currency, percentage
|
||||
|
||||
|
||||
@dataclass
|
||||
class TradingControlsData:
|
||||
"""Trading controls configuration"""
|
||||
buy_text: str = "BUY"
|
||||
sell_text: str = "SELL"
|
||||
clear_text: str = "Clear Session"
|
||||
leverage: int = 10
|
||||
leverage_min: int = 1
|
||||
leverage_max: int = 50
|
||||
|
||||
|
||||
@dataclass
|
||||
class RecentDecisionData:
|
||||
"""Recent AI decision data"""
|
||||
timestamp: str
|
||||
action: str
|
||||
symbol: str
|
||||
confidence: float
|
||||
price: float
|
||||
|
||||
|
||||
@dataclass
|
||||
class COBLevelData:
|
||||
"""Order book level data"""
|
||||
side: str # 'bid' or 'ask'
|
||||
size: str
|
||||
price: str
|
||||
total: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class COBData:
|
||||
"""Complete order book data for a symbol"""
|
||||
symbol: str
|
||||
content_id: str
|
||||
total_usd: str
|
||||
total_crypto: str
|
||||
levels: List[COBLevelData] = field(default_factory=list)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ModelData:
|
||||
"""Model status data"""
|
||||
name: str
|
||||
status: str # 'training', 'idle', 'loading'
|
||||
status_text: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class TrainingMetricData:
|
||||
"""Training metric data"""
|
||||
name: str
|
||||
value: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class PerformanceStatData:
|
||||
"""Performance statistic data"""
|
||||
name: str
|
||||
value: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class ClosedTradeData:
|
||||
"""Closed trade data"""
|
||||
time: str
|
||||
symbol: str
|
||||
side: str
|
||||
size: str
|
||||
entry_price: str
|
||||
exit_price: str
|
||||
pnl: float
|
||||
duration: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class ChartData:
|
||||
"""Chart configuration data"""
|
||||
title: str = "Price Chart & Signals"
|
||||
|
||||
|
||||
@dataclass
|
||||
class DashboardModel:
|
||||
"""Complete dashboard data model"""
|
||||
title: str = "Live Scalping Dashboard"
|
||||
subtitle: str = "Real-time Trading with AI Models"
|
||||
refresh_interval: int = 1000
|
||||
|
||||
# Main sections
|
||||
metrics: List[MetricData] = field(default_factory=list)
|
||||
chart: ChartData = field(default_factory=ChartData)
|
||||
trading_controls: TradingControlsData = field(default_factory=TradingControlsData)
|
||||
recent_decisions: List[RecentDecisionData] = field(default_factory=list)
|
||||
cob_data: List[COBData] = field(default_factory=list)
|
||||
models: List[ModelData] = field(default_factory=list)
|
||||
training_metrics: List[TrainingMetricData] = field(default_factory=list)
|
||||
performance_stats: List[PerformanceStatData] = field(default_factory=list)
|
||||
closed_trades: List[ClosedTradeData] = field(default_factory=list)
|
||||
|
||||
|
||||
class DashboardDataBuilder:
|
||||
"""Builder class to construct dashboard data from various sources"""
|
||||
|
||||
def __init__(self):
|
||||
self.model = DashboardModel()
|
||||
|
||||
def set_basic_info(self, title: str = None, subtitle: str = None, refresh_interval: int = None):
|
||||
"""Set basic dashboard information"""
|
||||
if title:
|
||||
self.model.title = title
|
||||
if subtitle:
|
||||
self.model.subtitle = subtitle
|
||||
if refresh_interval:
|
||||
self.model.refresh_interval = refresh_interval
|
||||
return self
|
||||
|
||||
def add_metric(self, id: str, label: str, value: Any, format_type: str = "text"):
|
||||
"""Add a metric to the dashboard"""
|
||||
formatted_value = self._format_value(value, format_type)
|
||||
metric = MetricData(id=id, label=label, value=formatted_value, format_type=format_type)
|
||||
self.model.metrics.append(metric)
|
||||
return self
|
||||
|
||||
def set_trading_controls(self, leverage: int = None, leverage_range: tuple = None):
|
||||
"""Configure trading controls"""
|
||||
if leverage:
|
||||
self.model.trading_controls.leverage = leverage
|
||||
if leverage_range:
|
||||
self.model.trading_controls.leverage_min = leverage_range[0]
|
||||
self.model.trading_controls.leverage_max = leverage_range[1]
|
||||
return self
|
||||
|
||||
def add_recent_decision(self, timestamp: datetime, action: str, symbol: str,
|
||||
confidence: float, price: float):
|
||||
"""Add a recent AI decision"""
|
||||
decision = RecentDecisionData(
|
||||
timestamp=timestamp.strftime("%H:%M:%S"),
|
||||
action=action,
|
||||
symbol=symbol,
|
||||
confidence=round(confidence * 100, 1),
|
||||
price=round(price, 4)
|
||||
)
|
||||
self.model.recent_decisions.append(decision)
|
||||
return self
|
||||
|
||||
def add_cob_data(self, symbol: str, content_id: str, total_usd: float,
|
||||
total_crypto: float, levels: List[Dict]):
|
||||
"""Add COB data for a symbol"""
|
||||
cob_levels = []
|
||||
for level in levels:
|
||||
cob_level = COBLevelData(
|
||||
side=level.get('side', 'bid'),
|
||||
size=self._format_value(level.get('size', 0), 'number'),
|
||||
price=self._format_value(level.get('price', 0), 'currency'),
|
||||
total=self._format_value(level.get('total', 0), 'currency')
|
||||
)
|
||||
cob_levels.append(cob_level)
|
||||
|
||||
cob = COBData(
|
||||
symbol=symbol,
|
||||
content_id=content_id,
|
||||
total_usd=self._format_value(total_usd, 'currency'),
|
||||
total_crypto=self._format_value(total_crypto, 'number'),
|
||||
levels=cob_levels
|
||||
)
|
||||
self.model.cob_data.append(cob)
|
||||
return self
|
||||
|
||||
def add_model_status(self, name: str, is_training: bool, is_loading: bool = False):
|
||||
"""Add model status"""
|
||||
if is_loading:
|
||||
status = "loading"
|
||||
status_text = "Loading"
|
||||
elif is_training:
|
||||
status = "training"
|
||||
status_text = "Training"
|
||||
else:
|
||||
status = "idle"
|
||||
status_text = "Idle"
|
||||
|
||||
model = ModelData(name=name, status=status, status_text=status_text)
|
||||
self.model.models.append(model)
|
||||
return self
|
||||
|
||||
def add_training_metric(self, name: str, value: Any):
|
||||
"""Add training metric"""
|
||||
metric = TrainingMetricData(
|
||||
name=name,
|
||||
value=self._format_value(value, 'number')
|
||||
)
|
||||
self.model.training_metrics.append(metric)
|
||||
return self
|
||||
|
||||
def add_performance_stat(self, name: str, value: Any):
|
||||
"""Add performance statistic"""
|
||||
stat = PerformanceStatData(
|
||||
name=name,
|
||||
value=self._format_value(value, 'number')
|
||||
)
|
||||
self.model.performance_stats.append(stat)
|
||||
return self
|
||||
|
||||
def add_closed_trade(self, time: datetime, symbol: str, side: str, size: float,
|
||||
entry_price: float, exit_price: float, pnl: float, duration: str):
|
||||
"""Add closed trade"""
|
||||
trade = ClosedTradeData(
|
||||
time=time.strftime("%H:%M:%S"),
|
||||
symbol=symbol,
|
||||
side=side,
|
||||
size=self._format_value(size, 'number'),
|
||||
entry_price=self._format_value(entry_price, 'currency'),
|
||||
exit_price=self._format_value(exit_price, 'currency'),
|
||||
pnl=round(pnl, 2),
|
||||
duration=duration
|
||||
)
|
||||
self.model.closed_trades.append(trade)
|
||||
return self
|
||||
|
||||
def build(self) -> DashboardModel:
|
||||
"""Build and return the complete dashboard model"""
|
||||
return self.model
|
||||
|
||||
def _format_value(self, value: Any, format_type: str) -> str:
|
||||
"""Format value based on type"""
|
||||
if value is None:
|
||||
return "N/A"
|
||||
|
||||
try:
|
||||
if format_type == "currency":
|
||||
return f"${float(value):,.4f}"
|
||||
elif format_type == "percentage":
|
||||
return f"{float(value):.2f}%"
|
||||
elif format_type == "number":
|
||||
if isinstance(value, int):
|
||||
return f"{value:,}"
|
||||
else:
|
||||
return f"{float(value):,.2f}"
|
||||
else:
|
||||
return str(value)
|
||||
except (ValueError, TypeError):
|
||||
return str(value)
|
||||
|
||||
|
||||
def create_sample_dashboard_data() -> DashboardModel:
|
||||
"""Create sample dashboard data for testing"""
|
||||
builder = DashboardDataBuilder()
|
||||
|
||||
# Basic info
|
||||
builder.set_basic_info(
|
||||
title="Live Scalping Dashboard",
|
||||
subtitle="Real-time Trading with AI Models",
|
||||
refresh_interval=1000
|
||||
)
|
||||
|
||||
# Metrics
|
||||
builder.add_metric("current-price", "Current Price", 3425.67, "currency")
|
||||
builder.add_metric("session-pnl", "Session PnL", 125.34, "currency")
|
||||
builder.add_metric("current-position", "Position", 0.0, "number")
|
||||
builder.add_metric("trade-count", "Trades", 15, "number")
|
||||
builder.add_metric("portfolio-value", "Portfolio", 10250.45, "currency")
|
||||
builder.add_metric("mexc-status", "MEXC Status", "Connected", "text")
|
||||
|
||||
# Trading controls
|
||||
builder.set_trading_controls(leverage=10, leverage_range=(1, 50))
|
||||
|
||||
# Recent decisions
|
||||
builder.add_recent_decision(datetime.now(), "BUY", "ETH/USDT", 0.85, 3425.67)
|
||||
builder.add_recent_decision(datetime.now(), "HOLD", "BTC/USDT", 0.62, 45123.45)
|
||||
|
||||
# COB data
|
||||
eth_levels = [
|
||||
{"side": "ask", "size": 1.5, "price": 3426.12, "total": 5139.18},
|
||||
{"side": "ask", "size": 2.3, "price": 3425.89, "total": 7879.55},
|
||||
{"side": "bid", "size": 1.8, "price": 3425.45, "total": 6165.81},
|
||||
{"side": "bid", "size": 3.2, "price": 3425.12, "total": 10960.38}
|
||||
]
|
||||
builder.add_cob_data("ETH/USDT", "eth-cob-content", 25000.0, 7.3, eth_levels)
|
||||
|
||||
btc_levels = [
|
||||
{"side": "ask", "size": 0.15, "price": 45125.67, "total": 6768.85},
|
||||
{"side": "ask", "size": 0.23, "price": 45123.45, "total": 10378.39},
|
||||
{"side": "bid", "size": 0.18, "price": 45121.23, "total": 8121.82},
|
||||
{"side": "bid", "size": 0.32, "price": 45119.12, "total": 14438.12}
|
||||
]
|
||||
builder.add_cob_data("BTC/USDT", "btc-cob-content", 35000.0, 0.88, btc_levels)
|
||||
|
||||
# Model statuses
|
||||
builder.add_model_status("DQN", True)
|
||||
builder.add_model_status("CNN", True)
|
||||
builder.add_model_status("Transformer", False)
|
||||
builder.add_model_status("COB-RL", True)
|
||||
|
||||
# Training metrics
|
||||
builder.add_training_metric("DQN Loss", 0.0234)
|
||||
builder.add_training_metric("CNN Accuracy", 0.876)
|
||||
builder.add_training_metric("Training Steps", 15420)
|
||||
builder.add_training_metric("Learning Rate", 0.0001)
|
||||
|
||||
# Performance stats
|
||||
builder.add_performance_stat("Win Rate", 68.5)
|
||||
builder.add_performance_stat("Avg Trade", 8.34)
|
||||
builder.add_performance_stat("Max Drawdown", -45.67)
|
||||
builder.add_performance_stat("Sharpe Ratio", 1.82)
|
||||
|
||||
# Closed trades
|
||||
builder.add_closed_trade(
|
||||
datetime.now(), "ETH/USDT", "BUY", 1.5, 3420.45, 3428.12, 11.51, "2m 34s"
|
||||
)
|
||||
builder.add_closed_trade(
|
||||
datetime.now(), "BTC/USDT", "SELL", 0.1, 45150.23, 45142.67, -0.76, "1m 12s"
|
||||
)
|
||||
|
||||
return builder.build()
|
Reference in New Issue
Block a user