fix(UX-001): tighten historical stale state handling
This commit is contained in:
@@ -290,6 +290,7 @@ def _render_backtests_page(workspace_id: str | None = None) -> None:
|
|||||||
).classes("w-full")
|
).classes("w-full")
|
||||||
|
|
||||||
def refresh_workspace_seeded_units() -> None:
|
def refresh_workspace_seeded_units() -> None:
|
||||||
|
validation_label.set_text("")
|
||||||
entry_spot, entry_error = derive_entry_spot()
|
entry_spot, entry_error = derive_entry_spot()
|
||||||
if (
|
if (
|
||||||
workspace_id
|
workspace_id
|
||||||
@@ -302,11 +303,19 @@ def _render_backtests_page(workspace_id: str | None = None) -> None:
|
|||||||
else:
|
else:
|
||||||
entry_spot_hint.set_text("Entry spot unavailable until the scenario dates are valid.")
|
entry_spot_hint.set_text("Entry spot unavailable until the scenario dates are valid.")
|
||||||
render_seeded_summary(entry_spot=entry_spot, entry_spot_error=entry_error)
|
render_seeded_summary(entry_spot=entry_spot, entry_spot_error=entry_error)
|
||||||
mark_results_stale()
|
if entry_error:
|
||||||
|
render_result_state("Scenario validation failed", entry_error, tone="warning")
|
||||||
|
else:
|
||||||
|
mark_results_stale()
|
||||||
|
|
||||||
def on_form_change() -> None:
|
def on_form_change() -> None:
|
||||||
render_seeded_summary()
|
validation_label.set_text("")
|
||||||
mark_results_stale()
|
entry_spot, entry_error = derive_entry_spot()
|
||||||
|
render_seeded_summary(entry_spot=entry_spot, entry_spot_error=entry_error)
|
||||||
|
if entry_error:
|
||||||
|
render_result_state("Scenario validation failed", entry_error, tone="warning")
|
||||||
|
else:
|
||||||
|
mark_results_stale()
|
||||||
|
|
||||||
def run_backtest() -> None:
|
def run_backtest() -> None:
|
||||||
validation_label.set_text("")
|
validation_label.set_text("")
|
||||||
|
|||||||
@@ -187,13 +187,13 @@ def _render_event_comparison_page(workspace_id: str | None = None) -> None:
|
|||||||
tone="info",
|
tone="info",
|
||||||
)
|
)
|
||||||
|
|
||||||
def refresh_preview(*, reset_templates: bool = False, reseed_units: bool = False) -> None:
|
def refresh_preview(*, reset_templates: bool = False, reseed_units: bool = False) -> str | None:
|
||||||
option = preset_lookup.get(str(preset_select.value or ""))
|
option = preset_lookup.get(str(preset_select.value or ""))
|
||||||
if option is None:
|
if option is None:
|
||||||
metadata_label.set_text("")
|
metadata_label.set_text("")
|
||||||
scenario_label.set_text("")
|
scenario_label.set_text("")
|
||||||
render_selected_summary(entry_spot=None)
|
render_selected_summary(entry_spot=None)
|
||||||
return
|
return None
|
||||||
|
|
||||||
if reset_templates:
|
if reset_templates:
|
||||||
syncing_controls["value"] = True
|
syncing_controls["value"] = True
|
||||||
@@ -202,12 +202,20 @@ def _render_event_comparison_page(workspace_id: str | None = None) -> None:
|
|||||||
finally:
|
finally:
|
||||||
syncing_controls["value"] = False
|
syncing_controls["value"] = False
|
||||||
|
|
||||||
|
template_slugs = selected_template_slugs()
|
||||||
|
if not template_slugs:
|
||||||
|
message = "Select at least one strategy template."
|
||||||
|
metadata_label.set_text(f"Preset: {option['label']} — {option['description']}")
|
||||||
|
scenario_label.set_text(message)
|
||||||
|
render_selected_summary(entry_spot=None, entry_spot_error=message)
|
||||||
|
return message
|
||||||
|
|
||||||
try:
|
try:
|
||||||
preview_units = float(units_input.value or 0.0)
|
preview_units = float(units_input.value or 0.0)
|
||||||
if workspace_id and config is not None and reseed_units:
|
if workspace_id and config is not None and reseed_units:
|
||||||
preview_scenario = service.preview_scenario(
|
preview_scenario = service.preview_scenario(
|
||||||
preset_slug=str(option["slug"]),
|
preset_slug=str(option["slug"]),
|
||||||
template_slugs=selected_template_slugs(),
|
template_slugs=template_slugs,
|
||||||
underlying_units=1.0,
|
underlying_units=1.0,
|
||||||
loan_amount=float(loan_input.value or 0.0),
|
loan_amount=float(loan_input.value or 0.0),
|
||||||
margin_call_ltv=float(ltv_input.value or 0.0),
|
margin_call_ltv=float(ltv_input.value or 0.0),
|
||||||
@@ -224,7 +232,7 @@ def _render_event_comparison_page(workspace_id: str | None = None) -> None:
|
|||||||
syncing_controls["value"] = False
|
syncing_controls["value"] = False
|
||||||
scenario = service.preview_scenario(
|
scenario = service.preview_scenario(
|
||||||
preset_slug=str(option["slug"]),
|
preset_slug=str(option["slug"]),
|
||||||
template_slugs=selected_template_slugs(),
|
template_slugs=template_slugs,
|
||||||
underlying_units=preview_units,
|
underlying_units=preview_units,
|
||||||
loan_amount=float(loan_input.value or 0.0),
|
loan_amount=float(loan_input.value or 0.0),
|
||||||
margin_call_ltv=float(ltv_input.value or 0.0),
|
margin_call_ltv=float(ltv_input.value or 0.0),
|
||||||
@@ -233,7 +241,7 @@ def _render_event_comparison_page(workspace_id: str | None = None) -> None:
|
|||||||
metadata_label.set_text(f"Preset: {option['label']} — {option['description']}")
|
metadata_label.set_text(f"Preset: {option['label']} — {option['description']}")
|
||||||
scenario_label.set_text(str(exc))
|
scenario_label.set_text(str(exc))
|
||||||
render_selected_summary(entry_spot=None, entry_spot_error=str(exc))
|
render_selected_summary(entry_spot=None, entry_spot_error=str(exc))
|
||||||
return
|
return str(exc)
|
||||||
preset = service.event_preset_service.get_preset(str(option["slug"]))
|
preset = service.event_preset_service.get_preset(str(option["slug"]))
|
||||||
metadata_label.set_text(f"Preset: {option['label']} — {option['description']}")
|
metadata_label.set_text(f"Preset: {option['label']} — {option['description']}")
|
||||||
scenario_label.set_text(
|
scenario_label.set_text(
|
||||||
@@ -247,14 +255,21 @@ def _render_event_comparison_page(workspace_id: str | None = None) -> None:
|
|||||||
+ f" · Entry spot: ${scenario.initial_portfolio.entry_spot:,.2f}"
|
+ f" · Entry spot: ${scenario.initial_portfolio.entry_spot:,.2f}"
|
||||||
)
|
)
|
||||||
render_selected_summary(entry_spot=float(scenario.initial_portfolio.entry_spot))
|
render_selected_summary(entry_spot=float(scenario.initial_portfolio.entry_spot))
|
||||||
|
return None
|
||||||
|
|
||||||
def render_report() -> None:
|
def render_report() -> None:
|
||||||
validation_label.set_text("")
|
validation_label.set_text("")
|
||||||
result_panel.clear()
|
result_panel.clear()
|
||||||
|
template_slugs = selected_template_slugs()
|
||||||
|
if not template_slugs:
|
||||||
|
message = "Select at least one strategy template."
|
||||||
|
validation_label.set_text(message)
|
||||||
|
render_result_state("Scenario validation failed", message, tone="warning")
|
||||||
|
return
|
||||||
try:
|
try:
|
||||||
report = service.run_read_only_comparison(
|
report = service.run_read_only_comparison(
|
||||||
preset_slug=str(preset_select.value or ""),
|
preset_slug=str(preset_select.value or ""),
|
||||||
template_slugs=selected_template_slugs(),
|
template_slugs=template_slugs,
|
||||||
underlying_units=float(units_input.value or 0.0),
|
underlying_units=float(units_input.value or 0.0),
|
||||||
loan_amount=float(loan_input.value or 0.0),
|
loan_amount=float(loan_input.value or 0.0),
|
||||||
margin_call_ltv=float(ltv_input.value or 0.0),
|
margin_call_ltv=float(ltv_input.value or 0.0),
|
||||||
@@ -388,14 +403,22 @@ def _render_event_comparison_page(workspace_id: str | None = None) -> None:
|
|||||||
def on_preset_change() -> None:
|
def on_preset_change() -> None:
|
||||||
if syncing_controls["value"]:
|
if syncing_controls["value"]:
|
||||||
return
|
return
|
||||||
refresh_preview(reset_templates=True, reseed_units=True)
|
validation_label.set_text("")
|
||||||
mark_results_stale()
|
preview_error = refresh_preview(reset_templates=True, reseed_units=True)
|
||||||
|
if preview_error:
|
||||||
|
render_result_state("Scenario validation failed", preview_error, tone="warning")
|
||||||
|
else:
|
||||||
|
mark_results_stale()
|
||||||
|
|
||||||
def on_preview_input_change() -> None:
|
def on_preview_input_change() -> None:
|
||||||
if syncing_controls["value"]:
|
if syncing_controls["value"]:
|
||||||
return
|
return
|
||||||
refresh_preview()
|
validation_label.set_text("")
|
||||||
mark_results_stale()
|
preview_error = refresh_preview()
|
||||||
|
if preview_error:
|
||||||
|
render_result_state("Scenario validation failed", preview_error, tone="warning")
|
||||||
|
else:
|
||||||
|
mark_results_stale()
|
||||||
|
|
||||||
preset_select.on_value_change(lambda _: on_preset_change())
|
preset_select.on_value_change(lambda _: on_preset_change())
|
||||||
template_select.on_value_change(lambda _: on_preview_input_change())
|
template_select.on_value_change(lambda _: on_preview_input_change())
|
||||||
|
|||||||
Reference in New Issue
Block a user