Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,9 @@ To research alternative SOXL delever gates without changing production, use
`--soxl-delever-symbol`, `--soxl-delever-window`,
`--soxl-delever-threshold`, `--soxl-delever-retention-ratio`, and
`--soxl-delever-redirect-symbol`. The current best research candidate is a
SOXX 10-day volatility gate at `0.50` that redirects SOXL into SOXX.
SOXX 20-day volatility gate at `0.50` that redirects SOXL into SOXX. See
`docs/tqqq-soxl-optimization-research.md` for the TQQQ/SOXL no-regression
optimization sweep.

For long-history core SOXL/SOXX validation, provide a BOXX-compatible cash
proxy such as BIL under the `BOXX` symbol and add `--disable-income-layer`.
Expand Down Expand Up @@ -749,9 +751,9 @@ underlying strategy artifact build remains independent; downstream systems read
the plugin's `latest_signal.json`, verify its `strategy` / `plugin` identity,
and treat the plugin as notification-only shadow context.
Plugin mounts are strategy-limited by code and tests. Keep the crisis plugin
scoped to defensive TQQQ-style risk-off behavior. Keep MAGS/TACO experiments in
research commands until a future PR adds a validated TQQQ TACO overlay plugin or
explicitly promotes another strategy mount.
scoped to defensive TQQQ/SOXL-style risk-off behavior. Keep MAGS/TACO
experiments in research commands until a future PR adds a validated TQQQ TACO
overlay plugin or explicitly promotes another strategy mount.

The only supported plugin mode is `shadow`. The runner rejects `paper`,
`advisory`, and `live` plugin modes; the current product decision is that the
Expand Down
8 changes: 4 additions & 4 deletions docs/crisis-response-live-promotion-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,10 @@ registers it. A plugin is mounted to a strategy through each
`[[strategy_plugins]]` entry; the strategy core must remain independent of the
runner and must not import plugin code. Plugins are strategy-limited in the
runner: a mount is rejected unless the plugin is explicitly declared compatible
with that strategy. This keeps `crisis_response_shadow` scoped to the TQQQ
black-swan strategy and blocks `taco_rebound_shadow` from runtime mounts while
MAGS remains research-only. A future TQQQ TACO overlay plugin must update the
compatibility table and tests in its own PR.
with that strategy. This keeps `crisis_response_shadow` scoped to TQQQ/SOXL
black-swan defense strategies and blocks `taco_rebound_shadow` from runtime
mounts while MAGS remains research-only. A future TQQQ TACO overlay plugin must
update the compatibility table and tests in its own PR.

The runner accepts only `mode = "shadow"` and writes that mode into each plugin
artifact. Downstream platform adapters must read the artifact as notification
Expand Down
13 changes: 7 additions & 6 deletions docs/crisis-response-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ auditable.

The production-facing plugin contract is now split:

- `crisis_response_shadow` is defense-only for TQQQ-style black-swan risk. It
may emit `true_crisis` / `defend` or `no_action` / `watch_only`; it must not
emit TACO routes or sleeves.
- `crisis_response_shadow` is defense-only for TQQQ/SOXL-style leveraged
equity black-swan risk. It may emit `true_crisis` / `defend` or `no_action` /
`watch_only`; it must not emit TACO routes or sleeves.
- TACO rebound work is separate from crisis defense and remains research-only
for MAGS-style pullback strategies. A TQQQ overlay candidate should be
promoted through a separate validation path before any runner mount.
Expand Down Expand Up @@ -56,13 +56,14 @@ The production-facing crisis shadow plugin narrows this to:
- TACO sleeve: start with `0.05` account sleeve in historical research. It is
not part of `crisis_response_shadow`, and the MAGS path is not a promoted
runner plugin.
- Crisis drawdown: `QQQ` drawdown from trailing high <= `-0.20`.
- Crisis drawdown: configured benchmark drawdown from trailing high <= `-0.20`
(`QQQ` for TQQQ, `SOXX` for SOXL).
- Crisis confirmation: `5` trading days.
- Crisis risk multiplier: `0.25`; do not full-clear risk exposure in V1.
- Defense-only shadow crisis plugin default: `0.0` risk multiplier when a
true-crisis route is emitted for manual review.
- Bubble proxy: `QQQ` 252-trading-day return >= `0.75`, remembered for 126
trading days.
- Bubble proxy: configured benchmark 252-trading-day return >= `0.75`,
remembered for 126 trading days.
- Financial proxy: `XLF` drawdown and relative weakness vs `SPY`.
- Safe asset in long history tests: `SHY`; live safe asset can be mapped by the
execution platform, for example BOXX/SGOV/CASH, but that is not part of this
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/strategy_plugins.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ strategy = "tqqq_growth_income"
plugin = "crisis_response_shadow"
enabled = true
# The runner enforces plugin/strategy compatibility. This plugin is scoped to
# the TQQQ black-swan defense strategy.
# TQQQ/SOXL leveraged equity black-swan defense strategies.
# mode is optional when it matches default_mode; only shadow notification mode is supported.

