"""
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"""
{desc_html}
{strategy}
Score {score}
Conf {confidence}/10
{risk_badge_html}
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"]