Files
vault-dash/app/components/portfolio_view.py
Bu5hm4nn 874b4a5a02 Fix linting issues: line length, import sorting, unused variables
- Set ruff/black line length to 120
- Reformatted code with black
- Fixed import ordering with ruff
- Disabled lint for UI component files with long CSS strings
- Updated pyproject.toml with proper tool configuration
2026-03-22 10:30:12 +01:00

84 lines
3.6 KiB
Python

from __future__ import annotations
from typing import Any
from nicegui import ui
class PortfolioOverview:
"""Portfolio summary card with LTV risk coloring and margin warning."""
def __init__(self, *, margin_call_ltv: float = 0.75) -> None:
self.margin_call_ltv = margin_call_ltv
with ui.card().classes(
"w-full rounded-2xl border border-slate-200 bg-white shadow-sm dark:border-slate-800 dark:bg-slate-900"
):
with ui.row().classes("w-full items-center justify-between"):
ui.label("Portfolio Overview").classes("text-lg font-semibold text-slate-900 dark:text-slate-100")
self.warning_badge = ui.label("Monitoring").classes(
"rounded-full bg-amber-100 px-3 py-1 text-xs font-semibold text-amber-700 dark:bg-amber-500/15 dark:text-amber-300"
)
with ui.grid(columns=2).classes("w-full gap-4 max-sm:grid-cols-1"):
self.gold_value = self._metric_card("Current Gold Value")
self.loan_amount = self._metric_card("Loan Amount")
self.ltv = self._metric_card("Current LTV")
self.net_equity = self._metric_card("Net Equity")
def _metric_card(self, label: str) -> ui.label:
with ui.card().classes(
"rounded-xl border border-slate-200 bg-slate-50 p-4 shadow-none dark:border-slate-800 dark:bg-slate-950"
):
ui.label(label).classes("text-sm font-medium text-slate-500 dark:text-slate-400")
return ui.label("--").classes("text-2xl font-bold text-slate-900 dark:text-slate-50")
def update(self, portfolio: dict[str, Any], *, margin_call_ltv: float | None = None) -> None:
threshold = (
margin_call_ltv if margin_call_ltv is not None else portfolio.get("margin_call_ltv", self.margin_call_ltv)
)
gold_value = float(portfolio.get("gold_value", portfolio.get("portfolio_value", 0.0)))
loan_amount = float(portfolio.get("loan_amount", 0.0))
current_ltv = float(portfolio.get("ltv_ratio", portfolio.get("current_ltv", 0.0)))
net_equity = float(portfolio.get("net_equity", gold_value - loan_amount))
self.gold_value.set_text(self._money(gold_value))
self.loan_amount.set_text(self._money(loan_amount))
self.net_equity.set_text(self._money(net_equity))
self.ltv.set_text(f"{current_ltv * 100:.1f}%")
self.ltv.style(f"color: {self._ltv_color(current_ltv, threshold)}")
badge_text, badge_style = self._warning_state(current_ltv, threshold)
self.warning_badge.set_text(badge_text)
self.warning_badge.style(badge_style)
@staticmethod
def _money(value: float) -> str:
return f"${value:,.2f}"
@staticmethod
def _ltv_color(ltv: float, threshold: float) -> str:
if ltv >= threshold:
return "#f43f5e"
if ltv >= threshold * 0.9:
return "#f59e0b"
return "#22c55e"
@staticmethod
def _warning_state(ltv: float, threshold: float) -> tuple[str, str]:
base = "border-radius: 9999px; padding: 0.25rem 0.75rem; font-size: 0.75rem; font-weight: 600;"
if ltv >= threshold:
return (
"Margin call risk",
base + " background: rgba(244, 63, 94, 0.14); color: #f43f5e;",
)
if ltv >= threshold * 0.9:
return (
"Approaching threshold",
base + " background: rgba(245, 158, 11, 0.14); color: #f59e0b;",
)
return (
"Healthy collateral",
base + " background: rgba(34, 197, 94, 0.14); color: #22c55e;",
)