[strategy_plugins.inputs]
Expand Down
101 changes: 101 additions & 0 deletions docs/tqqq-soxl-optimization-research.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# TQQQ / SOXL Optimization Research

Research date: 2026-05-10

This note records a bounded optimization sweep for the TQQQ and SOXL leveraged
equity profiles. The acceptance rule is intentionally strict to avoid fitting a
single crisis window:

1. CAGR must not decrease versus baseline in every comparison window.
2. Max drawdown must not worsen versus baseline in every comparison window.
3. A passing candidate remains research evidence only unless a later PR promotes
it into strategy configuration.

The `crisis_response_shadow` plugin remains notification-only. It can be mounted
to TQQQ/SOXL defense contexts, but it does not place trades or mutate live
allocations.

## TQQQ

Data and model:

- Source prices: `data/output/crisis_response_1999_synthetic_v2_context/input/crisis_response_price_history.csv`
- Benchmark: `QQQ`
- Attack leg: synthetic daily-reset `SYNTH_TQQQ` from `QQQ` at 3x, 1% annual
expense assumption
- Safe asset: `SHY`
- Turnover cost: 5 bps

Tested candidates:

- Pullback-rebound windows: 10, 20, 30 trading days.
- Pullback-rebound volatility multipliers: 1.0, 1.5, 2.0, 2.5, 3.0.
- Fixed pullback-rebound thresholds: 0%, 2%, 4%, 6%.
- Small allocation variants around the baseline 45% QQQ / 45% synthetic TQQQ /
8% SHY / 2% cash active mix.
- Moving the 2% cash sleeve into SHY for active and/or idle states.

Result:

- No TQQQ candidate passed the strict no-regression rule across all tested
windows.
- Higher pullback thresholds improved full-sample CAGR and drawdown in some
cases, but regressed at least one stress or recent period.
- Moving cash into SHY was close, but still caused small regressions in rate
stress windows.

Conclusion: keep the current TQQQ strategy parameters. Do not promote a TQQQ
optimization from this sweep.

## SOXL

Data and model:

- Source prices: `/tmp/soxl_synthetic_long/synthetic_soxl_from_soxx_price_history.csv`
- Benchmark: `SOXX`
- Attack leg: synthetic daily-reset `SOXL` from `SOXX`
- Strategy: `soxl_soxx_trend_income` research backtest with income layer
disabled for long-history core replay
- Turnover cost: 5 bps

Tested candidates:

- SOXX realized-volatility gates with 10, 15, 20, and 30 trading-day windows.
- Annualized realized-vol thresholds: 45%, 50%, 55%, 60%, 65%.
- SOXL retention ratios: 0% and 25%.
- Redirect destinations: mostly `SOXX`, with selected `BOXX` defensive checks.

Baseline:

| Period | CAGR | Max Drawdown |
| --- | ---: | ---: |
| Full 2001-2026 | 19.34% | -60.24% |
| Dotcom tail 2001-2003 | 25.30% | -51.24% |
| GFC 2007-2009 | 2.85% | -55.78% |
| Real SOXL era 2010-2026 | 27.13% | -36.84% |
| 2022 rate bear | -27.32% | -34.53% |
| 2024-2026 live-full proxy | 64.63% | -36.84% |

Passing candidates:

| Candidate | Stops | Full CAGR | Full MDD | Min CAGR Delta | Min MDD Delta |
| --- | ---: | ---: | ---: | ---: | ---: |
| SOXX 20d vol >= 50%, retain 0% SOXL, redirect to SOXX | 19 | 20.02% | -59.52% | +0.05 pp | +0.08 pp |
| SOXX 15d vol >= 50%, retain 0% SOXL, redirect to SOXX | 18 | 20.01% | -59.52% | +0.05 pp | +0.08 pp |
| SOXX 20d vol >= 50%, retain 25% SOXL, redirect rest to SOXX | 19 | 19.86% | -59.66% | +0.01 pp | +0.06 pp |
| SOXX 15d vol >= 50%, retain 25% SOXL, redirect rest to SOXX | 18 | 19.85% | -59.66% | +0.01 pp | +0.06 pp |

Selected `BOXX` redirect variants improved full-sample CAGR and drawdown, but
failed the strict no-CAGR-regression rule in at least one window.

Conclusion: the strongest SOXL research candidate is the 20-day SOXX
realized-volatility gate at 50%, redirecting triggered SOXL target exposure into
SOXX. It passed this bounded sweep, but should remain research-only until a
separate PR promotes it with implementation tests and operator review.

## Local Research Outputs

