2727DEFAULT_RESERVED_CASH_FLOOR_USD = 0.0
2828DEFAULT_RESERVED_CASH_RATIO = 0.0
2929DEFAULT_SAFE_HAVEN_CASH_SUBSTITUTE_THRESHOLD_USD = 1000.0
30+ IBIT_SMART_DCA_PROFILE = "ibit_smart_dca"
3031
3132
3233@dataclass (frozen = True )
@@ -205,10 +206,7 @@ def load_platform_runtime_settings(
205206 runtime_execution_window_trading_days = _runtime_execution_window_trading_days_env (
206207 strategy_definition .profile
207208 ),
208- market_signal_handoff_index_uri = _first_non_empty (
209- os .getenv ("FIRSTRADE_MARKET_SIGNAL_HANDOFF_INDEX_URI" ),
210- os .getenv ("MARKET_SIGNAL_HANDOFF_INDEX_URI" ),
211- ),
209+ market_signal_handoff_index_uri = _resolve_market_signal_handoff_index_uri (),
212210 market_signal_handoff_manifest_uri = _first_non_empty (
213211 os .getenv ("FIRSTRADE_MARKET_SIGNAL_HANDOFF_MANIFEST_URI" ),
214212 os .getenv ("MARKET_SIGNAL_HANDOFF_MANIFEST_URI" ),
@@ -221,16 +219,13 @@ def load_platform_runtime_settings(
221219 os .getenv ("FIRSTRADE_MARKET_SIGNAL_CACHE_DIR" ),
222220 os .getenv ("MARKET_SIGNAL_CACHE_DIR" ),
223221 ),
224- market_signal_required = resolve_bool_value (
225- _first_non_empty (
226- os .getenv ("FIRSTRADE_MARKET_SIGNAL_REQUIRED" ),
227- os .getenv ("MARKET_SIGNAL_REQUIRED" ),
228- "false" ,
229- )
222+ market_signal_required = _resolve_market_signal_required (
223+ strategy_profile = strategy_definition .profile ,
224+ dca_mode = _optional_dca_mode_env ("DCA_MODE" ),
230225 ),
231- market_signal_fallback_mode = _first_non_empty (
232- os . getenv ( "FIRSTRADE_MARKET_SIGNAL_FALLBACK_MODE" ) ,
233- os . getenv ( "MARKET_SIGNAL_FALLBACK_MODE " ),
226+ market_signal_fallback_mode = _resolve_market_signal_fallback_mode (
227+ strategy_profile = strategy_definition . profile ,
228+ dca_mode = _optional_dca_mode_env ( "DCA_MODE " ),
234229 ),
235230 market_signal_max_stale_days = _optional_int (
236231 _first_non_empty (
@@ -472,6 +467,58 @@ def _resolve_ratio_env(name: str, *, default: float) -> float:
472467 return value
473468
474469
470+ def _default_market_signal_handoff_index_uri_from_report_bucket (
471+ execution_report_gcs_uri : str | None ,
472+ ) -> str | None :
473+ text = str (execution_report_gcs_uri or "" ).strip ()
474+ if not text .startswith ("gs://" ):
475+ return None
476+ bucket = text [len ("gs://" ) :].split ("/" , 1 )[0 ].strip ()
477+ if not bucket :
478+ return None
479+ return f"gs://{ bucket } /platform_handoffs/index.json"
480+
481+
482+ def _resolve_market_signal_handoff_index_uri () -> str | None :
483+ explicit = _first_non_empty (
484+ os .getenv ("FIRSTRADE_MARKET_SIGNAL_HANDOFF_INDEX_URI" ),
485+ os .getenv ("MARKET_SIGNAL_HANDOFF_INDEX_URI" ),
486+ )
487+ if explicit :
488+ return explicit
489+ return _default_market_signal_handoff_index_uri_from_report_bucket (
490+ os .getenv ("EXECUTION_REPORT_GCS_URI" ),
491+ )
492+
493+
494+ def _resolve_market_signal_required (* , strategy_profile : str , dca_mode : str | None ) -> bool :
495+ explicit = _first_non_empty (
496+ os .getenv ("FIRSTRADE_MARKET_SIGNAL_REQUIRED" ),
497+ os .getenv ("MARKET_SIGNAL_REQUIRED" ),
498+ )
499+ if explicit is not None :
500+ return resolve_bool_value (explicit )
501+ if strategy_profile == IBIT_SMART_DCA_PROFILE and str (dca_mode or "" ).strip ().lower () == "smart" :
502+ return True
503+ return False
504+
505+
506+ def _resolve_market_signal_fallback_mode (
507+ * ,
508+ strategy_profile : str ,
509+ dca_mode : str | None ,
510+ ) -> str | None :
511+ explicit = _first_non_empty (
512+ os .getenv ("FIRSTRADE_MARKET_SIGNAL_FALLBACK_MODE" ),
513+ os .getenv ("MARKET_SIGNAL_FALLBACK_MODE" ),
514+ )
515+ if explicit :
516+ return explicit
517+ if strategy_profile == IBIT_SMART_DCA_PROFILE and str (dca_mode or "" ).strip ().lower () == "smart" :
518+ return "last_valid"
519+ return None
520+
521+
475522def _first_non_empty (* raw_values : str | None ) -> str | None :
476523 for raw_value in raw_values :
477524 value = str (raw_value or "" ).strip ()
0 commit comments