Skip to content

Commit b7d04ca

Browse files
committed
Drop IBKR legacy strategy aliases
1 parent 09b8b2f commit b7d04ca

9 files changed

Lines changed: 87 additions & 69 deletions

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ IBKR runtime for shared `us_equity` strategy profiles from `UsEquityStrategies`.
1616

1717
- `global_etf_rotation` (`Global ETF Rotation`): quarterly ETF momentum rotation with daily canary defense
1818
- `russell_1000_multi_factor_defensive` (`Russell 1000 Multi-Factor`): monthly stock-selection strategy that consumes a precomputed feature snapshot
19-
- `qqq_tech_enhancement` (`QQQ Tech Enhancement`, alias: `tech_pullback_cash_buffer`): monthly tech-heavy stock-selection branch with explicit BOXX cash buffer
19+
- `qqq_tech_enhancement` (`QQQ Tech Enhancement`): monthly tech-heavy stock-selection branch with explicit BOXX cash buffer
2020

2121
Current strategy implementations are sourced from `UsEquityStrategies`.
2222

@@ -40,8 +40,8 @@ The mainline runtime now follows one path only:
4040

4141
- `global_etf_rotation`
4242
- `russell_1000_multi_factor_defensive`
43-
- `soxl_soxx_trend_income` (alias: `semiconductor_rotation_income`)
44-
- `qqq_tech_enhancement` (alias: `tech_pullback_cash_buffer`)
43+
- `soxl_soxx_trend_income`
44+
- `qqq_tech_enhancement`
4545

4646

4747
**IBKR profile status**
@@ -50,7 +50,7 @@ The mainline runtime now follows one path only:
5050
| --- | --- | --- | --- | --- | --- | --- | --- |
5151
| `global_etf_rotation` | Global ETF Rotation | Yes | Yes | Yes | Yes | `us_equity` | current rollback line |
5252
| `russell_1000_multi_factor_defensive` | Russell 1000 Multi-Factor | Yes | Yes | No | No | `us_equity` | defensive stock baseline |
53-
| `soxl_soxx_trend_income` | SOXL/SOXX Semiconductor Trend Income | Yes | Yes | No | No | `us_equity` | current IBKR dry-run line |
53+
| `soxl_soxx_trend_income` | SOXL/SOXX Semiconductor Trend Income | Yes | Yes | No | No | `us_equity` | current IBKR live line |
5454
| `qqq_tech_enhancement` | QQQ Tech Enhancement | Yes | Yes | No | No | `us_equity` | enabled feature-snapshot alternative |
5555

5656
Check the current matrix locally:

notifications/telegram.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,8 @@
6161
"order_rejected": "❌ 订单异常 | {symbol} {side} {qty}股 状态: {status} (ID: {order_id})",
6262
"strategy_name_global_etf_rotation": "全球 ETF 轮动",
6363
"strategy_name_russell_1000_multi_factor_defensive": "罗素1000多因子",
64-
"strategy_name_tech_pullback_cash_buffer": "QQQ 科技增强",
6564
"strategy_name_qqq_tech_enhancement": "QQQ 科技增强",
66-
"strategy_name_hybrid_growth_income": "TQQQ 增长收益",
6765
"strategy_name_tqqq_growth_income": "TQQQ 增长收益",
68-
"strategy_name_semiconductor_rotation_income": "SOXL/SOXX 半导体趋势收益",
6966
"strategy_name_soxl_soxx_trend_income": "SOXL/SOXX 半导体趋势收益",
7067
},
7168
"en": {
@@ -125,11 +122,8 @@
125122
"order_rejected": "❌ Rejected | {symbol} {side} {qty} shares status: {status} (ID: {order_id})",
126123
"strategy_name_global_etf_rotation": "Global ETF Rotation",
127124
"strategy_name_russell_1000_multi_factor_defensive": "Russell 1000 Multi-Factor",
128-
"strategy_name_tech_pullback_cash_buffer": "QQQ Tech Enhancement",
129125
"strategy_name_qqq_tech_enhancement": "QQQ Tech Enhancement",
130-
"strategy_name_hybrid_growth_income": "TQQQ Growth Income",
131126
"strategy_name_tqqq_growth_income": "TQQQ Growth Income",
132-
"strategy_name_semiconductor_rotation_income": "SOXL/SOXX Semiconductor Trend Income",
133127
"strategy_name_soxl_soxx_trend_income": "SOXL/SOXX Semiconductor Trend Income",
134128
},
135129
}