- `/tmp/tqqq_soxl_optimization_research/tqqq_variant_summary.csv`
- `/tmp/tqqq_soxl_optimization_research/tqqq_variant_periods.csv`
- `/tmp/tqqq_soxl_optimization_research/soxl_variant_summary.csv`
- `/tmp/tqqq_soxl_optimization_research/soxl_variant_periods.csv`
2 changes: 1 addition & 1 deletion src/us_equity_snapshot_pipelines/strategy_plugin_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
PLUGIN_TACO_REBOUND_SHADOW = TACO_REBOUND_PROFILE
SUPPORTED_PLUGIN_MODES = (SHADOW_MODE,)
PLUGIN_COMPATIBLE_STRATEGIES: dict[str, tuple[str, ...]] = {
PLUGIN_CRISIS_RESPONSE_SHADOW: ("tqqq_growth_income",),
PLUGIN_CRISIS_RESPONSE_SHADOW: ("tqqq_growth_income", "soxl_soxx_trend_income"),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Enforce SOXL symbol overrides for new strategy mount

Allowing crisis_response_shadow to mount to soxl_soxx_trend_income without additional validation means SOXL entries can still run with the plugin’s hardcoded defaults (benchmark_symbol=QQQ, attack_symbol=TQQQ) when those fields are omitted. In that case the runner either evaluates the wrong market context or trips the kill switch on SOXL-only price files (missing QQQ), which breaks the new compatibility path introduced here. Please either add strategy-specific defaults for SOXL or reject SOXL mounts unless benchmark_symbol/attack_symbol are explicitly configured.

Useful? React with 👍 / 👎.

}
PLUGIN_RESEARCH_ONLY_REASONS: dict[str, str] = {
PLUGIN_TACO_REBOUND_SHADOW: (
Expand Down
57 changes: 57 additions & 0 deletions tests/test_strategy_plugin_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
)

STRATEGY_NAME = "tqqq_growth_income"
SOXL_STRATEGY_NAME = "soxl_soxx_trend_income"
LEFT_SIDE_STRATEGY_NAME = "mega_cap_leader_rotation_top50_balanced"


Expand All @@ -35,6 +36,23 @@ def _quiet_prices() -> pd.DataFrame:
return pd.DataFrame(rows)


def _soxl_quiet_prices() -> pd.DataFrame:
dates = pd.bdate_range("2025-01-02", periods=230)
rows: list[dict[str, object]] = []
for symbol in ("SOXX", "SOXL", "SPY"):
for offset, as_of in enumerate(dates):
multiplier = 3.0 if symbol == "SOXL" else 1.0
rows.append(
{
"symbol": symbol,
"as_of": as_of,
"close": 100.0 + offset * 0.01 * multiplier,
"volume": 1_000_000,
}
)
return pd.DataFrame(rows)


def _financial_crisis_prices() -> pd.DataFrame:
dates = pd.bdate_range("2007-01-02", periods=310)
rows: list[dict[str, object]] = []
Expand Down Expand Up @@ -226,6 +244,45 @@ def test_strategy_plugin_runner_uses_default_mode_when_entry_mode_is_omitted(tmp
assert payload["execution_controls"]["notification_profile"] == "shadow_only"


def test_strategy_plugin_runner_mounts_crisis_shadow_to_soxl_strategy(tmp_path) -> None:
prices_path = tmp_path / "soxl_prices.csv"
output_dir = tmp_path / SOXL_STRATEGY_NAME / "plugins" / PLUGIN_CRISIS_RESPONSE_SHADOW
_soxl_quiet_prices().to_csv(prices_path, index=False)
config = {
"output_dir": str(tmp_path / "runner"),
"default_mode": "shadow",
"strategy_plugins": [
{
"strategy": SOXL_STRATEGY_NAME,
"plugin": PLUGIN_CRISIS_RESPONSE_SHADOW,
"enabled": True,
"inputs": {
"prices": str(prices_path),
"as_of": "2025-11-19",
"start_date": "2025-01-02",
"benchmark_symbol": "SOXX",
"attack_symbol": "SOXL",
"financial_symbols": [],
"credit_pairs": [],
"rate_symbols": [],
},
"outputs": {"output_dir": str(output_dir)},
}
],
}

summary = run_configured_plugins(config)

result = summary["strategy_plugins"][0]
assert result["strategy"] == SOXL_STRATEGY_NAME
assert result["plugin"] == PLUGIN_CRISIS_RESPONSE_SHADOW
assert result["effective_mode"] == "shadow"
payload = json.loads((output_dir / "latest_signal.json").read_text(encoding="utf-8"))
assert payload["strategy"] == SOXL_STRATEGY_NAME
assert payload["evidence"]["metrics"]["benchmark_symbol"] == "SOXX"
assert payload["execution_controls"]["broker_order_allowed"] is False


def test_strategy_plugin_runner_filters_by_strategy(tmp_path) -> None:
config = _shadow_plugin_config(tmp_path)
config["strategy_plugins"].append(
Expand Down