Skip to content

Commit ee96843

Browse files
committed
Register TACO rebound notification plugin
1 parent b520bca commit ee96843

5 files changed

Lines changed: 90 additions & 3 deletions

File tree

docs/strategy_plugin_runtime_contract.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,13 @@ The default registry currently defines:
6868

6969
| Plugin | Supported strategies | Supported mode | Escalated alert channel |
7070
| --- | --- | --- | --- |
71-
| `crisis_response_shadow` | `tqqq_growth_income`, `soxl_soxx_trend_income` | `shadow` | `email` |
71+
| `crisis_response_shadow` | `tqqq_growth_income`, `soxl_soxx_trend_income` | `shadow` | `email`, `sms`, `push`, `telegram` |
72+
| `taco_rebound_shadow` | `tqqq_growth_income` | `shadow` | `email`, `sms`, `push`, `telegram` |
73+
74+
`taco_rebound_shadow` is notification-only. Its artifact may escalate a
75+
manual-review alert when a TACO-style rebound context is active, but it must not
76+
recommend position size, mutate live allocation, or imply broker order
77+
permission.
7278

7379
To expand a plugin later, update the shared definition or pass an explicit
7480
definition registry into the parser/loader. This keeps future plugin eligibility

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "quant-platform-kit"
7-
version = "0.7.30"
7+
version = "0.7.31"
88
description = "Shared broker adapters, domain models, execution ports, and notification utilities for QuantStrategyLab strategies."
99
readme = "README.md"
1010
requires-python = ">=3.9"

src/quant_platform_kit/common/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
CRISIS_RESPONSE_SHADOW_SUPPORTED_STRATEGIES,
4343
DEFAULT_STRATEGY_PLUGIN_DEFINITIONS,
4444
PLUGIN_CRISIS_RESPONSE_SHADOW,
45+
PLUGIN_TACO_REBOUND_SHADOW,
4546
PLUGIN_MODE_SHADOW,
4647
STRATEGY_PLUGIN_ALERT_CHANNEL_EMAIL,
4748
STRATEGY_PLUGIN_ALERT_CHANNEL_PUSH,
@@ -50,6 +51,7 @@
5051
STRATEGY_PLUGIN_ALERT_ACTIONS,
5152
STRATEGY_PLUGIN_NON_ALERT_ROUTES,
5253
SUPPORTED_STRATEGY_PLUGIN_MODES,
54+
TACO_REBOUND_SHADOW_SUPPORTED_STRATEGIES,
5355
StrategyPluginAlertMessage,
5456
StrategyPluginDefinition,
5557
StrategyPluginMountConfig,
@@ -77,6 +79,7 @@
7779
"DEFAULT_TERMINAL_FUNDING_BLOCK_SKIP_REASONS",
7880
"DEFAULT_TERMINAL_STRATEGY_RUN_STAGES",
7981
"PLUGIN_CRISIS_RESPONSE_SHADOW",
82+
"PLUGIN_TACO_REBOUND_SHADOW",
8083
"PLUGIN_MODE_SHADOW",
8184
"STAGE_COMPLETED",
8285
"STAGE_DRY_RUN_COMPLETED",
@@ -94,6 +97,7 @@
9497
"STRATEGY_PLUGIN_ALERT_ACTIONS",
9598
"STRATEGY_PLUGIN_NON_ALERT_ROUTES",
9699
"SUPPORTED_STRATEGY_PLUGIN_MODES",
100+
"TACO_REBOUND_SHADOW_SUPPORTED_STRATEGIES",
97101
"filter_execution_blocking_skips",
98102
"is_terminal_funding_block",
99103
"is_terminal_strategy_run_stage",

src/quant_platform_kit/common/strategy_plugins.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from typing import Any, Callable
1212

1313
PLUGIN_CRISIS_RESPONSE_SHADOW = "crisis_response_shadow"
14+
PLUGIN_TACO_REBOUND_SHADOW = "taco_rebound_shadow"
1415
PLUGIN_MODE_SHADOW = "shadow"
1516
STRATEGY_PLUGIN_ALERT_CHANNEL_EMAIL = "email"
1617
STRATEGY_PLUGIN_ALERT_CHANNEL_SMS = "sms"
@@ -26,6 +27,7 @@
2627
"soxl_soxx_trend_income",
2728
}
2829
)
30+
TACO_REBOUND_SHADOW_SUPPORTED_STRATEGIES = frozenset({"tqqq_growth_income"})
2931

3032

3133
@dataclass(frozen=True)
@@ -76,7 +78,18 @@ def supports_strategy(self, strategy: str) -> bool:
7678
STRATEGY_PLUGIN_ALERT_CHANNEL_PUSH,
7779
STRATEGY_PLUGIN_ALERT_CHANNEL_TELEGRAM,
7880
),
79-
)
81+
),
82+
PLUGIN_TACO_REBOUND_SHADOW: StrategyPluginDefinition(
83+
plugin=PLUGIN_TACO_REBOUND_SHADOW,
84+
supported_strategies=TACO_REBOUND_SHADOW_SUPPORTED_STRATEGIES,
85+
supported_modes=SUPPORTED_STRATEGY_PLUGIN_MODES,
86+
alert_channels=(
87+
STRATEGY_PLUGIN_ALERT_CHANNEL_EMAIL,
88+
STRATEGY_PLUGIN_ALERT_CHANNEL_SMS,
89+
STRATEGY_PLUGIN_ALERT_CHANNEL_PUSH,
90+
STRATEGY_PLUGIN_ALERT_CHANNEL_TELEGRAM,
91+
),
92+
),
8093
}
8194

