feat(PRICING-002): add GLD/GC=F basis display on overview
This commit is contained in:
@@ -152,6 +152,13 @@ async def overview_page(workspace_id: str) -> None:
|
||||
source=overview_source,
|
||||
updated_at=overview_updated_at,
|
||||
)
|
||||
|
||||
# Fetch basis data for GLD/GC=F comparison
|
||||
try:
|
||||
basis_data = await data_service.get_basis_data()
|
||||
except Exception:
|
||||
logger.exception("Failed to fetch basis data")
|
||||
basis_data = None
|
||||
configured_gold_value = float(config.gold_value or 0.0)
|
||||
portfolio["cash_buffer"] = max(float(portfolio["gold_value"]) - configured_gold_value, 0.0) + _DEFAULT_CASH_BUFFER
|
||||
portfolio["hedge_budget"] = float(config.monthly_budget)
|
||||
@@ -208,6 +215,78 @@ async def overview_page(workspace_id: str) -> None:
|
||||
)
|
||||
|
||||
with left_pane:
|
||||
# GLD/GC=F Basis Card
|
||||
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 gap-3"):
|
||||
ui.label("GLD/GC=F Basis").classes("text-lg font-semibold text-slate-900 dark:text-slate-100")
|
||||
if basis_data:
|
||||
basis_badge_class = {
|
||||
"green": "rounded-full bg-emerald-100 px-3 py-1 text-xs font-semibold text-emerald-700 dark:bg-emerald-500/15 dark:text-emerald-300",
|
||||
"yellow": "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",
|
||||
"red": "rounded-full bg-rose-100 px-3 py-1 text-xs font-semibold text-rose-700 dark:bg-rose-500/15 dark:text-rose-300",
|
||||
}.get(
|
||||
basis_data["basis_status"],
|
||||
"rounded-full bg-slate-100 px-3 py-1 text-xs font-semibold text-slate-700",
|
||||
)
|
||||
ui.label(f"{basis_data['basis_label']} ({basis_data['basis_bps']:+.1f} bps)").classes(
|
||||
basis_badge_class
|
||||
)
|
||||
|
||||
if basis_data:
|
||||
with ui.grid(columns=2).classes("w-full gap-4 mt-4"):
|
||||
# GLD Implied Spot
|
||||
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("GLD Implied Spot").classes(
|
||||
"text-sm font-medium text-slate-500 dark:text-slate-400"
|
||||
)
|
||||
ui.label(f"${basis_data['gld_implied_spot']:,.2f}/oz").classes(
|
||||
"text-2xl font-bold text-slate-900 dark:text-slate-50"
|
||||
)
|
||||
ui.label(
|
||||
f"GLD ${basis_data['gld_price']:.2f} ÷ {basis_data['gld_ounces_per_share']:.4f} oz/share"
|
||||
).classes("text-xs text-slate-500 dark:text-slate-400")
|
||||
|
||||
# GC=F Adjusted
|
||||
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("GC=F Adjusted").classes("text-sm font-medium text-slate-500 dark:text-slate-400")
|
||||
ui.label(f"${basis_data['gc_f_adjusted']:,.2f}/oz").classes(
|
||||
"text-2xl font-bold text-slate-900 dark:text-slate-50"
|
||||
)
|
||||
ui.label(
|
||||
f"GC=F ${basis_data['gc_f_price']:.2f} - ${basis_data['contango_estimate']:.0f} contango"
|
||||
).classes("text-xs text-slate-500 dark:text-slate-400")
|
||||
|
||||
# Basis explanation and after-hours notice
|
||||
with ui.row().classes("w-full items-start gap-2 mt-4"):
|
||||
ui.icon("info", size="xs").classes("text-slate-400 mt-0.5")
|
||||
ui.label(
|
||||
"Basis shows the premium/discount between GLD-implied gold and futures-adjusted spot. "
|
||||
"Green < 25 bps (normal), Yellow 25-50 bps (elevated), Red > 50 bps (unusual)."
|
||||
).classes("text-xs text-slate-500 dark:text-slate-400")
|
||||
|
||||
if basis_data["after_hours"]:
|
||||
with ui.row().classes("w-full items-start gap-2 mt-2"):
|
||||
ui.icon("schedule", size="xs").classes("text-amber-500 mt-0.5")
|
||||
ui.label(
|
||||
f"{basis_data['after_hours_note']} · GLD: {_format_timestamp(basis_data['gld_updated_at'])} · "
|
||||
f"GC=F: {_format_timestamp(basis_data['gc_f_updated_at'])}"
|
||||
).classes("text-xs text-amber-700 dark:text-amber-300")
|
||||
|
||||
# Warning for elevated basis
|
||||
if basis_data["basis_status"] == "red":
|
||||
ui.label(
|
||||
f"⚠️ Elevated basis detected: {basis_data['basis_bps']:+.1f} bps. "
|
||||
"This may indicate after-hours pricing gaps, physical stress, or arbitrage disruption."
|
||||
).classes("text-sm font-medium text-rose-700 dark:text-rose-300 mt-3")
|
||||
else:
|
||||
ui.label("Basis data temporarily unavailable").classes("text-sm text-slate-500 dark:text-slate-400")
|
||||
|
||||
with ui.card().classes(
|
||||
"w-full rounded-2xl border border-slate-200 bg-white shadow-sm dark:border-slate-800 dark:bg-slate-900"
|
||||
):
|
||||
|
||||
Reference in New Issue
Block a user