Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion application/rebalance_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
)
from quant_platform_kit.common.strategy_plugins import (
attach_strategy_plugin_metadata,
build_strategy_plugin_error_notification_lines,
build_strategy_plugin_report_payload,
load_configured_strategy_plugin_signals,
parse_strategy_plugin_mounts,
Expand Down Expand Up @@ -200,11 +201,14 @@ def attach_strategy_plugin_result(
error: str | None,
translator: Callable[..., str],
) -> dict[str, Any]:
del translator
if signals:
result.update(build_strategy_plugin_report_payload(signals))
if error:
result["strategy_plugin_error"] = error
result["strategy_plugin_error_lines"] = build_strategy_plugin_error_notification_lines(
error,
translator=translator,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep translator bound for load-error fallback

When a configured strategy plugin fails to load, this new call tries to pass translator after attach_strategy_plugin_result() has already executed del translator a few lines above. In that error path Python raises UnboundLocalError here, so the cycle no longer returns a non-blocking result with strategy_plugin_error; it crashes instead of falling back to the built-in strategy rules.

Useful? React with 👍 / 👎.

)
return result


Expand Down
5 changes: 5 additions & 0 deletions notifications/telegram.py
Original file line number Diff line number Diff line change
Expand Up @@ -1078,6 +1078,11 @@ def render_cycle_summary(result: Mapping[str, Any], *, lang: str = "en") -> str:
lines.extend(_format_signal_lines(execution, translator=translator))
lines.append(SEPARATOR)
lines.extend(target_diff_lines)
lines.extend(
str(line).strip()
for line in result.get("strategy_plugin_error_lines") or ()
if str(line).strip()
)
execution_notes = tuple(result.get("execution_notes") or allocation.get("small_account_whole_share_cash_notes") or ())
lines.extend(format_small_account_cash_substitution_notes(execution_notes, translator=translator))
if submitted:
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ authors = [
]
dependencies = [
"firstrade==0.0.39",
"quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@2a711adf60b585ca02932bab9ee1bac7ce1df7c6",
"us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@fdd39ef0313181bee9083319b87b7175c32b364d",
"quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@1a31ddde0dde0f2ad423e841a84af3ba0869e612",
"us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@0ad01faaa2741195d06ecf8dae6a0f3fda712080",
"google-cloud-storage",
"requests",
]
Expand Down
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
flask
gunicorn
firstrade==0.0.39
quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@2a711adf60b585ca02932bab9ee1bac7ce1df7c6
us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@fdd39ef0313181bee9083319b87b7175c32b364d
quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@1a31ddde0dde0f2ad423e841a84af3ba0869e612
us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@0ad01faaa2741195d06ecf8dae6a0f3fda712080
google-cloud-storage
requests
pytest
3 changes: 3 additions & 0 deletions tests/test_rebalance_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,9 @@ def test_run_strategy_cycle_strategy_plugin_load_error_is_non_blocking(monkeypat
assert result["ok"] is True
assert result["action_done"] is True
assert result["strategy_plugin_error"].startswith("JSONDecodeError:")
assert result["strategy_plugin_error_lines"] == (
"⚠️ Plugin signal failed to load: invalid plugin mount JSON; this run falls back to built-in strategy rules",
)
assert result["strategy_plugin_alert_email_sent_count"] == 0
assert result["strategy_plugin_alert_sms_sent_count"] == 0

Expand Down