feat(CORE-002): add GLD share quote conversion seam

This commit is contained in:
Bu5hm4nn
2026-03-25 14:52:48 +01:00
parent 1a2dfaff01
commit f0d7ab5748
10 changed files with 425 additions and 34 deletions

View File

@@ -7,6 +7,7 @@ from fastapi.responses import RedirectResponse
from nicegui import ui
from app.components import PortfolioOverview
from app.domain.portfolio_math import resolve_portfolio_spot_from_quote
from app.models.workspace import WORKSPACE_COOKIE, get_workspace_repository
from app.pages.common import dashboard_page, quick_recommendations, recommendation_style, strategy_catalog
from app.services.alerts import AlertService, build_portfolio_alert_context
@@ -16,20 +17,10 @@ from app.services.turnstile import load_turnstile_settings
_DEFAULT_CASH_BUFFER = 18_500.0
def _resolve_overview_spot(config, quote: dict[str, object]) -> tuple[float, str, str]:
configured_price = float(config.entry_price or 0.0)
quote_price = float(quote.get("price", configured_price or 0.0) or 0.0)
quote_source = str(quote.get("source", "unknown"))
quote_updated_at = str(quote.get("updated_at", ""))
if configured_price > 0 and quote_price > 0:
ratio = max(configured_price / quote_price, quote_price / configured_price)
if ratio > 1.5:
return configured_price, "configured_entry_price", ""
if quote_price > 0:
return quote_price, quote_source, quote_updated_at
return configured_price, "configured_entry_price", ""
def _resolve_overview_spot(
config, quote: dict[str, object], *, fallback_symbol: str | None = None
) -> tuple[float, str, str]:
return resolve_portfolio_spot_from_quote(config, quote, fallback_symbol=fallback_symbol)
def _format_timestamp(value: str | None) -> str:
@@ -116,7 +107,9 @@ async def overview_page(workspace_id: str) -> None:
data_service = get_data_service()
symbol = data_service.default_symbol
quote = await data_service.get_quote(symbol)
overview_spot_price, overview_source, overview_updated_at = _resolve_overview_spot(config, quote)
overview_spot_price, overview_source, overview_updated_at = _resolve_overview_spot(
config, quote, fallback_symbol=symbol
)
portfolio = build_portfolio_alert_context(
config,
spot_price=overview_spot_price,
@@ -132,6 +125,7 @@ async def overview_page(workspace_id: str) -> None:
else:
quote_status = (
f"Live quote source: {portfolio['quote_source']} · "
f"GLD share quote converted to ozt-equivalent spot · "
f"Last updated {_format_timestamp(str(portfolio['quote_updated_at']))}"
)
@@ -161,15 +155,21 @@ async def overview_page(workspace_id: str) -> None:
if alert_status.history:
latest = alert_status.history[0]
ui.label(
f"Latest alert logged {_format_timestamp(latest.updated_at)} at spot ${latest.spot_price:,.2f}"
f"Latest alert logged {_format_timestamp(latest.updated_at)} at collateral spot ${latest.spot_price:,.2f}"
).classes("text-xs text-slate-500 dark:text-slate-400")
spot_caption = (
f"{symbol} share quote converted to USD/ozt via {portfolio['quote_source']}"
if portfolio["quote_source"] != "configured_entry_price"
else "Configured entry price fallback in USD/ozt"
)
with ui.grid(columns=4).classes("w-full gap-4 max-lg:grid-cols-2 max-sm:grid-cols-1"):
summary_cards = [
(
"Spot Price",
"Collateral Spot Price",
f"${portfolio['spot_price']:,.2f}",
f"{symbol} live quote via {portfolio['quote_source']}",
spot_caption,
),
(
"Margin Call Price",