Skip to content

Commit 6d54bb7

Browse files
Pigbibicursoragent
andcommitted
Add TECL volatility delever retention profiles for research.
Expose tecl_step_rebound retention profiles and enable XLK-benchmarked price rebound context for tecl_xlk_trend_income without affecting SOXL defaults. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 5bd4e2d commit 6d54bb7

4 files changed

Lines changed: 56 additions & 3 deletions

File tree

src/quant_strategy_plugins/market_regime_control_plugin.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,8 @@ def _build_volatility_delever_context(
217217
tqqq_softzero_035 = _retention_profile(0.0, "hard_risk")
218218
soxl_rebound = _retention_profile(0.0, "hard_risk")
219219
soxl_softzero_rebound = _retention_profile(0.0, "hard_risk")
220+
tecl_rebound = _retention_profile(0.0, "hard_risk")
221+
tecl_softzero_rebound = _retention_profile(0.0, "hard_risk")
220222
elif soft_risk:
221223
tqqq_softzero_025 = _retention_profile(0.0, "soft_risk")
222224
tqqq_softzero_035 = _retention_profile(0.0, "soft_risk")
@@ -226,18 +228,30 @@ def _build_volatility_delever_context(
226228
else _retention_profile(0.0, "soft_risk")
227229
)
228230
soxl_softzero_rebound = _retention_profile(0.0, "soft_risk")
231+
tecl_rebound = (
232+
_retention_profile(0.25, "price_rebound_candidate", "soft_risk")
233+
if price_rebound_candidate
234+
else _retention_profile(0.0, "soft_risk")
235+
)
236+
tecl_softzero_rebound = _retention_profile(0.0, "soft_risk")
229237
else:
230238
tqqq_softzero_025 = _retention_profile(0.25, "non_soft_risk")
231239
tqqq_softzero_035 = _retention_profile(0.35, "non_soft_risk")
232240
if price_rebound_confirm:
233241
soxl_rebound = _retention_profile(0.50, "constructive", "price_rebound_confirm")
234242
soxl_softzero_rebound = _retention_profile(0.50, "constructive", "price_rebound_confirm")
243+
tecl_rebound = _retention_profile(0.50, "constructive", "price_rebound_confirm")
244+
tecl_softzero_rebound = _retention_profile(0.50, "constructive", "price_rebound_confirm")
235245
elif price_rebound_candidate:
236246
soxl_rebound = _retention_profile(0.25, "price_rebound_candidate")
237247
soxl_softzero_rebound = _retention_profile(0.25, "price_rebound_candidate")
248+
tecl_rebound = _retention_profile(0.25, "price_rebound_candidate")
249+
tecl_softzero_rebound = _retention_profile(0.25, "price_rebound_candidate")
238250
else:
239251
soxl_rebound = _retention_profile(0.0, "rebound_not_confirmed")
240252
soxl_softzero_rebound = _retention_profile(0.0, "rebound_not_confirmed")
253+
tecl_rebound = _retention_profile(0.0, "rebound_not_confirmed")
254+
tecl_softzero_rebound = _retention_profile(0.0, "rebound_not_confirmed")
241255
context = {
242256
"schema_version": "volatility_delever_context.v1",
243257
"source": "deterministic_market_regime_components",
@@ -255,6 +269,8 @@ def _build_volatility_delever_context(
255269
"tqqq_step_softzero_0.35_0.50": tqqq_softzero_035,
256270
"soxl_step_rebound_0.25_0.50": soxl_rebound,
257271
"soxl_step_softzero_rebound_0.25_0.50": soxl_softzero_rebound,
272+
"tecl_step_rebound_0.25_0.50": tecl_rebound,
273+
"tecl_step_softzero_rebound_0.25_0.50": tecl_softzero_rebound,
258274
},
259275
}
260276
if isinstance(price_rebound_context, Mapping) and price_rebound_context:

src/quant_strategy_plugins/volatility_delever_price_rebound.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,21 +125,23 @@ def build_volatility_delever_price_rebound_context(
125125
price_history: pd.DataFrame,
126126
plugin_config: Mapping[str, Any],
127127
) -> dict[str, Any]:
128-
"""Build deterministic SOXL volatility-delever rebound context.
128+
"""Build deterministic levered volatility-delever rebound context.
129129
130130
The context is intentionally limited to backtestable hard data. It feeds
131131
retention profiles only; market-regime route authority stays with the
132132
existing crisis and macro components.
133133
"""
134134

135135
strategy = str(plugin_config.get("strategy") or "").strip().lower()
136-
default_enabled = strategy == "soxl_soxx_trend_income"
136+
default_enabled = strategy in {"soxl_soxx_trend_income", "tecl_xlk_trend_income"}
137137
if not _as_bool(plugin_config.get("volatility_delever_price_rebound_enabled"), default=default_enabled):
138138
return {}
139139

140140
close = normalize_close(price_history)
141141
as_of = str(plugin_config.get("as_of", "") or "").strip() or None
142-
benchmark_symbol = str(plugin_config.get("benchmark_symbol", "SOXX") or "SOXX").strip().upper()
142+
benchmark_symbol = str(plugin_config.get("benchmark_symbol") or "").strip().upper()
143+
if not benchmark_symbol:
144+
benchmark_symbol = "XLK" if strategy == "tecl_xlk_trend_income" else "SOXX"
143145
if benchmark_symbol not in close.columns:
144146
_, signal_date = resolve_signal_date(close, as_of)
145147
return {

tests/test_market_regime_control_plugin.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,3 +276,18 @@ def test_market_regime_control_blocked_component_blocks_taco_opportunity() -> No
276276
assert payload["suggested_action"] == "blocked"
277277
assert payload["position_control"]["taco_allowed"] is False
278278
assert "macro:blocked" in payload["position_control"]["reason_codes"]
279+
280+
281+
def test_market_regime_control_exposes_tecl_retention_profiles() -> None:
282+
payload = build_market_regime_control_signal(
283+
{},
284+
volatility_delever_price_rebound_context={
285+
"schema_version": "volatility_delever_price_rebound_context.v1",
286+
"confirmed": True,
287+
"reason_codes": ["price_rebound_confirm"],
288+
},
289+
)
290+
291+
profiles = payload["position_control"]["volatility_delever_context"]["retention_profiles"]
292+
assert profiles["tecl_step_rebound_0.25_0.50"]["retention_ratio"] == 0.50
293+
assert profiles["tecl_step_softzero_rebound_0.25_0.50"]["retention_ratio"] == 0.50

tests/test_volatility_delever_price_rebound.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,26 @@ def test_price_rebound_context_defaults_disabled_for_non_soxl_strategy() -> None
4747
assert context == {}
4848

4949

50+
def test_price_rebound_context_defaults_enabled_for_tecl_strategy() -> None:
51+
prices = _soxl_rebound_prices()
52+
prices = prices.assign(
53+
symbol=prices["symbol"].map(lambda value: {"SOXX": "XLK", "SOXL": "TECL"}.get(value, value))
54+
)
55+
context = build_volatility_delever_price_rebound_context(
56+
prices,
57+
{
58+
"strategy": "tecl_xlk_trend_income",
59+
"as_of": pd.Timestamp(prices["as_of"].max()).date().isoformat(),
60+
"vix_symbols": ["VIX"],
61+
"credit_pairs": ["HYG:IEF"],
62+
"financial_symbols": ["XLF"],
63+
},
64+
)
65+
66+
assert context.get("enabled") is True
67+
assert context.get("benchmark_symbol") == "XLK"
68+
69+
5070
def test_price_rebound_context_confirms_soxl_constructive_rebound() -> None:
5171
prices = _soxl_rebound_prices()
5272
context = build_volatility_delever_price_rebound_context(

0 commit comments

Comments
 (0)