feat(PORT-004C): seed workspace routes from portfolio settings
This commit is contained in:
@@ -6,6 +6,7 @@ from typing import Any
|
||||
|
||||
from nicegui import ui
|
||||
|
||||
from app.models.portfolio import PortfolioConfig
|
||||
from app.services.strategy_templates import StrategyTemplateService
|
||||
|
||||
NAV_ITEMS: list[tuple[str, str, str]] = [
|
||||
@@ -23,10 +24,10 @@ def nav_items(workspace_id: str | None = None) -> list[tuple[str, str, str]]:
|
||||
return NAV_ITEMS
|
||||
return [
|
||||
("overview", f"/{workspace_id}", "Overview"),
|
||||
("hedge", "/hedge", "Hedge Analysis"),
|
||||
("hedge", f"/{workspace_id}/hedge", "Hedge Analysis"),
|
||||
("options", "/options", "Options Chain"),
|
||||
("backtests", "/backtests", "Backtests"),
|
||||
("event-comparison", "/event-comparison", "Event Comparison"),
|
||||
("backtests", f"/{workspace_id}/backtests", "Backtests"),
|
||||
("event-comparison", f"/{workspace_id}/event-comparison", "Event Comparison"),
|
||||
("settings", f"/{workspace_id}/settings", "Settings"),
|
||||
]
|
||||
|
||||
@@ -35,22 +36,33 @@ def demo_spot_price() -> float:
|
||||
return 215.0
|
||||
|
||||
|
||||
def portfolio_snapshot() -> dict[str, float]:
|
||||
gold_units = 1_000.0
|
||||
spot = demo_spot_price()
|
||||
gold_value = gold_units * spot
|
||||
loan_amount = 145_000.0
|
||||
margin_call_ltv = 0.75
|
||||
def portfolio_snapshot(config: PortfolioConfig | None = None) -> dict[str, float]:
|
||||
if config is None:
|
||||
gold_units = 1_000.0
|
||||
spot = demo_spot_price()
|
||||
gold_value = gold_units * spot
|
||||
loan_amount = 145_000.0
|
||||
margin_call_ltv = 0.75
|
||||
hedge_budget = 8_000.0
|
||||
else:
|
||||
gold_units = float(config.gold_ounces or 0.0)
|
||||
spot = float(config.entry_price or 0.0)
|
||||
gold_value = float(config.gold_value or gold_units * spot)
|
||||
loan_amount = float(config.loan_amount)
|
||||
margin_call_ltv = float(config.margin_threshold)
|
||||
hedge_budget = float(config.monthly_budget)
|
||||
|
||||
return {
|
||||
"gold_value": gold_value,
|
||||
"loan_amount": loan_amount,
|
||||
"ltv_ratio": loan_amount / gold_value,
|
||||
"net_equity": gold_value - loan_amount,
|
||||
"spot_price": spot,
|
||||
"gold_units": gold_units,
|
||||
"margin_call_ltv": margin_call_ltv,
|
||||
"margin_call_price": loan_amount / (margin_call_ltv * gold_units),
|
||||
"cash_buffer": 18_500.0,
|
||||
"hedge_budget": 8_000.0,
|
||||
"hedge_budget": hedge_budget,
|
||||
}
|
||||
|
||||
|
||||
@@ -122,12 +134,17 @@ def option_chain() -> list[dict[str, Any]]:
|
||||
return rows
|
||||
|
||||
|
||||
def strategy_metrics(strategy_name: str, scenario_pct: int) -> dict[str, Any]:
|
||||
def strategy_metrics(
|
||||
strategy_name: str,
|
||||
scenario_pct: int,
|
||||
*,
|
||||
portfolio: dict[str, Any] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
strategy = next(
|
||||
(item for item in strategy_catalog() if item["name"] == strategy_name),
|
||||
strategy_catalog()[0],
|
||||
)
|
||||
portfolio = portfolio_snapshot()
|
||||
portfolio = portfolio or portfolio_snapshot()
|
||||
spot = float(portfolio["spot_price"])
|
||||
underlying_units = portfolio["gold_value"] / spot
|
||||
loan_amount = float(portfolio["loan_amount"])
|
||||
@@ -209,6 +226,21 @@ def dashboard_page(title: str, subtitle: str, current: str, workspace_id: str |
|
||||
yield container
|
||||
|
||||
|
||||
def render_workspace_recovery(title: str = "Workspace not found", message: str | None = None) -> None:
|
||||
resolved_message = message or "The requested workspace is unavailable. Start a new workspace or return to the welcome page."
|
||||
with ui.column().classes("mx-auto mt-24 w-full max-w-2xl gap-6 px-6 text-center"):
|
||||
ui.icon("folder_off").classes("mx-auto text-6xl text-slate-400")
|
||||
ui.label(title).classes("text-3xl font-bold text-slate-900 dark:text-slate-50")
|
||||
ui.label(resolved_message).classes("text-base text-slate-500 dark:text-slate-400")
|
||||
with ui.row().classes("mx-auto gap-3"):
|
||||
ui.link("Get started", "/workspaces/bootstrap").classes(
|
||||
"rounded-lg bg-slate-900 px-5 py-3 text-sm font-semibold text-white no-underline dark:bg-slate-100 dark:text-slate-900"
|
||||
)
|
||||
ui.link("Go to welcome page", "/").classes(
|
||||
"rounded-lg border border-slate-300 px-5 py-3 text-sm font-semibold text-slate-700 no-underline dark:border-slate-700 dark:text-slate-200"
|
||||
)
|
||||
|
||||
|
||||
def recommendation_style(tone: str) -> str:
|
||||
return {
|
||||
"positive": "border-emerald-200 bg-emerald-50 dark:border-emerald-900/60 dark:bg-emerald-950/30",
|
||||
|
||||
Reference in New Issue
Block a user