From 4e9a610452853e9f7bdad9dfe1426fc499753468 Mon Sep 17 00:00:00 2001 From: Bu5hm4nn Date: Sat, 4 Apr 2026 22:40:39 +0200 Subject: [PATCH] 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 --- app/pages/backtests.py | 79 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 69 insertions(+), 10 deletions(-) diff --git a/app/pages/backtests.py b/app/pages/backtests.py index 3e8828a..0934faf 100644 --- a/app/pages/backtests.py +++ b/app/pages/backtests.py @@ -944,12 +944,27 @@ def _render_backtests_page(workspace_id: str | None = None) -> None: "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 = [ - ("Start value", f"${result.get('total_pnl', 0):,.0f}"), - ("End value hedged", f"${result.get('total_pnl_pct', 0)*100:.1f}%"), - ("Hedge cost", f"${result.get('hedging_cost', 0):,.0f}"), - ("Hedge cost %", f"{result.get('hedging_cost_pct', 0)*100:.2f}%"), + ("Start value", f"${start_value:,.0f}"), + ("End value hedged", f"${end_value_hedged:,.0f}"), + ("Hedge cost", f"${hedge_cost:,.0f}"), + ("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"): 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(value).classes("text-2xl font-bold text-slate-900 dark:text-slate-100") - # Margin call info - if result.get("margin_call_events"): + # Additional metrics row + 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( + "rounded-xl border border-slate-200 bg-slate-50 p-4 shadow-none dark:border-slate-800 dark:bg-slate-950" + ): + 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") + + # 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-amber-200 bg-amber-50 p-4 dark:border-amber-900/60 dark:bg-amber-950/30" + "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(f"Margin calls: {len(result['margin_call_events'])}").classes( - "text-amber-800 dark:text-amber-200" + 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 if str(data_source_select.value) == "databento":