@@ -162,6 +162,21 @@ def _retention_profile(retention_ratio: float, *reason_codes: str) -> dict[str,
162162 }
163163
164164
165+ def _price_rebound_candidate (price_rebound_context : Mapping [str , Any ] | None ) -> bool :
166+ if not isinstance (price_rebound_context , Mapping ):
167+ return False
168+ return bool (
169+ _as_bool (price_rebound_context .get ("volatility_triggered" ), default = False )
170+ and _as_bool (price_rebound_context .get ("trend_ok" ), default = False )
171+ and (
172+ _as_bool (price_rebound_context .get ("rebound_1d" ), default = False )
173+ or _as_bool (price_rebound_context .get ("rebound_nd" ), default = False )
174+ or _as_bool (price_rebound_context .get ("confirmed" ), default = False )
175+ )
176+ and not _as_bool (price_rebound_context .get ("hard_filter" ), default = False )
177+ )
178+
179+
165180def _build_volatility_delever_context (
166181 * ,
167182 final_route : str ,
@@ -180,7 +195,11 @@ def _build_volatility_delever_context(
180195 isinstance (price_rebound_context , Mapping )
181196 and _as_bool (price_rebound_context .get ("confirmed" ), default = False )
182197 and not hard_risk
183- and not soft_risk
198+ and not blocked
199+ )
200+ price_rebound_candidate = bool (
201+ _price_rebound_candidate (price_rebound_context )
202+ and not hard_risk
184203 and not blocked
185204 )
186205 opportunity_rebound_confirm = bool (taco_active or panic_reversal_active )
@@ -197,23 +216,28 @@ def _build_volatility_delever_context(
197216 tqqq_softzero_025 = _retention_profile (0.0 , "hard_risk" )
198217 tqqq_softzero_035 = _retention_profile (0.0 , "hard_risk" )
199218 soxl_rebound = _retention_profile (0.0 , "hard_risk" )
219+ soxl_softzero_rebound = _retention_profile (0.0 , "hard_risk" )
200220 elif soft_risk :
201221 tqqq_softzero_025 = _retention_profile (0.0 , "soft_risk" )
202222 tqqq_softzero_035 = _retention_profile (0.0 , "soft_risk" )
203- soxl_rebound = _retention_profile (0.0 , "soft_risk" )
204- elif rebound_confirm :
205- if opportunity_rebound_confirm :
206- tqqq_softzero_025 = _retention_profile (0.50 , "constructive" , "rebound_confirm" )
207- tqqq_softzero_035 = _retention_profile (0.50 , "constructive" , "rebound_confirm" )
208- soxl_rebound = _retention_profile (0.50 if constructive else 0.25 , "constructive" , "rebound_confirm" )
209- else :
210- tqqq_softzero_025 = _retention_profile (0.25 , "non_soft_risk" )
211- tqqq_softzero_035 = _retention_profile (0.35 , "non_soft_risk" )
212- soxl_rebound = _retention_profile (0.50 , "constructive" , "price_rebound_confirm" )
223+ soxl_rebound = (
224+ _retention_profile (0.25 , "price_rebound_candidate" , "soft_risk" )
225+ if price_rebound_candidate
226+ else _retention_profile (0.0 , "soft_risk" )
227+ )
228+ soxl_softzero_rebound = _retention_profile (0.0 , "soft_risk" )
213229 else :
214230 tqqq_softzero_025 = _retention_profile (0.25 , "non_soft_risk" )
215231 tqqq_softzero_035 = _retention_profile (0.35 , "non_soft_risk" )
216- soxl_rebound = _retention_profile (0.0 , "rebound_not_confirmed" )
232+ if price_rebound_confirm :
233+ soxl_rebound = _retention_profile (0.50 , "constructive" , "price_rebound_confirm" )
234+ soxl_softzero_rebound = _retention_profile (0.50 , "constructive" , "price_rebound_confirm" )
235+ elif price_rebound_candidate :
236+ soxl_rebound = _retention_profile (0.25 , "price_rebound_candidate" )
237+ soxl_softzero_rebound = _retention_profile (0.25 , "price_rebound_candidate" )
238+ else :
239+ soxl_rebound = _retention_profile (0.0 , "rebound_not_confirmed" )
240+ soxl_softzero_rebound = _retention_profile (0.0 , "rebound_not_confirmed" )
217241 context = {
218242 "schema_version" : "volatility_delever_context.v1" ,
219243 "source" : "deterministic_market_regime_components" ,
@@ -222,13 +246,15 @@ def _build_volatility_delever_context(
222246 "soft_risk" : soft_risk ,
223247 "constructive" : constructive ,
224248 "rebound_confirm" : rebound_confirm ,
249+ "price_rebound_candidate" : price_rebound_candidate ,
225250 "rebound_sources" : tuple (rebound_sources ),
226251 "macro_watch" : bool (macro_watch ),
227252 "reason_codes" : tuple (dict .fromkeys (reason_codes )),
228253 "retention_profiles" : {
229254 "tqqq_step_softzero_0.25_0.50" : tqqq_softzero_025 ,
230255 "tqqq_step_softzero_0.35_0.50" : tqqq_softzero_035 ,
231256 "soxl_step_rebound_0.25_0.50" : soxl_rebound ,
257+ "soxl_step_softzero_rebound_0.25_0.50" : soxl_softzero_rebound ,
232258 },
233259 }
234260 if isinstance (price_rebound_context , Mapping ) and price_rebound_context :
0 commit comments