8295

tests/test_strategy_plugins.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@
77
CRISIS_RESPONSE_SHADOW_SUPPORTED_STRATEGIES,
88
DEFAULT_STRATEGY_PLUGIN_DEFINITIONS,
99
PLUGIN_CRISIS_RESPONSE_SHADOW,
10+
PLUGIN_TACO_REBOUND_SHADOW,
1011
PLUGIN_MODE_SHADOW,
1112
STRATEGY_PLUGIN_ALERT_CHANNEL_EMAIL,
1213
STRATEGY_PLUGIN_ALERT_CHANNEL_PUSH,
1314
STRATEGY_PLUGIN_ALERT_CHANNEL_SMS,
1415
STRATEGY_PLUGIN_ALERT_CHANNEL_TELEGRAM,
16+
TACO_REBOUND_SHADOW_SUPPORTED_STRATEGIES,
1517
StrategyPluginDefinition,
1618
build_strategy_plugin_alert_messages,
1719
build_strategy_plugin_notification_lines,
@@ -111,6 +113,34 @@ def test_default_plugin_definition_limits_crisis_response_to_supported_strategie
111113
mode=PLUGIN_MODE_SHADOW,
112114
)
113115

116+
def test_default_plugin_definition_limits_taco_rebound_to_tqqq_notifications(self):
117+
definition = DEFAULT_STRATEGY_PLUGIN_DEFINITIONS[PLUGIN_TACO_REBOUND_SHADOW]
118+
119+
self.assertEqual(definition.supported_strategies, TACO_REBOUND_SHADOW_SUPPORTED_STRATEGIES)
120+
self.assertEqual(
121+
definition.alert_channels,
122+
(
123+
STRATEGY_PLUGIN_ALERT_CHANNEL_EMAIL,
124+
STRATEGY_PLUGIN_ALERT_CHANNEL_SMS,
125+
STRATEGY_PLUGIN_ALERT_CHANNEL_PUSH,
126+
STRATEGY_PLUGIN_ALERT_CHANNEL_TELEGRAM,
127+
),
128+
)
129+
validate_strategy_plugin_compatibility(
130+
strategy="tqqq_growth_income",
131+
plugin=PLUGIN_TACO_REBOUND_SHADOW,
132+
mode=PLUGIN_MODE_SHADOW,
133+
)
134+
with self.assertRaisesRegex(
135+
ValueError,
136+
"taco_rebound_shadow does not support strategy soxl_soxx_trend_income",
137+
):
138+
validate_strategy_plugin_compatibility(
139+
strategy="soxl_soxx_trend_income",
140+
plugin=PLUGIN_TACO_REBOUND_SHADOW,
141+
mode=PLUGIN_MODE_SHADOW,
142+
)
143+
114144
def test_parse_strategy_plugin_mounts_rejects_unsupported_crisis_response_strategy(self):
115145
raw = [
116146
{
@@ -126,6 +156,20 @@ def test_parse_strategy_plugin_mounts_rejects_unsupported_crisis_response_strate
126156
):
127157
parse_strategy_plugin_mounts(raw)
128158

159+
def test_parse_strategy_plugin_mounts_accepts_taco_rebound_tqqq_notification(self):
160+
mounts = parse_strategy_plugin_mounts(
161+
[
162+
{
163+
"strategy": "tqqq_growth_income",
164+
"plugin": PLUGIN_TACO_REBOUND_SHADOW,
165+
"signal_path": "gs://bucket/taco/latest_signal.json",
166+
}
167+
]
168+
)
169+
170+
self.assertEqual(mounts[0].strategy, "tqqq_growth_income")
171+
self.assertEqual(mounts[0].plugin, PLUGIN_TACO_REBOUND_SHADOW)
172+
129173
def test_plugin_definition_can_extend_future_strategy_support(self):
130174
raw = [
131175
{
@@ -315,6 +359,26 @@ def test_strategy_plugin_true_crisis_builds_generic_alert_message(self):
315359
self.assertNotIn("source=", alerts[0].body)
316360
self.assertTrue(alerts[0].metadata["would_trade_if_enabled"])
317361

362+
def test_taco_rebound_notification_alerts_without_trade_flag(self):
363+
signal = validate_strategy_plugin_signal_payload(
364+
{
365+
**_signal_payload(plugin=PLUGIN_TACO_REBOUND_SHADOW),
366+
"schema_version": "taco_rebound_shadow.v2",
367+
"canonical_route": "taco_rebound",
368+
"suggested_action": "notify_manual_review",
369+
"would_trade_if_enabled": False,
370+
"manual_review_required": True,
371+
},
372+
source_uri="gs://bucket/taco/latest_signal.json",
373+
)
374+
375+
self.assertTrue(should_alert_strategy_plugin_signal(signal))
376+
alerts = build_strategy_plugin_alert_messages([signal], strategy_label="TQQQ Growth Income")
377+
378+
self.assertEqual(len(alerts), 1)
379+
self.assertIn("taco_rebound_shadow", alerts[0].subject)
380+
self.assertFalse(alerts[0].metadata["would_trade_if_enabled"])
381+
318382

319383
if __name__ == "__main__":
320384
unittest.main()

0 commit comments

Comments
 (0)