tests/test_execution_service.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ def fake_fetch_quote_snapshots(_ib, symbols):
9595
order_intent_cls=OrderIntent,
9696
translator=translate,
9797
strategy_symbols=["VOO", "BIL"],
98-
strategy_profile="tech_pullback_cash_buffer",
98+
strategy_profile="qqq_tech_enhancement",
9999
signal_metadata=_signal_metadata(
100100
{"VOO": 1.0},
101101
risk_symbols=("VOO",),
@@ -145,7 +145,7 @@ def accountValues(self):
145145
order_intent_cls=OrderIntent,
146146
translator=translate,
147147
strategy_symbols=["VOO"],
148-
strategy_profile="tech_pullback_cash_buffer",
148+
strategy_profile="qqq_tech_enhancement",
149149
signal_metadata=_signal_metadata({"VOO": 1.0}, risk_symbols=("VOO",)),
150150
dry_run_only=False,
151151
cash_reserve_ratio=0.03,
@@ -154,7 +154,7 @@ def accountValues(self):
154154
sell_settle_delay_sec=0,
155155
)
156156

157-
assert trade_logs == ["pending_orders_detected profile=tech_pullback_cash_buffer symbols=VOO"]
157+
assert trade_logs == ["pending_orders_detected profile=qqq_tech_enhancement symbols=VOO"]
158158

159159

