fix(UX-001): reconcile preview validation behavior
This commit is contained in:
@@ -289,6 +289,34 @@ def _render_backtests_page(workspace_id: str | None = None) -> None:
|
|||||||
row_key="date",
|
row_key="date",
|
||||||
).classes("w-full")
|
).classes("w-full")
|
||||||
|
|
||||||
|
def validate_current_scenario() -> str | None:
|
||||||
|
try:
|
||||||
|
service.run_read_only_scenario(
|
||||||
|
symbol=str(symbol_input.value or ""),
|
||||||
|
start_date=parse_iso_date(start_input.value, "Start date"),
|
||||||
|
end_date=parse_iso_date(end_input.value, "End date"),
|
||||||
|
template_slug=str(template_select.value or ""),
|
||||||
|
underlying_units=float(units_input.value or 0.0),
|
||||||
|
loan_amount=float(loan_input.value or 0.0),
|
||||||
|
margin_call_ltv=float(ltv_input.value or 0.0),
|
||||||
|
)
|
||||||
|
except (ValueError, KeyError) as exc:
|
||||||
|
return str(exc)
|
||||||
|
except Exception:
|
||||||
|
logger.exception(
|
||||||
|
"Backtest preview failed for workspace=%s symbol=%s start=%s end=%s template=%s units=%s loan=%s margin_call_ltv=%s",
|
||||||
|
workspace_id,
|
||||||
|
symbol_input.value,
|
||||||
|
start_input.value,
|
||||||
|
end_input.value,
|
||||||
|
template_select.value,
|
||||||
|
units_input.value,
|
||||||
|
loan_input.value,
|
||||||
|
ltv_input.value,
|
||||||
|
)
|
||||||
|
return "Backtest preview failed. Please verify the scenario inputs and try again."
|
||||||
|
return None
|
||||||
|
|
||||||
def refresh_workspace_seeded_units() -> None:
|
def refresh_workspace_seeded_units() -> None:
|
||||||
validation_label.set_text("")
|
validation_label.set_text("")
|
||||||
entry_spot, entry_error = derive_entry_spot()
|
entry_spot, entry_error = derive_entry_spot()
|
||||||
@@ -304,7 +332,13 @@ def _render_backtests_page(workspace_id: str | None = None) -> None:
|
|||||||
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)
|
||||||
if entry_error:
|
if entry_error:
|
||||||
|
validation_label.set_text(entry_error)
|
||||||
render_result_state("Scenario validation failed", entry_error, tone="warning")
|
render_result_state("Scenario validation failed", entry_error, tone="warning")
|
||||||
|
return
|
||||||
|
validation_error = validate_current_scenario()
|
||||||
|
if validation_error:
|
||||||
|
validation_label.set_text(validation_error)
|
||||||
|
render_result_state("Scenario validation failed", validation_error, tone="warning")
|
||||||
else:
|
else:
|
||||||
mark_results_stale()
|
mark_results_stale()
|
||||||
|
|
||||||
@@ -313,7 +347,14 @@ def _render_backtests_page(workspace_id: str | None = None) -> None:
|
|||||||
entry_spot, entry_error = derive_entry_spot()
|
entry_spot, entry_error = derive_entry_spot()
|
||||||
render_seeded_summary(entry_spot=entry_spot, entry_spot_error=entry_error)
|
render_seeded_summary(entry_spot=entry_spot, entry_spot_error=entry_error)
|
||||||
if entry_error:
|
if entry_error:
|
||||||
|
entry_spot_hint.set_text("Entry spot unavailable until the scenario dates are valid.")
|
||||||
|
validation_label.set_text(entry_error)
|
||||||
render_result_state("Scenario validation failed", entry_error, tone="warning")
|
render_result_state("Scenario validation failed", entry_error, tone="warning")
|
||||||
|
return
|
||||||
|
validation_error = validate_current_scenario()
|
||||||
|
if validation_error:
|
||||||
|
validation_label.set_text(validation_error)
|
||||||
|
render_result_state("Scenario validation failed", validation_error, tone="warning")
|
||||||
else:
|
else:
|
||||||
mark_results_stale()
|
mark_results_stale()
|
||||||
|
|
||||||
|
|||||||
@@ -204,11 +204,12 @@ def _render_event_comparison_page(workspace_id: str | None = None) -> None:
|
|||||||
|
|
||||||
template_slugs = selected_template_slugs()
|
template_slugs = selected_template_slugs()
|
||||||
if not template_slugs:
|
if not template_slugs:
|
||||||
message = "Select at least one strategy template."
|
template_slugs = tuple(service.default_template_selection(str(option["slug"])))
|
||||||
metadata_label.set_text(f"Preset: {option['label']} — {option['description']}")
|
syncing_controls["value"] = True
|
||||||
scenario_label.set_text(message)
|
try:
|
||||||
render_selected_summary(entry_spot=None, entry_spot_error=message)
|
template_select.value = list(template_slugs)
|
||||||
return message
|
finally:
|
||||||
|
syncing_controls["value"] = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
preview_units = float(units_input.value or 0.0)
|
preview_units = float(units_input.value or 0.0)
|
||||||
@@ -260,12 +261,15 @@ def _render_event_comparison_page(workspace_id: str | None = None) -> None:
|
|||||||
def render_report() -> None:
|
def render_report() -> None:
|
||||||
validation_label.set_text("")
|
validation_label.set_text("")
|
||||||
result_panel.clear()
|
result_panel.clear()
|
||||||
|
option = preset_lookup.get(str(preset_select.value or ""))
|
||||||
template_slugs = selected_template_slugs()
|
template_slugs = selected_template_slugs()
|
||||||
if not template_slugs:
|
if option is not None and not template_slugs:
|
||||||
message = "Select at least one strategy template."
|
template_slugs = tuple(service.default_template_selection(str(option["slug"])))
|
||||||
validation_label.set_text(message)
|
syncing_controls["value"] = True
|
||||||
render_result_state("Scenario validation failed", message, tone="warning")
|
try:
|
||||||
return
|
template_select.value = list(template_slugs)
|
||||||
|
finally:
|
||||||
|
syncing_controls["value"] = False
|
||||||
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 ""),
|
||||||
@@ -406,6 +410,7 @@ def _render_event_comparison_page(workspace_id: str | None = None) -> None:
|
|||||||
validation_label.set_text("")
|
validation_label.set_text("")
|
||||||
preview_error = refresh_preview(reset_templates=True, reseed_units=True)
|
preview_error = refresh_preview(reset_templates=True, reseed_units=True)
|
||||||
if preview_error:
|
if preview_error:
|
||||||
|
validation_label.set_text(preview_error)
|
||||||
render_result_state("Scenario validation failed", preview_error, tone="warning")
|
render_result_state("Scenario validation failed", preview_error, tone="warning")
|
||||||
else:
|
else:
|
||||||
mark_results_stale()
|
mark_results_stale()
|
||||||
@@ -416,6 +421,7 @@ def _render_event_comparison_page(workspace_id: str | None = None) -> None:
|
|||||||
validation_label.set_text("")
|
validation_label.set_text("")
|
||||||
preview_error = refresh_preview()
|
preview_error = refresh_preview()
|
||||||
if preview_error:
|
if preview_error:
|
||||||
|
validation_label.set_text(preview_error)
|
||||||
render_result_state("Scenario validation failed", preview_error, tone="warning")
|
render_result_state("Scenario validation failed", preview_error, tone="warning")
|
||||||
else:
|
else:
|
||||||
mark_results_stale()
|
mark_results_stale()
|
||||||
|
|||||||
Reference in New Issue
Block a user