diff --git a/README.md b/README.md index a028b5b..52f9a88 100644 --- a/README.md +++ b/README.md @@ -39,21 +39,23 @@ The mainline runtime now follows one path only: - `tqqq_growth_income` - `soxl_soxx_trend_income` - `tech_communication_pullback_enhancement` +- `mega_cap_leader_rotation_aggressive` - `mega_cap_leader_rotation_dynamic_top20` - `dynamic_mega_leveraged_pullback` **IBKR profile status** -| Canonical profile | Display name | Eligible | Enabled | Default | Rollback | Domain | Runtime note | -| --- | --- | --- | --- | --- | --- | --- | --- | -| `global_etf_rotation` | Global ETF Rotation | Yes | Yes | Yes | Yes | `us_equity` | current rollback line | -| `russell_1000_multi_factor_defensive` | Russell 1000 Multi-Factor | Yes | Yes | No | No | `us_equity` | defensive stock baseline | -| `tqqq_growth_income` | TQQQ Growth Income | Yes | Yes | No | No | `us_equity` | enabled value-mode alternative | -| `soxl_soxx_trend_income` | SOXL/SOXX Semiconductor Trend Income | Yes | Yes | No | No | `us_equity` | current IBKR live line | -| `tech_communication_pullback_enhancement` | Tech/Communication Pullback Enhancement | Yes | Yes | No | No | `us_equity` | enabled feature-snapshot alternative | -| `mega_cap_leader_rotation_dynamic_top20` | Mega Cap Leader Rotation Dynamic Top20 | Yes | Yes | No | No | `us_equity` | enabled concentrated leader rotation | -| `dynamic_mega_leveraged_pullback` | Dynamic Mega Leveraged Pullback | Yes | Yes | No | No | `us_equity` | enabled 2x mega-cap pullback line | +| Canonical profile | Display name | Eligible | Enabled | Domain | Runtime note | +| --- | --- | --- | --- | --- | --- | +| `global_etf_rotation` | Global ETF Rotation | Yes | Yes | `us_equity` | enabled weight-mode rotation line | +| `russell_1000_multi_factor_defensive` | Russell 1000 Multi-Factor | Yes | Yes | `us_equity` | defensive stock baseline | +| `tqqq_growth_income` | TQQQ Growth Income | Yes | Yes | `us_equity` | enabled value-mode alternative | +| `soxl_soxx_trend_income` | SOXL/SOXX Semiconductor Trend Income | Yes | Yes | `us_equity` | current IBKR live line | +| `tech_communication_pullback_enhancement` | Tech/Communication Pullback Enhancement | Yes | Yes | `us_equity` | enabled feature-snapshot alternative | +| `mega_cap_leader_rotation_aggressive` | Mega Cap Leader Rotation Aggressive | Yes | Yes | `us_equity` | enabled aggressive leader rotation | +| `mega_cap_leader_rotation_dynamic_top20` | Mega Cap Leader Rotation Dynamic Top20 | Yes | Yes | `us_equity` | enabled concentrated leader rotation | +| `dynamic_mega_leveraged_pullback` | Dynamic Mega Leveraged Pullback | Yes | Yes | `us_equity` | enabled 2x mega-cap pullback line | Check the current matrix locally: @@ -98,8 +100,8 @@ The selected `ACCOUNT_GROUP` is now the runtime identity. Keep broker-specific i |----------|----------|-------------| | `IB_GATEWAY_ZONE` | Optional fallback | GCE zone (for example `us-central1-a`). Recommended to keep in the selected account-group entry; this env var is only a transition fallback. | | `IB_GATEWAY_IP_MODE` | Optional fallback | `internal` (default) or `external`. Recommended to keep in the selected account-group entry; this env var is only a transition fallback. | -| `STRATEGY_PROFILE` | Yes | Strategy profile selector. Supported `us_equity` values: `global_etf_rotation`, `russell_1000_multi_factor_defensive`, `tqqq_growth_income`, `soxl_soxx_trend_income`, `tech_communication_pullback_enhancement`, `mega_cap_leader_rotation_dynamic_top20`, `dynamic_mega_leveraged_pullback` | -| `ACCOUNT_GROUP` | Yes | Account-group selector. No default fallback. | +| `STRATEGY_PROFILE` | Yes | Strategy profile selector. Supported `us_equity` values: `global_etf_rotation`, `russell_1000_multi_factor_defensive`, `tqqq_growth_income`, `soxl_soxx_trend_income`, `tech_communication_pullback_enhancement`, `mega_cap_leader_rotation_aggressive`, `mega_cap_leader_rotation_dynamic_top20`, `dynamic_mega_leveraged_pullback` | +| `ACCOUNT_GROUP` | Yes | Account-group selector. Set explicitly for each deployment. | | `IBKR_FEATURE_SNAPSHOT_PATH` | Conditionally required | Required for snapshot-backed profiles such as `russell_1000_multi_factor_defensive`, `tech_communication_pullback_enhancement`, and `mega_cap_leader_rotation_dynamic_top20`. Path to the latest feature snapshot file (`.csv`, `.json`, `.jsonl`, `.parquet`). | | `IB_ACCOUNT_GROUP_CONFIG_SECRET_NAME` | Yes for Cloud Run | Secret Manager secret name for account-group config JSON. Recommended production source. | | `IB_ACCOUNT_GROUP_CONFIG_JSON` | No | Local/dev JSON fallback for account-group config. Not recommended for production Cloud Run. | @@ -218,7 +220,7 @@ Recommended setup: - `CLOUD_RUN_REGION` - `CLOUD_RUN_SERVICE` - `TELEGRAM_TOKEN_SECRET_NAME` (recommended when Cloud Run already uses Secret Manager for `TELEGRAM_TOKEN`) - - `STRATEGY_PROFILE` (recommended: `global_etf_rotation`) + - `STRATEGY_PROFILE` (set explicitly to one enabled profile, such as `soxl_soxx_trend_income`) - `ACCOUNT_GROUP` (recommended: `default`) - `IB_ACCOUNT_GROUP_CONFIG_SECRET_NAME` - `GLOBAL_TELEGRAM_CHAT_ID` @@ -288,7 +290,7 @@ gcloud run services update ibkr-quant \ IBKR runtime 负责把共享的 `us_equity` 策略档位部署到 GCP Cloud Run,并连接 GCE 上的 IB Gateway 执行。策略逻辑、策略频率、标的池、参数和研究/回测说明都放在 `UsEquityStrategies`;这个仓库只维护 IBKR 运行时、账号组、Gateway 连接、下单和通知。 -当前 `global_etf_rotation`、`russell_1000_multi_factor_defensive`、`tqqq_growth_income`、`soxl_soxx_trend_income`、`tech_communication_pullback_enhancement` 和 `mega_cap_leader_rotation_dynamic_top20` 的策略实现都来自 `UsEquityStrategies`。 +当前 `global_etf_rotation`、`russell_1000_multi_factor_defensive`、`tqqq_growth_income`、`soxl_soxx_trend_income`、`tech_communication_pullback_enhancement`、`mega_cap_leader_rotation_aggressive`、`mega_cap_leader_rotation_dynamic_top20` 和 `dynamic_mega_leveraged_pullback` 的策略实现都来自 `UsEquityStrategies`。 完整策略说明现在放在 [`UsEquityStrategies`](https://github.com/QuantStrategyLab/UsEquityStrategies)。这个 README 只保留 IBKR 运行时、profile 启用状态、部署和凭据说明。 @@ -329,8 +331,8 @@ IBKR 账户 |------|------|------| | `IB_GATEWAY_ZONE` | 可选过渡项 | GCE zone(如 `us-central1-a`)。推荐直接放进选中的账号组配置里;这里只保留过渡 fallback。 | | `IB_GATEWAY_IP_MODE` | 可选过渡项 | `internal`(默认)或 `external`。推荐直接放进选中的账号组配置里;这里只保留过渡 fallback。 | -| `STRATEGY_PROFILE` | 是 | 策略档位选择。当前可用的 `us_equity` 值:`global_etf_rotation`、`russell_1000_multi_factor_defensive`、`tqqq_growth_income`、`soxl_soxx_trend_income`、`tech_communication_pullback_enhancement`、`mega_cap_leader_rotation_dynamic_top20`、`dynamic_mega_leveraged_pullback` | -| `ACCOUNT_GROUP` | 是 | 账号组选择器,不再提供默认回退。 | +| `STRATEGY_PROFILE` | 是 | 策略档位选择。当前可用的 `us_equity` 值:`global_etf_rotation`、`russell_1000_multi_factor_defensive`、`tqqq_growth_income`、`soxl_soxx_trend_income`、`tech_communication_pullback_enhancement`、`mega_cap_leader_rotation_aggressive`、`mega_cap_leader_rotation_dynamic_top20`、`dynamic_mega_leveraged_pullback` | +| `ACCOUNT_GROUP` | 是 | 账号组选择器,每个部署都要显式设置。 | | `IB_ACCOUNT_GROUP_CONFIG_SECRET_NAME` | Cloud Run 建议必填 | 账号组配置 JSON 在 Secret Manager 里的密钥名。生产环境推荐使用。 | | `IB_ACCOUNT_GROUP_CONFIG_JSON` | 否 | 本地开发用的账号组配置 JSON fallback。不建议在生产 Cloud Run 直接使用。 | | `TELEGRAM_TOKEN` | 是 | Telegram 机器人 Token。Cloud Run 上更推荐走 Secret Manager 引用,不要直接写成明文 env。 | @@ -415,7 +417,7 @@ IB_GATEWAY_IP_MODE=internal - `CLOUD_RUN_REGION` - `CLOUD_RUN_SERVICE` - `TELEGRAM_TOKEN_SECRET_NAME`(如果 Cloud Run 上的 `TELEGRAM_TOKEN` 已经改成 Secret Manager,建议配置) - - `STRATEGY_PROFILE`(建议设为 `global_etf_rotation`) + - `STRATEGY_PROFILE`(显式设置为任一已启用 profile,例如 `soxl_soxx_trend_income`) - `ACCOUNT_GROUP`(建议设为 `default`) - `IB_ACCOUNT_GROUP_CONFIG_SECRET_NAME` - `GLOBAL_TELEGRAM_CHAT_ID` diff --git a/notifications/telegram.py b/notifications/telegram.py index 1e4b33d..7fbdc96 100644 --- a/notifications/telegram.py +++ b/notifications/telegram.py @@ -67,6 +67,8 @@ "strategy_name_russell_1000_multi_factor_defensive": "罗素1000多因子", "strategy_name_tech_communication_pullback_enhancement": "科技通信回调增强", "strategy_name_qqq_tech_enhancement": "科技通信回调增强", + "strategy_name_mega_cap_leader_rotation_dynamic_top20": "Mega Cap 动态 Top20 龙头轮动", + "strategy_name_dynamic_mega_leveraged_pullback": "Mega Cap 2x 回调策略", "strategy_name_tqqq_growth_income": "TQQQ 增长收益", "strategy_name_soxl_soxx_trend_income": "SOXL/SOXX 半导体趋势收益", }, @@ -133,6 +135,8 @@ "strategy_name_russell_1000_multi_factor_defensive": "Russell 1000 Multi-Factor", "strategy_name_tech_communication_pullback_enhancement": "Tech/Communication Pullback Enhancement", "strategy_name_qqq_tech_enhancement": "Tech/Communication Pullback Enhancement", + "strategy_name_mega_cap_leader_rotation_dynamic_top20": "Mega Cap Leader Rotation Dynamic Top20", + "strategy_name_dynamic_mega_leveraged_pullback": "Dynamic Mega Leveraged Pullback", "strategy_name_tqqq_growth_income": "TQQQ Growth Income", "strategy_name_soxl_soxx_trend_income": "SOXL/SOXX Semiconductor Trend Income", }, diff --git a/runtime_config_support.py b/runtime_config_support.py index 3d09524..012b92f 100644 --- a/runtime_config_support.py +++ b/runtime_config_support.py @@ -8,7 +8,6 @@ from quant_platform_kit.common.strategies import derive_strategy_artifact_paths from strategy_registry import ( - DEFAULT_STRATEGY_PROFILE as PLATFORM_DEFAULT_STRATEGY_PROFILE, IBKR_PLATFORM, resolve_strategy_definition, resolve_strategy_metadata, @@ -16,7 +15,6 @@ from us_equity_strategies import get_strategy_catalog DEFAULT_ACCOUNT_GROUP = "default" -DEFAULT_STRATEGY_PROFILE = PLATFORM_DEFAULT_STRATEGY_PROFILE @dataclass(frozen=True) diff --git a/scripts/print_strategy_profile_status.py b/scripts/print_strategy_profile_status.py index ea6dbd6..93d2e4f 100644 --- a/scripts/print_strategy_profile_status.py +++ b/scripts/print_strategy_profile_status.py @@ -43,8 +43,6 @@ def _print_table(rows: list[dict[str, object]]) -> None: "requires_strategy_config_path", "eligible", "enabled", - "is_default", - "is_rollback", "domain", ) widths = { diff --git a/strategy_registry.py b/strategy_registry.py index accc28d..aecd955 100644 --- a/strategy_registry.py +++ b/strategy_registry.py @@ -22,9 +22,6 @@ IBKR_PLATFORM = "ibkr" -DEFAULT_STRATEGY_PROFILE = "global_etf_rotation" -ROLLBACK_STRATEGY_PROFILE = DEFAULT_STRATEGY_PROFILE - IBKR_ROLLOUT_ALLOWLIST = get_runtime_enabled_profiles() PLATFORM_SUPPORTED_DOMAINS: dict[str, frozenset[str]] = { @@ -61,12 +58,17 @@ platform_id=IBKR_PLATFORM, supported_domains=PLATFORM_SUPPORTED_DOMAINS[IBKR_PLATFORM], enabled_profiles=IBKR_ENABLED_PROFILES, - default_profile=DEFAULT_STRATEGY_PROFILE, - rollback_profile=ROLLBACK_STRATEGY_PROFILE, + default_profile="", + rollback_profile="", require_explicit_profile=True, ) SUPPORTED_STRATEGY_PROFILES = IBKR_ENABLED_PROFILES +_SELECTION_ROLE_FIELDS = frozenset({"is_default", "is_rollback"}) + + +def _without_selection_role_fields(row: dict[str, object]) -> dict[str, object]: + return {key: value for key, value in row.items() if key not in _SELECTION_ROLE_FIELDS} def get_eligible_profiles_for_platform(platform_id: str) -> frozenset[str]: @@ -80,15 +82,21 @@ def get_supported_profiles_for_platform(platform_id: str) -> frozenset[str]: def get_platform_profile_matrix() -> list[dict[str, object]]: - return build_platform_profile_matrix(STRATEGY_CATALOG, policy=PLATFORM_POLICY) + return [ + _without_selection_role_fields(row) + for row in build_platform_profile_matrix(STRATEGY_CATALOG, policy=PLATFORM_POLICY) + ] def get_platform_profile_status_matrix() -> list[dict[str, object]]: - return build_platform_profile_status_matrix( - STRATEGY_CATALOG, - policy=PLATFORM_POLICY, - eligible_profiles=ELIGIBLE_STRATEGY_PROFILES, - ) + return [ + _without_selection_role_fields(row) + for row in build_platform_profile_status_matrix( + STRATEGY_CATALOG, + policy=PLATFORM_POLICY, + eligible_profiles=ELIGIBLE_STRATEGY_PROFILES, + ) + ] def resolve_strategy_definition( diff --git a/tests/test_notifications.py b/tests/test_notifications.py index c5026a1..835dbb0 100644 --- a/tests/test_notifications.py +++ b/tests/test_notifications.py @@ -1,4 +1,4 @@ -from notifications.telegram import build_translator, send_telegram_message +from notifications.telegram import build_strategy_display_name, build_translator, send_telegram_message def test_build_translator_supports_chinese(): @@ -9,6 +9,16 @@ def test_build_translator_supports_chinese(): assert translate("signal_risk_on", window=150, ratio="40.2%") == "SOXL 站上 150 日均线,持有 SOXL,交易层风险仓位 40.2%" +def test_strategy_display_name_translates_new_live_profiles(): + zh_name = build_strategy_display_name(build_translator("zh")) + en_name = build_strategy_display_name(build_translator("en")) + + assert zh_name("mega_cap_leader_rotation_dynamic_top20") == "Mega Cap 动态 Top20 龙头轮动" + assert zh_name("dynamic_mega_leveraged_pullback") == "Mega Cap 2x 回调策略" + assert en_name("mega_cap_leader_rotation_dynamic_top20") == "Mega Cap Leader Rotation Dynamic Top20" + assert en_name("dynamic_mega_leveraged_pullback") == "Dynamic Mega Leveraged Pullback" + + def test_send_telegram_message_logs_non_200_response(capsys): class FakeResponse: status_code = 401 diff --git a/tests/test_runtime_config_support.py b/tests/test_runtime_config_support.py index 1d20d21..49b1a36 100644 --- a/tests/test_runtime_config_support.py +++ b/tests/test_runtime_config_support.py @@ -6,7 +6,6 @@ import pytest from runtime_config_support import ( - DEFAULT_STRATEGY_PROFILE, load_platform_runtime_settings, parse_account_group_configs, ) @@ -26,6 +25,7 @@ ) SCRIPT_PATH = Path(__file__).resolve().parents[1] / "scripts" / "print_strategy_profile_status.py" SWITCH_PLAN_SCRIPT_PATH = Path(__file__).resolve().parents[1] / "scripts" / "print_strategy_switch_env_plan.py" +SAMPLE_STRATEGY_PROFILE = "global_etf_rotation" def test_load_platform_runtime_settings_requires_strategy_profile(monkeypatch): @@ -39,7 +39,7 @@ def test_load_platform_runtime_settings_requires_strategy_profile(monkeypatch): def test_load_platform_runtime_settings_requires_account_group(monkeypatch): - monkeypatch.setenv("STRATEGY_PROFILE", DEFAULT_STRATEGY_PROFILE) + monkeypatch.setenv("STRATEGY_PROFILE", SAMPLE_STRATEGY_PROFILE) monkeypatch.setenv("IB_ACCOUNT_GROUP_CONFIG_JSON", MINIMAL_GROUP_JSON) monkeypatch.delenv("ACCOUNT_GROUP", raising=False) @@ -49,7 +49,7 @@ def test_load_platform_runtime_settings_requires_account_group(monkeypatch): def test_load_platform_runtime_settings_requires_account_group_config_source(monkeypatch): - monkeypatch.setenv("STRATEGY_PROFILE", DEFAULT_STRATEGY_PROFILE) + monkeypatch.setenv("STRATEGY_PROFILE", SAMPLE_STRATEGY_PROFILE) monkeypatch.setenv("ACCOUNT_GROUP", "default") monkeypatch.delenv("IB_ACCOUNT_GROUP_CONFIG_JSON", raising=False) monkeypatch.delenv("IB_ACCOUNT_GROUP_CONFIG_SECRET_NAME", raising=False) @@ -63,7 +63,7 @@ def test_load_platform_runtime_settings_requires_account_group_config_source(mon def test_load_platform_runtime_settings_uses_minimal_group_config(monkeypatch): - monkeypatch.setenv("STRATEGY_PROFILE", DEFAULT_STRATEGY_PROFILE) + monkeypatch.setenv("STRATEGY_PROFILE", SAMPLE_STRATEGY_PROFILE) monkeypatch.setenv("ACCOUNT_GROUP", "default") monkeypatch.setenv("IB_ACCOUNT_GROUP_CONFIG_JSON", MINIMAL_GROUP_JSON) monkeypatch.delenv("IB_GATEWAY_ZONE", raising=False) @@ -80,7 +80,7 @@ def test_load_platform_runtime_settings_uses_minimal_group_config(monkeypatch): assert settings.ib_gateway_mode == "paper" assert settings.ib_gateway_ip_mode == "internal" assert settings.ib_client_id == 1 - assert settings.strategy_profile == DEFAULT_STRATEGY_PROFILE + assert settings.strategy_profile == SAMPLE_STRATEGY_PROFILE assert settings.strategy_display_name == "Global ETF Rotation" assert settings.strategy_domain == US_EQUITY_DOMAIN assert settings.strategy_target_mode == "weight" @@ -102,7 +102,7 @@ def test_load_platform_runtime_settings_uses_minimal_group_config(monkeypatch): def test_load_platform_runtime_settings_supports_explicit_group_config_values(monkeypatch): - monkeypatch.setenv("STRATEGY_PROFILE", DEFAULT_STRATEGY_PROFILE) + monkeypatch.setenv("STRATEGY_PROFILE", SAMPLE_STRATEGY_PROFILE) monkeypatch.setenv("ACCOUNT_GROUP", "taxable_main") monkeypatch.setenv( "IB_ACCOUNT_GROUP_CONFIG_JSON", @@ -123,7 +123,7 @@ def test_load_platform_runtime_settings_supports_explicit_group_config_values(mo assert settings.ib_gateway_mode == "live" assert settings.ib_gateway_ip_mode == "external" assert settings.ib_client_id == 7 - assert settings.strategy_profile == DEFAULT_STRATEGY_PROFILE + assert settings.strategy_profile == SAMPLE_STRATEGY_PROFILE assert settings.strategy_display_name == "Global ETF Rotation" assert settings.strategy_domain == US_EQUITY_DOMAIN assert settings.strategy_target_mode == "weight" @@ -155,6 +155,7 @@ def test_platform_supported_profiles_are_filtered_by_registry(): "tech_communication_pullback_enhancement", "global_etf_rotation", "dynamic_mega_leveraged_pullback", + "mega_cap_leader_rotation_aggressive", "mega_cap_leader_rotation_dynamic_top20", "russell_1000_multi_factor_defensive", } @@ -169,6 +170,7 @@ def test_platform_eligible_profiles_are_exposed_by_capability_matrix(): "tech_communication_pullback_enhancement", "global_etf_rotation", "dynamic_mega_leveraged_pullback", + "mega_cap_leader_rotation_aggressive", "mega_cap_leader_rotation_dynamic_top20", "russell_1000_multi_factor_defensive", } @@ -244,11 +246,11 @@ def test_load_platform_runtime_settings_rejects_legacy_qqq_tech_alias(monkeypatc load_platform_runtime_settings(project_id_resolver=lambda: "project-1") -def test_platform_profile_matrix_marks_default_and_rollback(): +def test_platform_profile_matrix_exposes_profiles_without_selection_roles(): rows = get_platform_profile_matrix() by_profile = {row["canonical_profile"]: row for row in rows} - assert by_profile["global_etf_rotation"]["is_default"] is True - assert by_profile["global_etf_rotation"]["is_rollback"] is True + assert "is_default" not in by_profile["global_etf_rotation"] + assert "is_rollback" not in by_profile["global_etf_rotation"] assert by_profile["tech_communication_pullback_enhancement"]["display_name"] == "Tech/Communication Pullback Enhancement" @@ -263,6 +265,7 @@ def test_platform_profile_status_matrix_matches_current_ibkr_rollout(): "soxl_soxx_trend_income", "tqqq_growth_income", "tech_communication_pullback_enhancement", + "mega_cap_leader_rotation_aggressive", "mega_cap_leader_rotation_dynamic_top20", } assert by_profile["global_etf_rotation"] == { @@ -271,8 +274,6 @@ def test_platform_profile_status_matrix_matches_current_ibkr_rollout(): "domain": "us_equity", "eligible": True, "enabled": True, - "is_default": True, - "is_rollback": True, "platform": "ibkr", } assert by_profile["soxl_soxx_trend_income"]["display_name"] == "SOXL/SOXX Semiconductor Trend Income" @@ -301,8 +302,6 @@ def test_print_strategy_profile_status_json_matches_registry(): "domain", "eligible", "enabled", - "is_default", - "is_rollback", "platform", ) } @@ -493,7 +492,7 @@ def test_load_platform_runtime_settings_derives_artifact_paths_from_root(monkeyp def test_load_platform_runtime_settings_uses_account_group_secret(monkeypatch): - monkeypatch.setenv("STRATEGY_PROFILE", DEFAULT_STRATEGY_PROFILE) + monkeypatch.setenv("STRATEGY_PROFILE", SAMPLE_STRATEGY_PROFILE) monkeypatch.setenv("ACCOUNT_GROUP", "ira") monkeypatch.setenv("IB_ACCOUNT_GROUP_CONFIG_SECRET_NAME", "ibkr-account-groups") @@ -539,7 +538,7 @@ def access_secret_version(self, request): def test_load_platform_runtime_settings_requires_project_for_secret_source(monkeypatch): - monkeypatch.setenv("STRATEGY_PROFILE", DEFAULT_STRATEGY_PROFILE) + monkeypatch.setenv("STRATEGY_PROFILE", SAMPLE_STRATEGY_PROFILE) monkeypatch.setenv("ACCOUNT_GROUP", "default") monkeypatch.setenv("IB_ACCOUNT_GROUP_CONFIG_SECRET_NAME", "ibkr-account-groups") @@ -552,7 +551,7 @@ def test_load_platform_runtime_settings_requires_project_for_secret_source(monke def test_load_platform_runtime_settings_rejects_unknown_account_group(monkeypatch): - monkeypatch.setenv("STRATEGY_PROFILE", DEFAULT_STRATEGY_PROFILE) + monkeypatch.setenv("STRATEGY_PROFILE", SAMPLE_STRATEGY_PROFILE) monkeypatch.setenv("ACCOUNT_GROUP", "missing") monkeypatch.setenv("IB_ACCOUNT_GROUP_CONFIG_JSON", MINIMAL_GROUP_JSON) @@ -562,7 +561,7 @@ def test_load_platform_runtime_settings_rejects_unknown_account_group(monkeypatc def test_load_platform_runtime_settings_requires_key_group_fields(monkeypatch): - monkeypatch.setenv("STRATEGY_PROFILE", DEFAULT_STRATEGY_PROFILE) + monkeypatch.setenv("STRATEGY_PROFILE", SAMPLE_STRATEGY_PROFILE) monkeypatch.setenv("ACCOUNT_GROUP", "default") monkeypatch.setenv( "IB_ACCOUNT_GROUP_CONFIG_JSON",