"""
Dashboard Components
Reusable UI components for the Streamlit dashboard.
"""
import streamlit as st
from typing import Dict, Any, List, Optional
from datetime import datetime
def render_header(
symbol: str = "BTC/USDT",
price: float = 0.0,
change_24h: float = 0.0,
connection_status: bool = True,
):
"""
Render the dashboard header with live price and status.
"""
col1, col2, col3 = st.columns([2, 1, 1])
with col1:
st.markdown(f"""
🤖 DRL Trading System
""", unsafe_allow_html=True)
with col2:
change_color = "#26a69a" if change_24h >= 0 else "#ef5350"
st.markdown(f"""
{symbol}
${price:,.2f}
{'+' if change_24h >= 0 else ''}{change_24h:.2f}%
""", unsafe_allow_html=True)
with col3:
status_color = "#26a69a" if connection_status else "#ef5350"
status_text = "🟢 Connected" if connection_status else "🔴 Disconnected"
st.markdown(f"""
{status_text}
Binance Testnet
""", unsafe_allow_html=True)
def render_confidence_gauge(confidence: float):
"""
Render the agent confidence gauge.
Args:
confidence: Confidence percentage (0-100)
"""
# Determine color based on confidence
if confidence >= 70:
color = "#26a69a"
label = "High"
elif confidence >= 40:
color = "#ffc107"
label = "Medium"
else:
color = "#ef5350"
label = "Low"
st.markdown(f"""
Agent Confidence
{confidence:.0f}%
{label} Confidence
""", unsafe_allow_html=True)
def render_pnl_card(
total_balance: float,
daily_pnl: float,
daily_roi: float,
initial_balance: float = 10000.0,
):
"""
Render the P&L summary card.
"""
total_pnl = total_balance - initial_balance
total_roi = (total_pnl / initial_balance) * 100
pnl_color = "#26a69a" if total_pnl >= 0 else "#ef5350"
daily_color = "#26a69a" if daily_pnl >= 0 else "#ef5350"
st.markdown(f"""
Portfolio Value
${total_balance:,.2f}
Total P&L
{'+' if total_pnl >= 0 else ''}${total_pnl:,.2f}
({'+' if total_roi >= 0 else ''}{total_roi:.2f}%)
Daily P&L
{'+' if daily_pnl >= 0 else ''}${daily_pnl:,.2f}
({'+' if daily_roi >= 0 else ''}{daily_roi:.2f}%)
""", unsafe_allow_html=True)
def render_position_card(position: Optional[Dict[str, Any]]):
"""
Render the current position card.
"""
if position is None:
st.markdown("""
Current Position
No Position
""", unsafe_allow_html=True)
return
side = position.get('side', 'unknown')
is_long = side == 'buy'
color = "#26a69a" if is_long else "#ef5350"
icon = "📈" if is_long else "📉"
entry_price = position.get('entry_price', 0)
amount = position.get('amount', 0)
unrealized_pnl = position.get('unrealized_pnl', 0)
st.markdown(f"""
Current Position
{icon} {'LONG' if is_long else 'SHORT'}
Entry Price:
${entry_price:,.2f}
Size:
{amount:.6f}
Unrealized P&L:
{'+' if unrealized_pnl >= 0 else ''}${unrealized_pnl:,.2f}
""", unsafe_allow_html=True)
def render_trade_history(trades: List[Dict], limit: int = 10):
"""
Render the trade history table.
"""
st.markdown("""
Recent Trades
""", unsafe_allow_html=True)
if not trades:
st.info("No trades yet")
return
# Prepare data for display
display_trades = trades[-limit:][::-1] # Most recent first
for trade in display_trades:
side = trade.get('side', trade.get('position', 0))
if isinstance(side, int):
side = 'LONG' if side == 1 else 'SHORT'
else:
side = side.upper()
is_long = side == 'LONG' or side == 'BUY'
color = "#26a69a" if is_long else "#ef5350"
pnl = trade.get('pnl', 0)
pnl_color = "#26a69a" if pnl >= 0 else "#ef5350"
entry = trade.get('entry_price', 0)
exit_price = trade.get('exit_price', 0)
st.markdown(f"""
{side}
${entry:,.2f} → ${exit_price:,.2f}
{'+' if pnl >= 0 else ''}${pnl:,.2f}
""", unsafe_allow_html=True)
def render_circuit_breaker_status(status: Dict[str, Any]):
"""
Render the circuit breaker status indicator.
"""
is_tripped = status.get('is_tripped', False)
if is_tripped:
st.error(f"""
⚠️ **CIRCUIT BREAKER ACTIVATED**
Reason: {status.get('trip_reason', 'Unknown')}
Cooldown: {status.get('cooldown_remaining', 'Unknown')}
""")
else:
daily_metrics = status.get('daily_metrics', {})
daily_loss = -daily_metrics.get('daily_return', 0) * 100
max_loss = status.get('thresholds', {}).get('max_daily_loss', 0.05) * 100
progress = min(daily_loss / max_loss, 1.0) if max_loss > 0 else 0
if progress < 0.5:
status_color = "#26a69a"
elif progress < 0.8:
status_color = "#ffc107"
else:
status_color = "#ef5350"
st.markdown(f"""
Risk Monitor
●
Daily Loss: {daily_loss:.2f}%
Max: {max_loss:.1f}%
""", unsafe_allow_html=True)
def render_training_status(status: Dict[str, Any]):
"""
Render the self-improvement training status.
"""
is_finetuning = status.get('is_finetuning', False)
finetune_count = status.get('finetune_count', 0)
next_finetune = status.get('next_finetune_in', 'Unknown')
buffer_size = status.get('buffer_size', 0)
if is_finetuning:
st.info("🔄 Fine-tuning in progress...")
else:
st.markdown(f"""
Self-Improvement
Fine-tunes:
{finetune_count}
Buffer Size:
{buffer_size}
Next Fine-tune:
{next_finetune}
""", unsafe_allow_html=True)