fix: update render_job_result to use correct result field names
The job serialization was fixed to use new field names, but the UI render function was still using old field names (total_pnl, hedging_cost, etc.) which don't exist anymore. Now uses: - start_value, end_value_hedged_net, total_hedge_cost from summary_metrics - template_results[0].daily_path for daily results table - Added margin call metrics display
This commit is contained in:
@@ -944,12 +944,27 @@ def _render_backtests_page(workspace_id: str | None = None) -> None:
|
|||||||
"text-sm text-slate-500 dark:text-slate-400"
|
"text-sm text-slate-500 dark:text-slate-400"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Summary metrics
|
# Get template results for summary
|
||||||
|
template_results = result.get("template_results", [])
|
||||||
|
first_template = template_results[0] if template_results else {}
|
||||||
|
summary = first_template.get("summary_metrics", {})
|
||||||
|
|
||||||
|
# Summary metrics using correct field names
|
||||||
|
start_value = summary.get("start_value", result.get("start_value", 0))
|
||||||
|
end_value_hedged = summary.get("end_value_hedged_net", 0)
|
||||||
|
hedge_cost = summary.get("total_hedge_cost", result.get("total_hedge_cost", 0))
|
||||||
|
max_ltv_hedged = summary.get("max_ltv_hedged", 0)
|
||||||
|
margin_days_hedged = summary.get("margin_call_days_hedged", 0)
|
||||||
|
margin_days_unhedged = summary.get("margin_call_days_unhedged", 0)
|
||||||
|
|
||||||
|
# Calculate hedge cost percentage
|
||||||
|
hedge_cost_pct = (hedge_cost / start_value * 100) if start_value > 0 else 0
|
||||||
|
|
||||||
summary_data = [
|
summary_data = [
|
||||||
("Start value", f"${result.get('total_pnl', 0):,.0f}"),
|
("Start value", f"${start_value:,.0f}"),
|
||||||
("End value hedged", f"${result.get('total_pnl_pct', 0)*100:.1f}%"),
|
("End value hedged", f"${end_value_hedged:,.0f}"),
|
||||||
("Hedge cost", f"${result.get('hedging_cost', 0):,.0f}"),
|
("Hedge cost", f"${hedge_cost:,.0f}"),
|
||||||
("Hedge cost %", f"{result.get('hedging_cost_pct', 0)*100:.2f}%"),
|
("Hedge cost %", f"{hedge_cost_pct:.2f}%"),
|
||||||
]
|
]
|
||||||
with ui.grid(columns=4).classes("w-full gap-4 max-lg:grid-cols-2 max-sm:grid-cols-1"):
|
with ui.grid(columns=4).classes("w-full gap-4 max-lg:grid-cols-2 max-sm:grid-cols-1"):
|
||||||
for label, value in summary_data:
|
for label, value in summary_data:
|
||||||
@@ -959,14 +974,58 @@ def _render_backtests_page(workspace_id: str | None = None) -> None:
|
|||||||
ui.label(label).classes("text-sm text-slate-500 dark:text-slate-400")
|
ui.label(label).classes("text-sm text-slate-500 dark:text-slate-400")
|
||||||
ui.label(value).classes("text-2xl font-bold text-slate-900 dark:text-slate-100")
|
ui.label(value).classes("text-2xl font-bold text-slate-900 dark:text-slate-100")
|
||||||
|
|
||||||
# Margin call info
|
# Additional metrics row
|
||||||
if result.get("margin_call_events"):
|
with ui.grid(columns=4).classes("w-full gap-4 max-lg:grid-cols-2 max-sm:grid-cols-1"):
|
||||||
|
extra_data = [
|
||||||
|
("Max LTV hedged", f"{max_ltv_hedged:.1%}"),
|
||||||
|
("Margin call days hedged", str(margin_days_hedged)),
|
||||||
|
("Margin call days unhedged", str(margin_days_unhedged)),
|
||||||
|
("Breached threshold", "No" if margin_days_hedged == 0 else "Yes"),
|
||||||
|
]
|
||||||
|
for label, value in extra_data:
|
||||||
with ui.card().classes(
|
with ui.card().classes(
|
||||||
"w-full mt-4 rounded-xl border border-amber-200 bg-amber-50 p-4 dark:border-amber-900/60 dark:bg-amber-950/30"
|
"rounded-xl border border-slate-200 bg-slate-50 p-4 shadow-none dark:border-slate-800 dark:bg-slate-950"
|
||||||
):
|
):
|
||||||
ui.label(f"Margin calls: {len(result['margin_call_events'])}").classes(
|
ui.label(label).classes("text-sm text-slate-500 dark:text-slate-400")
|
||||||
"text-amber-800 dark:text-amber-200"
|
ui.label(value).classes("text-2xl font-bold text-slate-900 dark:text-slate-100")
|
||||||
|
|
||||||
|
# Daily path table
|
||||||
|
daily_path = first_template.get("daily_path", [])
|
||||||
|
if daily_path:
|
||||||
|
with ui.card().classes(
|
||||||
|
"w-full mt-4 rounded-xl border border-slate-200 bg-slate-50 p-4 shadow-none dark:border-slate-800 dark:bg-slate-950"
|
||||||
|
):
|
||||||
|
ui.label("Daily Results").classes(
|
||||||
|
"text-md font-semibold text-slate-900 dark:text-slate-100 mb-2"
|
||||||
)
|
)
|
||||||
|
ui.table(
|
||||||
|
columns=[
|
||||||
|
{"name": "date", "label": "Date", "field": "date", "align": "left"},
|
||||||
|
{"name": "spot", "label": "Spot", "field": "spot", "align": "right"},
|
||||||
|
{
|
||||||
|
"name": "ltv_hedged",
|
||||||
|
"label": "LTV hedged",
|
||||||
|
"field": "ltv_hedged",
|
||||||
|
"align": "right",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "margin_call",
|
||||||
|
"label": "Margin call",
|
||||||
|
"field": "margin_call",
|
||||||
|
"align": "center",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
rows=[
|
||||||
|
{
|
||||||
|
"date": dp.get("date", ""),
|
||||||
|
"spot": f"${dp.get('spot_close', 0):,.2f}",
|
||||||
|
"ltv_hedged": f"{dp.get('ltv_hedged', 0):.1%}",
|
||||||
|
"margin_call": "Yes" if dp.get("margin_call_hedged") else "No",
|
||||||
|
}
|
||||||
|
for dp in daily_path
|
||||||
|
],
|
||||||
|
row_key="date",
|
||||||
|
).classes("w-full")
|
||||||
|
|
||||||
# Update cost estimate for Databento
|
# Update cost estimate for Databento
|
||||||
if str(data_source_select.value) == "databento":
|
if str(data_source_select.value) == "databento":
|
||||||
|
|||||||
Reference in New Issue
Block a user