2222)
2323from .taco_panic_rebound_research import (
2424 DEFAULT_EVENT_SET ,
25- EVENT_KIND_SHOCK ,
2625 EVENT_KIND_SOFTENING ,
2726 TRADE_WAR_EVENT_SETS ,
2827 TradeWarEvent ,
2928 resolve_trade_war_event_set ,
3029)
3130from .yfinance_prices import download_price_history
3231
33- SCHEMA_VERSION = "taco_rebound_shadow.v1 "
32+ SCHEMA_VERSION = "taco_rebound_shadow.v2 "
3433SHADOW_MODE = "shadow"
3534TACO_REBOUND_PROFILE = "taco_rebound_shadow"
3635ROUTE_TACO_REBOUND = "taco_rebound"
37- ACTION_INCREASE_REBOUND_BUDGET = "increase_rebound_budget "
36+ ACTION_NOTIFY_MANUAL_REVIEW = "notify_manual_review "
3837ACTION_WATCH_ONLY = "watch_only"
3938ACTION_NO_ACTION = "no_action"
40- ACTION_BLOCKED = "blocked"
4139DEFAULT_OUTPUT_DIR = "data/output/taco_rebound_shadow"
4240DEFAULT_START_DATE = "2018-01-01"
4341DEFAULT_MAX_PRICE_AGE_DAYS = 4
4442DEFAULT_ACTIVE_SIGNAL_DAYS = 10
45- DEFAULT_TARIFF_SOFTENING_SLEEVE = 0.05
46- DEFAULT_GEOPOLITICAL_DEESCALATION_SLEEVE = 0.10
47- DEFAULT_SHOCK_SLEEVE = 0.0
48- DEFAULT_MAX_SLEEVE = 0.10
4943HARD_DEFENSE_BREAK_BEAR_REGIONS = frozenset ({"iran_middle_east" })
5044
5145
@@ -57,29 +51,18 @@ def _next_index_date(index: pd.DatetimeIndex, raw_date: str | pd.Timestamp) -> p
5751 return pd .Timestamp (candidates [0 ]).normalize ()
5852
5953
60- def _event_sleeve (
61- event : TradeWarEvent ,
62- * ,
63- tariff_softening_sleeve : float ,
64- geopolitical_deescalation_sleeve : float ,
65- shock_sleeve : float ,
66- max_sleeve : float ,
67- ) -> float :
68- if event .kind == EVENT_KIND_SHOCK :
69- sleeve = float (shock_sleeve )
70- elif str (event .region ).strip ().lower () == "iran_middle_east" :
71- sleeve = float (geopolitical_deescalation_sleeve )
72- else :
73- sleeve = float (tariff_softening_sleeve )
74- return max (0.0 , min (float (max_sleeve ), sleeve ))
75-
76-
7754def _event_allows_hard_defense (event : TradeWarEvent | None ) -> bool :
7855 if event is None or event .kind != EVENT_KIND_SOFTENING :
7956 return False
8057 return str (event .region ).strip ().lower () in HARD_DEFENSE_BREAK_BEAR_REGIONS
8158
8259
60+ def _event_notice_priority (event : TradeWarEvent ) -> tuple [int , int , str ]:
61+ kind_priority = 1 if event .kind == EVENT_KIND_SOFTENING else 0
62+ region_priority = 1 if str (event .region ).strip ().lower () in HARD_DEFENSE_BREAK_BEAR_REGIONS else 0
63+ return kind_priority , region_priority , str (event .event_date )
64+
65+
8366def _active_recognized_events (
8467 events : Sequence [TradeWarEvent ],
8568 * ,
@@ -107,10 +90,6 @@ def build_taco_rebound_shadow_signal(
10790 benchmark_symbol : str = DEFAULT_BENCHMARK_SYMBOL ,
10891 attack_symbol : str = DEFAULT_ATTACK_SYMBOL ,
10992 active_signal_days : int = DEFAULT_ACTIVE_SIGNAL_DAYS ,
110- tariff_softening_sleeve : float = DEFAULT_TARIFF_SOFTENING_SLEEVE ,
111- geopolitical_deescalation_sleeve : float = DEFAULT_GEOPOLITICAL_DEESCALATION_SLEEVE ,
112- shock_sleeve : float = DEFAULT_SHOCK_SLEEVE ,
113- max_sleeve : float = DEFAULT_MAX_SLEEVE ,
11493 suppress_when_price_crisis_guard_active : bool = True ,
11594 crisis_guard_drawdown : float = DEFAULT_PRICE_CRISIS_GUARD_DRAWDOWN ,
11695 crisis_guard_ma_days : int = DEFAULT_PRICE_CRISIS_GUARD_MA_DAYS ,
@@ -171,43 +150,40 @@ def build_taco_rebound_shadow_signal(
171150
172151 selected_event : TradeWarEvent | None = None
173152 selected_event_signal_date : pd .Timestamp | None = None
174- sleeve = 0.0
175153 for event , event_signal_date in active_events :
176- candidate_sleeve = _event_sleeve (
177- event ,
178- tariff_softening_sleeve = float (tariff_softening_sleeve ),
179- geopolitical_deescalation_sleeve = float (geopolitical_deescalation_sleeve ),
180- shock_sleeve = float (shock_sleeve ),
181- max_sleeve = float (max_sleeve ),
182- )
183- if candidate_sleeve >= sleeve :
154+ if selected_event is None or _event_notice_priority (event ) >= _event_notice_priority (selected_event ):
184155 selected_event = event
185156 selected_event_signal_date = event_signal_date
186- sleeve = candidate_sleeve
187157
188- canonical_route = ROUTE_TACO_REBOUND if sleeve > 0.0 else "no_action"
189- suggested_action = ACTION_INCREASE_REBOUND_BUDGET if sleeve > 0.0 else ACTION_NO_ACTION
190- would_trade_if_enabled = sleeve > 0.0
191- allow_hard_defense = bool (would_trade_if_enabled and _event_allows_hard_defense (selected_event ))
158+ rebound_context_active = bool (
159+ selected_event is not None and selected_event .kind == EVENT_KIND_SOFTENING and not crisis_guard_active
160+ )
161+ manual_review_required = rebound_context_active
162+ canonical_route = ROUTE_TACO_REBOUND if manual_review_required else "no_action"
163+ suggested_action = ACTION_NOTIFY_MANUAL_REVIEW if manual_review_required else ACTION_NO_ACTION
164+ would_trade_if_enabled = False
165+ event_rebound_break_bear = bool (manual_review_required and _event_allows_hard_defense (selected_event ))
192166 suppression_reason = ""
193- if active_events and sleeve <= 0.0 :
167+ notification_reason = "event rebound context active" if manual_review_required else ""
168+ if active_events and not manual_review_required :
194169 suggested_action = ACTION_WATCH_ONLY
195- suppression_reason = "active event has zero configured sleeve"
196- allow_hard_defense = False
170+ suppression_reason = "active event is not a softening/de-escalation rebound context"
197171 if crisis_guard_active :
198172 canonical_route = "no_action"
199- suggested_action = ACTION_BLOCKED
200- would_trade_if_enabled = False
201- sleeve = 0.0
202- allow_hard_defense = False
173+ suggested_action = ACTION_WATCH_ONLY
174+ manual_review_required = False
175+ rebound_context_active = False
176+ event_rebound_break_bear = False
203177 suppression_reason = "price crisis guard active"
178+ notification_reason = ""
204179 if kill_reasons :
205180 canonical_route = "no_action"
206- suggested_action = ACTION_BLOCKED
207- would_trade_if_enabled = False
208- sleeve = 0.0
209- allow_hard_defense = False
181+ suggested_action = ACTION_WATCH_ONLY
182+ manual_review_required = False
183+ rebound_context_active = False
184+ event_rebound_break_bear = False
210185 suppression_reason = "; " .join (kill_reasons )
186+ notification_reason = ""
211187
212188 generated_at = datetime .now (timezone .utc ).isoformat ()
213189 payload = {
@@ -217,9 +193,10 @@ def build_taco_rebound_shadow_signal(
217193 "profile" : TACO_REBOUND_PROFILE ,
218194 "canonical_route" : canonical_route ,
219195 "suggested_action" : suggested_action ,
220- "sleeve_suggestion" : sleeve if sleeve > 0.0 else None ,
221- "allow_hard_defense" : allow_hard_defense ,
222- "event_rebound_break_bear" : allow_hard_defense ,
196+ "manual_review_required" : manual_review_required ,
197+ "notification_reason" : notification_reason ,
198+ "rebound_context_active" : rebound_context_active ,
199+ "event_rebound_break_bear" : event_rebound_break_bear ,
223200 "would_trade_if_enabled" : would_trade_if_enabled ,
224201 "price_stress_scan_active" : scan_active ,
225202 "price_crisis_guard_active" : crisis_guard_active ,
@@ -255,10 +232,12 @@ def build_taco_rebound_shadow_signal(
255232 "broker_order_allowed" : False ,
256233 "live_allocation_mutation_allowed" : False ,
257234 "log_namespace" : TACO_REBOUND_PROFILE ,
258- "notification_profile" : "shadow_only " ,
259- "intended_strategy_role" : "left_side_rebound_budget_modifier " ,
235+ "notification_profile" : "manual_review_only " ,
236+ "intended_strategy_role" : "event_rebound_notification " ,
260237 "selection_allowed" : False ,
261- "hard_defense_override_signal_allowed" : allow_hard_defense ,
238+ "position_sizing_allowed" : False ,
239+ "allocation_recommendation_allowed" : False ,
240+ "hard_defense_override_signal_allowed" : False ,
262241 },
263242 "generated_at" : generated_at ,
264243 }
@@ -285,8 +264,9 @@ def write_taco_rebound_shadow_outputs(payload: Mapping[str, Any], output_dir: st
285264 "as_of" : payload .get ("as_of" ),
286265 "canonical_route" : payload .get ("canonical_route" ),
287266 "suggested_action" : payload .get ("suggested_action" ),
288- "sleeve_suggestion" : payload .get ("sleeve_suggestion" ),
289- "allow_hard_defense" : payload .get ("allow_hard_defense" ),
267+ "manual_review_required" : payload .get ("manual_review_required" ),
268+ "notification_reason" : payload .get ("notification_reason" ),
269+ "rebound_context_active" : payload .get ("rebound_context_active" ),
290270 "event_rebound_break_bear" : payload .get ("event_rebound_break_bear" ),
291271 ** flatten_for_csv (payload .get ("data_freshness" , {})),
292272 ** flatten_for_csv (payload .get ("selected_event" ) or {}),
@@ -316,14 +296,6 @@ def build_parser() -> argparse.ArgumentParser:
316296 parser .add_argument ("--benchmark-symbol" , default = DEFAULT_BENCHMARK_SYMBOL )
317297 parser .add_argument ("--attack-symbol" , default = DEFAULT_ATTACK_SYMBOL )
318298 parser .add_argument ("--active-signal-days" , type = int , default = DEFAULT_ACTIVE_SIGNAL_DAYS )
319- parser .add_argument ("--tariff-softening-sleeve" , type = float , default = DEFAULT_TARIFF_SOFTENING_SLEEVE )
320- parser .add_argument (
321- "--geopolitical-deescalation-sleeve" ,
322- type = float ,
323- default = DEFAULT_GEOPOLITICAL_DEESCALATION_SLEEVE ,
324- )
325- parser .add_argument ("--shock-sleeve" , type = float , default = DEFAULT_SHOCK_SLEEVE )
326- parser .add_argument ("--max-sleeve" , type = float , default = DEFAULT_MAX_SLEEVE )
327299 parser .add_argument ("--output-dir" , default = DEFAULT_OUTPUT_DIR )
328300 return parser
329301
@@ -355,10 +327,6 @@ def main(argv: Sequence[str] | None = None) -> int:
355327 benchmark_symbol = args .benchmark_symbol ,
356328 attack_symbol = args .attack_symbol ,
357329 active_signal_days = args .active_signal_days ,
358- tariff_softening_sleeve = args .tariff_softening_sleeve ,
359- geopolitical_deescalation_sleeve = args .geopolitical_deescalation_sleeve ,
360- shock_sleeve = args .shock_sleeve ,
361- max_sleeve = args .max_sleeve ,
362330 )
363331 paths = write_taco_rebound_shadow_outputs (payload , args .output_dir )
364332 print (
@@ -370,10 +338,7 @@ def main(argv: Sequence[str] | None = None) -> int:
370338
371339
372340__all__ = [
373- "ACTION_INCREASE_REBOUND_BUDGET" ,
374- "DEFAULT_GEOPOLITICAL_DEESCALATION_SLEEVE" ,
375- "DEFAULT_MAX_SLEEVE" ,
376- "DEFAULT_TARIFF_SOFTENING_SLEEVE" ,
341+ "ACTION_NOTIFY_MANUAL_REVIEW" ,
377342 "ROUTE_TACO_REBOUND" ,
378343 "SCHEMA_VERSION" ,
379344 "TACO_REBOUND_PROFILE" ,
0 commit comments