""" Trading terminal dark theme for the Streamlit dashboard. Bloomberg/TradingView-inspired aesthetic with green/amber accents. Uses CSS variables for consistency and injects custom fonts. """ # -- Color Tokens -- COLORS = { "bg_primary": "#0a0e17", "bg_secondary": "#111827", "bg_card": "#1a2234", "bg_card_hover": "#1f2b42", "bg_input": "#151d2e", "border": "#2a3548", "border_active": "#3b82f6", "text_primary": "#e2e8f0", "text_secondary": "#94a3b8", "text_muted": "#64748b", "green": "#22c55e", "green_dim": "#16a34a", "green_glow": "rgba(34, 197, 94, 0.15)", "red": "#ef4444", "red_dim": "#dc2626", "red_glow": "rgba(239, 68, 68, 0.15)", "amber": "#f59e0b", "amber_dim": "#d97706", "blue": "#3b82f6", "blue_dim": "#2563eb", "cyan": "#06b6d4", "purple": "#a855f7", } def get_plotly_template(): """Return a Plotly layout template matching the terminal theme.""" return dict( paper_bgcolor=COLORS["bg_card"], plot_bgcolor=COLORS["bg_card"], font=dict( family="JetBrains Mono, SF Mono, Menlo, monospace", color=COLORS["text_secondary"], size=11, ), xaxis=dict( gridcolor="rgba(42, 53, 72, 0.5)", zerolinecolor=COLORS["border"], showgrid=True, gridwidth=1, ), yaxis=dict( gridcolor="rgba(42, 53, 72, 0.5)", zerolinecolor=COLORS["border"], showgrid=True, gridwidth=1, ), margin=dict(l=0, r=0, t=32, b=0), hoverlabel=dict( bgcolor=COLORS["bg_secondary"], font_color=COLORS["text_primary"], bordercolor=COLORS["border"], ), colorway=[ COLORS["green"], COLORS["blue"], COLORS["amber"], COLORS["cyan"], COLORS["purple"], COLORS["red"], ], ) GLOBAL_CSS = f""" """ def kpi_card(label: str, value: str, delta: str = "", color: str = "blue") -> str: """Render a custom KPI card as HTML.""" delta_class = ( "positive" if delta.startswith("+") else ("negative" if delta.startswith("-") else "neutral") ) delta_html = f'
{delta}
' if delta else "" return f"""
{label}
{value}
{delta_html}
""" def page_header(title: str, subtitle: str = "") -> str: """Render a page header as HTML.""" sub = f'
{subtitle}
' if subtitle else "" return f""" """ def signal_card( rank: int, ticker: str, score: int, confidence: int, strategy: str, entry_price: float, reason: str, company_name: str = "", description: str = "", risk_level: str = "", ) -> str: """Render a recommendation signal card as HTML.""" # Confidence bar color if confidence >= 8: bar_color = COLORS["green"] elif confidence >= 6: bar_color = COLORS["amber"] else: bar_color = COLORS["red"] # Score badge color if score >= 40: score_badge = "badge-green" elif score >= 25: score_badge = "badge-amber" else: score_badge = "badge-muted" # Strategy badge strat_badge = "badge-blue" strat_css = "" strat_lower = strategy.lower().replace(" ", "_") if "momentum" in strat_lower: strat_badge = "badge-green" strat_css = "strat-momentum" elif "insider" in strat_lower: strat_badge = "badge-amber" strat_css = "strat-insider" elif "earnings" in strat_lower: strat_badge = "badge-blue" strat_css = "strat-earnings" elif "volume" in strat_lower: strat_badge = "badge-blue" strat_css = "strat-volume" # Risk level badge risk_badge_html = "" if risk_level: risk_lower = risk_level.lower() if risk_lower == "low": risk_badge_html = f'{risk_level.title()}' elif risk_lower == "moderate": risk_badge_html = f'{risk_level.title()}' elif risk_lower == "high": risk_badge_html = f'{risk_level.title()}' elif risk_lower == "speculative": risk_badge_html = f'{risk_level.title()}' entry_str = f"${entry_price:.2f}" if entry_price else "N/A" conf_pct = confidence * 10 name_html = ( f'{company_name}' if company_name and company_name != ticker else "" ) desc_html = ( f'
' f'
Company
' f'
{description}
' f"
" if description else "" ) return f"""
{ticker} #{rank} {name_html}
{desc_html}
{strategy} Score {score} Conf {confidence}/10 {risk_badge_html}
Entry
{entry_str}
Score
{score}
Confidence
{confidence}/10
Strategy
{strategy.upper()}
{reason}
""" def pnl_color(value: float) -> str: """Return green/red CSS color based on sign.""" if value > 0: return COLORS["green"] elif value < 0: return COLORS["red"] return COLORS["text_muted"]