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
15 changes: 13 additions & 2 deletions application/runtime_composer.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,12 @@ def build_rebalance_runtime(
post_submit_order=notification_adapters.post_submit_order,
)

def build_rebalance_config(self, *, strategy_plugin_signals=()) -> LongBridgeRebalanceConfig:
def build_rebalance_config(
self,
*,
strategy_plugin_signals=(),
strategy_plugin_error: str | None = None,
) -> LongBridgeRebalanceConfig:
market_scope_line = self.translator(
"market_scope_detail",
market=self.market,
Expand All @@ -204,6 +209,12 @@ def build_rebalance_config(self, *, strategy_plugin_signals=()) -> LongBridgeReb
lambda _signals: (),
)
plugin_lines = tuple(build_plugin_lines(tuple(strategy_plugin_signals or ())))
build_plugin_error_lines = getattr(
self.strategy_adapters,
"build_strategy_plugin_error_notification_lines",
lambda _error: (),
)
plugin_error_lines = tuple(build_plugin_error_lines(strategy_plugin_error))
return LongBridgeRebalanceConfig(
limit_sell_discount=self.limit_sell_discount,
limit_buy_premium=self.limit_buy_premium,
Expand All @@ -219,7 +230,7 @@ def build_rebalance_config(self, *, strategy_plugin_signals=()) -> LongBridgeReb
min_order_notional_usd=self.min_order_notional_usd,
safe_haven_cash_substitute_threshold_usd=self.safe_haven_cash_substitute_threshold_usd,
sleeper=self.sleeper,
extra_notification_lines=(market_scope_line, *plugin_lines),
extra_notification_lines=(market_scope_line, *plugin_lines, *plugin_error_lines),
strategy_plugin_signals=tuple(strategy_plugin_signals or ()),
execution_dedup_enabled=resolve_execution_dedup_enabled(
env_reader=self.env_reader,
Expand Down
4 changes: 4 additions & 0 deletions application/runtime_strategy_adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from quant_platform_kit.common.strategy_plugins import (
build_strategy_plugin_alert_messages,
build_strategy_plugin_error_notification_lines,
build_strategy_plugin_notification_lines,
should_alert_strategy_plugin_signal,
translate_strategy_plugin_value,
Expand Down Expand Up @@ -89,6 +90,9 @@ def translate_strategy_plugin_value(self, category: str, raw_value: str | None)
def build_strategy_plugin_notification_lines(self, signals) -> tuple[str, ...]:
return build_strategy_plugin_notification_lines(signals, translator=self.translator)

def build_strategy_plugin_error_notification_lines(self, error) -> tuple[str, ...]:
return build_strategy_plugin_error_notification_lines(error, translator=self.translator)

def should_alert_strategy_plugin_signal(self, signal) -> bool:
return should_alert_strategy_plugin_signal(signal)

Expand Down
5 changes: 4 additions & 1 deletion main.py
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,10 @@ def run_strategy(*, force_run: bool = False, validation_only: bool = False, vali
)
cycle_result = run_rebalance_cycle(
runtime=rebalance_runtime,
config=composer.build_rebalance_config(strategy_plugin_signals=strategy_plugin_signals),
config=composer.build_rebalance_config(
strategy_plugin_signals=strategy_plugin_signals,
strategy_plugin_error=strategy_plugin_error,
),
)
signal_snapshot = {}
if cycle_result is not None:
Expand Down
6 changes: 3 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
flask
gunicorn
quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@2a711adf60b585ca02932bab9ee1bac7ce1df7c6
us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@fdd39ef0313181bee9083319b87b7175c32b364d
hk-equity-strategies @ git+https://github.com/QuantStrategyLab/HkEquityStrategies.git@02af62bc7af7b8ffdbe8575421434e455ab00d66
quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@1a31ddde0dde0f2ad423e841a84af3ba0869e612
us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@0ad01faaa2741195d06ecf8dae6a0f3fda712080
hk-equity-strategies @ git+https://github.com/QuantStrategyLab/HkEquityStrategies.git@1c50d2fcedc41b36d387366d0a9209ee759f0308
pandas
requests
pytz
Expand Down
4 changes: 2 additions & 2 deletions tests/test_request_handling.py
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ def with_prefix(self, message):
def build_rebalance_runtime(self, *, silent_cycle_notifications=False):
return types.SimpleNamespace()

def build_rebalance_config(self, *, strategy_plugin_signals=()):
def build_rebalance_config(self, *, strategy_plugin_signals=(), strategy_plugin_error=None):
return types.SimpleNamespace()

module.build_composer = lambda *, dry_run_only_override=None: FakeComposer()
Expand Down Expand Up @@ -555,7 +555,7 @@ def build_rebalance_runtime(self, *, silent_cycle_notifications=False):
observed["silent_cycle_notifications"] = silent_cycle_notifications
return types.SimpleNamespace()

def build_rebalance_config(self, *, strategy_plugin_signals=()):
def build_rebalance_config(self, *, strategy_plugin_signals=(), strategy_plugin_error=None):
return types.SimpleNamespace()

module.build_composer = lambda *, dry_run_only_override=None: observed.__setitem__("override", dry_run_only_override) or FakeComposer()
Expand Down
9 changes: 8 additions & 1 deletion tests/test_runtime_composer.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ def fake_bootstrap_builder(**kwargs):
strategy_adapters=SimpleNamespace(
calculate_strategy_indicators="strategy-indicators",
resolve_rebalance_plan="resolve-plan",
build_strategy_plugin_notification_lines=lambda signals: tuple(signals),
build_strategy_plugin_error_notification_lines=lambda error: (f"plugin-error:{error}",) if error else (),
),
estimate_max_purchase_quantity_fn="estimate-max-purchase",
fetch_order_status_fn="fetch-order-status",
Expand Down Expand Up @@ -106,7 +108,10 @@ def fake_bootstrap_builder(**kwargs):
reporting_adapters = composer.build_reporting_adapters()
runtime = composer.build_rebalance_runtime()
silent_runtime = composer.build_rebalance_runtime(silent_cycle_notifications=True)
config = composer.build_rebalance_config()
config = composer.build_rebalance_config(
strategy_plugin_signals=("plugin-line",),
strategy_plugin_error="bad config",
)

assert notification_adapters.notification_port == "notification-port"
assert reporting_adapters == "reporting-adapters"
Expand All @@ -118,6 +123,8 @@ def fake_bootstrap_builder(**kwargs):
assert observed["reporting_builder"]["runtime_assembly"].runtime_target.platform_id == "longbridge"
assert observed["reporting_builder"]["runtime_assembly"].runtime_target.strategy_profile == "soxl_soxx_trend_income"
assert observed["reporting_builder"]["runtime_assembly"].runtime_target.execution_mode == "paper"
assert "plugin-line" in config.extra_notification_lines
assert "plugin-error:bad config" in config.extra_notification_lines
assert observed["bootstrap_builder"]["secret_name"] == "secret-1"
assert observed["bootstrap_builder"]["calculate_strategy_indicators_fn"] == "strategy-indicators"
assert runtime.bootstrap == "bootstrap"
Expand Down
5 changes: 5 additions & 0 deletions tests/test_runtime_strategy_adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,8 @@ def fake_load(mounts, *, strategy_profile):
signal_text_fn=lambda icon: f"signal:{icon}",
translator=lambda key, **kwargs: {
"strategy_plugin_line": "plugin={plugin}|mode={mode}|route={route}|action={action}",
"strategy_plugin_error_line": "plugin-error={reason}|fallback=built-in",
"strategy_plugin_error_reason_ValueError": "config validation failed",
"strategy_plugin_name_crisis_response_shadow": "Crisis",
"strategy_plugin_mode_shadow": "shadow",
"strategy_plugin_route_no_action": "no action",
Expand All @@ -301,6 +303,9 @@ def fake_load(mounts, *, strategy_profile):
assert adapters.build_strategy_plugin_notification_lines(signals) == (
"plugin=Crisis|mode=shadow|route=no action|action=monitor",
)
assert adapters.build_strategy_plugin_error_notification_lines("ValueError: bad config") == (
"plugin-error=config validation failed|fallback=built-in",
)
assert adapters.build_strategy_plugin_alert_messages(signals) == ()


Expand Down