@@ -185,6 +185,46 @@ def _attach_strategy_plugin_metadata(
185185 return portfolio_snapshot
186186 return attach_strategy_plugin_metadata (portfolio_snapshot , tuple (strategy_plugin_signals or ()))
187187
188+ def _with_consecutive_loss_metadata (self , portfolio_snapshot : Any | None ) -> Any | None :
189+ """Stamp trailing consecutive_losses onto portfolio metadata before evaluate."""
190+ if portfolio_snapshot is None :
191+ return None
192+ metadata = dict (getattr (portfolio_snapshot , "metadata" , None ) or {})
193+ if metadata .get ("consecutive_losses" ) is not None :
194+ return portfolio_snapshot
195+ try :
196+ from quant_platform_kit .strategy_lifecycle .live_equity import resolve_consecutive_losses
197+ from quant_platform_kit .strategy_lifecycle .performance_monitor import infer_strategy_domain
198+
199+ streak = resolve_consecutive_losses (
200+ domain = infer_strategy_domain (self .profile ),
201+ strategy_profile = self .profile ,
202+ )
203+ except Exception as exc :
204+ self .logger (
205+ "strategy_consecutive_losses_resolve_failed | "
206+ f"profile={ self .profile } error_type={ type (exc ).__name__ } error={ exc } "
207+ )
208+ return portfolio_snapshot
209+ if streak is None :
210+ return portfolio_snapshot
211+ metadata ["consecutive_losses" ] = int (streak )
212+ return replace (portfolio_snapshot , metadata = metadata )
213+
214+ def _prepare_portfolio_snapshot (
215+ self ,
216+ portfolio_snapshot : Any | None ,
217+ strategy_symbols = (),
218+ strategy_plugin_signals = (),
219+ * ,
220+ project : bool = True ,
221+ ) -> Any | None :
222+ snapshot = portfolio_snapshot
223+ if project :
224+ snapshot = self ._project_portfolio_snapshot (snapshot , strategy_symbols )
225+ snapshot = self ._attach_strategy_plugin_metadata (snapshot , strategy_plugin_signals )
226+ return self ._with_consecutive_loss_metadata (snapshot )
227+
188228 @staticmethod
189229 def _normalize_symbols (symbols ) -> tuple [str , ...]:
190230 normalized = []
@@ -680,11 +720,11 @@ def _evaluate_direct_market_data_strategy(
680720 ib ,
681721 required = False ,
682722 )
683- portfolio_snapshot = self ._project_portfolio_snapshot (
723+ portfolio_snapshot = self ._prepare_portfolio_snapshot (
684724 portfolio_snapshot ,
685725 self ._configured_strategy_symbols (include_ranking_pool = True ),
726+ strategy_plugin_signals ,
686727 )
687- portfolio_snapshot = self ._attach_strategy_plugin_metadata (portfolio_snapshot , strategy_plugin_signals )
688728 option_chains = self ._fetch_option_chains_for_runtime (ib , runtime_config , portfolio_snapshot )
689729 if option_chains :
690730 runtime_config ["option_chains" ] = option_chains
@@ -760,11 +800,11 @@ def _evaluate_market_data_strategy(
760800 ib ,
761801 required = requires_portfolio ,
762802 )
763- portfolio_snapshot = self ._project_portfolio_snapshot (
803+ portfolio_snapshot = self ._prepare_portfolio_snapshot (
764804 portfolio_snapshot ,
765805 self ._configured_strategy_symbols (include_ranking_pool = True ),
806+ strategy_plugin_signals ,
766807 )
767- portfolio_snapshot = self ._attach_strategy_plugin_metadata (portfolio_snapshot , strategy_plugin_signals )
768808 option_chains = self ._fetch_option_chains_for_runtime (ib , runtime_config , portfolio_snapshot )
769809 if option_chains :
770810 runtime_config ["option_chains" ] = option_chains
@@ -835,8 +875,11 @@ def _evaluate_value_target_strategy(
835875 apply_runtime_policy_to_runtime_config (runtime_config , self .runtime_adapter )
836876 managed_symbols = self ._configured_strategy_symbols ()
837877 portfolio_snapshot = self ._fetch_portfolio_snapshot_for_context (ib , required = True )
838- portfolio_snapshot = self ._project_portfolio_snapshot (portfolio_snapshot , managed_symbols )
839- portfolio_snapshot = self ._attach_strategy_plugin_metadata (portfolio_snapshot , strategy_plugin_signals )
878+ portfolio_snapshot = self ._prepare_portfolio_snapshot (
879+ portfolio_snapshot ,
880+ managed_symbols ,
881+ strategy_plugin_signals ,
882+ )
840883 option_chains = self ._fetch_option_chains_for_runtime (ib , runtime_config , portfolio_snapshot )
841884 if option_chains :
842885 runtime_config ["option_chains" ] = option_chains
@@ -965,7 +1008,11 @@ def build_available_inputs(feature_snapshot) -> Mapping[str, Any]:
9651008 ib ,
9661009 required = requires_portfolio ,
9671010 )
968- portfolio_snapshot = self ._attach_strategy_plugin_metadata (portfolio_snapshot , strategy_plugin_signals )
1011+ portfolio_snapshot = self ._prepare_portfolio_snapshot (
1012+ portfolio_snapshot ,
1013+ strategy_plugin_signals = strategy_plugin_signals ,
1014+ project = False ,
1015+ )
9691016 if portfolio_snapshot is not None :
9701017 portfolio_snapshot_holder ["portfolio_snapshot" ] = portfolio_snapshot
9711018 option_chains = self ._fetch_option_chains_for_runtime (ib , runtime_config , portfolio_snapshot )
0 commit comments