from __future__ import annotations from dataclasses import dataclass from decimal import Decimal from typing import Protocol from app.models.portfolio import PortfolioConfig from app.services.boundary_values import boundary_decimal class _SaveStatusConfig(Protocol): entry_basis_mode: str gold_value: float | None entry_price: float | None gold_ounces: float | None current_ltv: float margin_call_price: object @dataclass(frozen=True, slots=True) class SaveStatusSnapshot: entry_basis_mode: str gold_value: Decimal entry_price: Decimal gold_ounces: Decimal current_ltv: Decimal margin_call_price: Decimal def _normalize_save_status_snapshot(config: PortfolioConfig | _SaveStatusConfig) -> SaveStatusSnapshot: margin_call_price = config.margin_call_price resolved_margin_call_price = margin_call_price() if callable(margin_call_price) else margin_call_price return SaveStatusSnapshot( entry_basis_mode=config.entry_basis_mode, gold_value=boundary_decimal(config.gold_value, field_name="config.gold_value"), entry_price=boundary_decimal(config.entry_price, field_name="config.entry_price"), gold_ounces=boundary_decimal(config.gold_ounces, field_name="config.gold_ounces"), current_ltv=boundary_decimal(config.current_ltv, field_name="config.current_ltv"), margin_call_price=boundary_decimal( resolved_margin_call_price, field_name="config.margin_call_price", ), ) def margin_call_price_value(config: PortfolioConfig | _SaveStatusConfig) -> float: return float(_normalize_save_status_snapshot(config).margin_call_price) def save_status_text(config: PortfolioConfig | _SaveStatusConfig) -> str: snapshot = _normalize_save_status_snapshot(config) return ( f"Saved: basis={snapshot.entry_basis_mode}, start=${float(snapshot.gold_value):,.0f}, " f"entry=${float(snapshot.entry_price):,.2f}/oz, weight={float(snapshot.gold_ounces):,.2f} oz, " f"LTV={float(snapshot.current_ltv):.1%}, trigger=${float(snapshot.margin_call_price):,.2f}/oz" )