160160
def test_execute_rebalance_blocks_same_day_repeat_via_execution_lock(tmp_path, monkeypatch):
@@ -179,7 +179,7 @@ def fake_fetch_quote_snapshots(_ib, symbols):
179179
order_intent_cls=OrderIntent,
180180
translator=translate,
181181
strategy_symbols=["VOO", "BOXX"],
182-
strategy_profile="tech_pullback_cash_buffer",
182+
strategy_profile="qqq_tech_enhancement",
183183
account_group="default",
184184
service_name="ibkr-paper",
185185
account_ids=("DU123",),
@@ -257,7 +257,7 @@ def accountValues(self):
257257
order_intent_cls=OrderIntent,
258258
translator=translate,
259259
strategy_symbols=["VOO"],
260-
strategy_profile="tech_pullback_cash_buffer",
260+
strategy_profile="qqq_tech_enhancement",
261261
account_group="default",
262262
service_name="ibkr-paper",
263263
account_ids=("DU123",),
@@ -298,7 +298,7 @@ def fake_fetch_quote_snapshots(_ib, symbols):
298298
order_intent_cls=OrderIntent,
299299
translator=translate,
300300
strategy_symbols=["VOO", "BOXX"],
301-
strategy_profile="tech_pullback_cash_buffer",
301+
strategy_profile="qqq_tech_enhancement",
302302
account_group="default",
303303
service_name="ibkr-paper",
304304
account_ids=("DU123",),
@@ -353,7 +353,7 @@ def accountValues(self):
353353
order_intent_cls=OrderIntent,
354354
translator=translate,
355355
strategy_symbols=["VOO"],
356-
strategy_profile="tech_pullback_cash_buffer",
356+
strategy_profile="qqq_tech_enhancement",
357357
signal_metadata=_signal_metadata(
358358
{"VOO": 1.0},
359359
risk_symbols=("VOO",),
@@ -395,7 +395,7 @@ def accountValues(self):
395395
order_intent_cls=OrderIntent,
396396
translator=translate,
397397
strategy_symbols=["VOO"],
398-
strategy_profile="tech_pullback_cash_buffer",
398+
strategy_profile="qqq_tech_enhancement",
399399
signal_metadata=_signal_metadata(
400400
{"VOO": 1.0},
401401
risk_symbols=("VOO",),
@@ -437,7 +437,7 @@ def accountValues(self):
437437
order_intent_cls=OrderIntent,
438438
translator=translate,
439439
strategy_symbols=["VOO", "BOXX"],
440-
strategy_profile="tech_pullback_cash_buffer",
440+
strategy_profile="qqq_tech_enhancement",
441441
signal_metadata=_signal_metadata(
442442
{"VOO": 0.6, "BOXX": 0.4},
443443
risk_symbols=("VOO",),

tests/test_feature_snapshot_service.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -112,14 +112,14 @@ def test_load_feature_snapshot_guarded_validates_manifest_checksums(self):
112112
snapshot_path = Path(tmp_dir) / "snapshot.csv"
113113
config_path = Path(tmp_dir) / "config.json"
114114
snapshot_path.write_text("as_of,symbol,sector,mom_6_1\n2026-03-31,AAA,tech,0.1\n", encoding="utf-8")
115-
config_path.write_text(json.dumps({"name": "tech_pullback_cash_buffer"}), encoding="utf-8")
115+
config_path.write_text(json.dumps({"name": "qqq_tech_enhancement"}), encoding="utf-8")
116116
manifest_path = Path(f"{snapshot_path}.manifest.json")
117117
manifest_path.write_text(
118118
json.dumps(
119119
{
120-
"contract_version": "tech_pullback_cash_buffer.feature_snapshot.v1",
121-
"strategy_profile": "tech_pullback_cash_buffer",
122-
"config_name": "tech_pullback_cash_buffer",
120+
"contract_version": "qqq_tech_enhancement.feature_snapshot.v1",
121+
"strategy_profile": "qqq_tech_enhancement",
122+
"config_name": "qqq_tech_enhancement",
123123
"config_path": str(config_path),
124124
"config_sha256": _sha256_file(config_path),
125125
"snapshot_path": str(snapshot_path),
@@ -143,8 +143,8 @@ def test_load_feature_snapshot_guarded_validates_manifest_checksums(self):
143143

144144
self.assertIsNotNone(result.frame)
145145
self.assertEqual(result.metadata["snapshot_guard_decision"], "proceed")
146-
self.assertEqual(result.metadata["snapshot_manifest_strategy_profile"], "tech_pullback_cash_buffer")
147-
self.assertEqual(result.metadata["snapshot_manifest_config_name"], "tech_pullback_cash_buffer")
146+
self.assertEqual(result.metadata["snapshot_manifest_strategy_profile"], "qqq_tech_enhancement")
147+
self.assertEqual(result.metadata["snapshot_manifest_config_name"], "qqq_tech_enhancement")
148148

149149
def test_load_feature_snapshot_downloads_gcs_csv(self):
150150
_skip_if_missing_pandas()
@@ -169,9 +169,9 @@ def test_load_feature_snapshot_guarded_downloads_gcs_snapshot_and_manifest(self)
169169

170170
with TemporaryDirectory() as tmp_dir:
171171
config_path = Path(tmp_dir) / "config.json"
172-
config_path.write_text(json.dumps({"name": "tech_pullback_cash_buffer"}), encoding="utf-8")
172+
config_path.write_text(json.dumps({"name": "qqq_tech_enhancement"}), encoding="utf-8")
173173

174-
snapshot_uri = "gs://unit-test-bucket/snapshots/tech_pullback_cash_buffer_feature_snapshot_latest.csv"
174+
snapshot_uri = "gs://unit-test-bucket/snapshots/qqq_tech_enhancement_feature_snapshot_latest.csv"
175175
manifest_uri = f"{snapshot_uri}.manifest.json"
176176
downloaded_snapshot_path: Path | None = None
177177

@@ -190,9 +190,9 @@ def fake_download(uri: str, destination: Path) -> None:
190190
destination.write_text(
191191
json.dumps(
192192
{
193-
"contract_version": "tech_pullback_cash_buffer.feature_snapshot.v1",
194-
"strategy_profile": "tech_pullback_cash_buffer",
195-
"config_name": "tech_pullback_cash_buffer",
193+
"contract_version": "qqq_tech_enhancement.feature_snapshot.v1",
194+
"strategy_profile": "qqq_tech_enhancement",
195+
"config_name": "qqq_tech_enhancement",
196196
"config_path": str(config_path),
197197
"config_sha256": _sha256_file(config_path),
198198
"snapshot_path": snapshot_uri,

tests/test_rebalance_service.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ def disconnect(self):
168168
False,
169169
"breadth=41.0%",
170170
{
171-
"strategy_profile": "tech_pullback_cash_buffer",
171+
"strategy_profile": "qqq_tech_enhancement",
172172
"managed_symbols": ("AAA", "BOXX"),
173173
"status_icon": "🧲",
174174
"trade_date": "2026-04-01",
@@ -216,7 +216,7 @@ def disconnect(self):
216216

217217
assert result == "OK - executed"
218218
payload = json.loads(output_path.read_text(encoding="utf-8"))
219-
assert payload["strategy_profile"] == "tech_pullback_cash_buffer"
219+
assert payload["strategy_profile"] == "qqq_tech_enhancement"
220220
assert payload["snapshot_as_of"] == "2026-03-31"
221221
assert payload["orders_submitted"][0]["symbol"] == "AAA"
222222
assert payload["snapshot_price_fallback_used"] is True
@@ -235,7 +235,7 @@ def isConnected(self):
235235
def disconnect(self):
236236
return None
237237

238-
output_root = tmp_path / "tech_pullback_cash_buffer" / "reconciliation"
238+
output_root = tmp_path / "qqq_tech_enhancement" / "reconciliation"
239239

240240
result = run_strategy_core(
241241
connect_ib=lambda: FakeIB(),
@@ -246,7 +246,7 @@ def disconnect(self):
246246
False,
247247
"outside execution window",
248248
{
249-
"strategy_profile": "tech_pullback_cash_buffer",
249+
"strategy_profile": "qqq_tech_enhancement",
250250
"trade_date": "2026-04-01",
251251
"snapshot_as_of": "2026-03-31",
252252
"snapshot_guard_decision": "no_op",

tests/test_runtime_config_support.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,8 @@ def test_platform_eligible_profiles_are_exposed_by_capability_matrix():
168168
)
169169

170170

171-
def test_load_platform_runtime_settings_accepts_tech_pullback_cash_buffer(monkeypatch):
172-
monkeypatch.setenv("STRATEGY_PROFILE", "tech_pullback_cash_buffer")
171+
def test_load_platform_runtime_settings_accepts_qqq_tech_enhancement(monkeypatch):
172+
monkeypatch.setenv("STRATEGY_PROFILE", "qqq_tech_enhancement")
173173
monkeypatch.setenv("ACCOUNT_GROUP", "default")
174174
monkeypatch.setenv("IB_ACCOUNT_GROUP_CONFIG_JSON", MINIMAL_GROUP_JSON)
175175
monkeypatch.setenv("IBKR_FEATURE_SNAPSHOT_PATH", "/tmp/cash-buffer.csv")
@@ -181,6 +181,16 @@ def test_load_platform_runtime_settings_accepts_tech_pullback_cash_buffer(monkey
181181
assert settings.strategy_target_mode == "weight"
182182

183183

184+
def test_load_platform_runtime_settings_rejects_legacy_qqq_tech_alias(monkeypatch):
185+
monkeypatch.setenv("STRATEGY_PROFILE", "tech_pullback_cash_buffer")
186+
monkeypatch.setenv("ACCOUNT_GROUP", "default")
187+
monkeypatch.setenv("IB_ACCOUNT_GROUP_CONFIG_JSON", MINIMAL_GROUP_JSON)
188+
monkeypatch.setenv("IBKR_FEATURE_SNAPSHOT_PATH", "/tmp/cash-buffer.csv")
189+
190+
with pytest.raises(ValueError, match="Unsupported STRATEGY_PROFILE"):
191+
load_platform_runtime_settings(project_id_resolver=lambda: "project-1")
192+
193+
184194
def test_platform_profile_matrix_marks_default_and_rollback():
185195
rows = get_platform_profile_matrix()
186196
by_profile = {row["canonical_profile"]: row for row in rows}
@@ -252,7 +262,7 @@ def test_load_platform_runtime_settings_reads_feature_snapshot_path(monkeypatch)
252262

253263

254264
def test_load_platform_runtime_settings_reads_tech_pullback_runtime_config(monkeypatch):
255-
monkeypatch.setenv("STRATEGY_PROFILE", "tech_pullback_cash_buffer")
265+
monkeypatch.setenv("STRATEGY_PROFILE", "qqq_tech_enhancement")
256266
monkeypatch.setenv("ACCOUNT_GROUP", "default")
257267
monkeypatch.setenv("IB_ACCOUNT_GROUP_CONFIG_JSON", MINIMAL_GROUP_JSON)
258268
monkeypatch.setenv("IBKR_FEATURE_SNAPSHOT_PATH", "/tmp/cash-buffer.csv")
@@ -272,7 +282,7 @@ def test_load_platform_runtime_settings_reads_tech_pullback_runtime_config(monke
272282

273283

274284
def test_load_platform_runtime_settings_uses_bundled_tech_pullback_config_when_env_missing(monkeypatch):
275-
monkeypatch.setenv("STRATEGY_PROFILE", "tech_pullback_cash_buffer")
285+
monkeypatch.setenv("STRATEGY_PROFILE", "qqq_tech_enhancement")
276286
monkeypatch.setenv("ACCOUNT_GROUP", "default")
277287
monkeypatch.setenv("IB_ACCOUNT_GROUP_CONFIG_JSON", MINIMAL_GROUP_JSON)
278288
monkeypatch.setenv("IBKR_FEATURE_SNAPSHOT_PATH", "/tmp/cash-buffer.csv")
@@ -287,7 +297,7 @@ def test_load_platform_runtime_settings_uses_bundled_tech_pullback_config_when_e
287297

288298

289299
def test_load_platform_runtime_settings_derives_artifact_paths_from_root(monkeypatch, tmp_path):
290-
monkeypatch.setenv("STRATEGY_PROFILE", "tech_pullback_cash_buffer")
300+
monkeypatch.setenv("STRATEGY_PROFILE", "qqq_tech_enhancement")
291301
monkeypatch.setenv("ACCOUNT_GROUP", "default")
292302
monkeypatch.setenv("IB_ACCOUNT_GROUP_CONFIG_JSON", MINIMAL_GROUP_JSON)
293303
monkeypatch.setenv("IBKR_STRATEGY_ARTIFACT_ROOT", str(tmp_path))

0 commit comments

Comments
 (0)