|
6 | 6 | import pytest |
7 | 7 |
|
8 | 8 | from runtime_config_support import ( |
| 9 | + DEFAULT_RESERVED_CASH_FLOOR_USD, |
9 | 10 | DEFAULT_SAFE_HAVEN_CASH_SUBSTITUTE_THRESHOLD_USD, |
10 | 11 | load_platform_runtime_settings, |
11 | 12 | parse_account_group_configs, |
| 13 | + resolve_non_negative_float_env, |
| 14 | + resolve_optional_ratio_env, |
12 | 15 | ) |
13 | 16 | from strategy_registry import ( |
14 | 17 | IBKR_PLATFORM, |
@@ -122,6 +125,8 @@ def test_load_platform_runtime_settings_uses_minimal_group_config(monkeypatch): |
122 | 125 | assert settings.dry_run_only is False |
123 | 126 | assert settings.quantity_step == 1.0 |
124 | 127 | assert settings.min_order_notional == 50.0 |
| 128 | + assert settings.reserved_cash_floor_usd == DEFAULT_RESERVED_CASH_FLOOR_USD |
| 129 | + assert settings.reserved_cash_ratio is None |
125 | 130 | assert settings.safe_haven_cash_substitute_threshold_usd == DEFAULT_SAFE_HAVEN_CASH_SUBSTITUTE_THRESHOLD_USD |
126 | 131 | assert settings.account_group == "paper" |
127 | 132 | assert settings.service_name is None |
@@ -209,6 +214,48 @@ def test_load_platform_runtime_settings_uses_whole_share_quantity_step(monkeypat |
209 | 214 | assert settings.safe_haven_cash_substitute_threshold_usd == 750.0 |
210 | 215 |
|
211 | 216 |
|
| 217 | +def test_load_platform_runtime_settings_reads_reserved_cash_policy(monkeypatch): |
| 218 | + monkeypatch.setenv("RUNTIME_TARGET_JSON", runtime_target_json(SAMPLE_STRATEGY_PROFILE)) |
| 219 | + monkeypatch.setenv("ACCOUNT_GROUP", "paper") |
| 220 | + monkeypatch.setenv("IB_ACCOUNT_GROUP_CONFIG_JSON", MINIMAL_GROUP_JSON) |
| 221 | + monkeypatch.setenv("IBKR_MIN_RESERVED_CASH_USD", "250") |
| 222 | + monkeypatch.setenv("IBKR_RESERVED_CASH_RATIO", "0.025") |
| 223 | + |
| 224 | + settings = load_platform_runtime_settings(project_id_resolver=lambda: "project-1") |
| 225 | + |
| 226 | + assert settings.reserved_cash_floor_usd == 250.0 |
| 227 | + assert settings.reserved_cash_ratio == 0.025 |
| 228 | + |
| 229 | + |
| 230 | +def test_load_platform_runtime_settings_rejects_invalid_reserved_cash_ratio(monkeypatch): |
| 231 | + monkeypatch.setenv("IBKR_RESERVED_CASH_RATIO", "1.25") |
| 232 | + |
| 233 | + with pytest.raises(ValueError, match="IBKR_RESERVED_CASH_RATIO"): |
| 234 | + resolve_optional_ratio_env("IBKR_RESERVED_CASH_RATIO") |
| 235 | + |
| 236 | + |
| 237 | +@pytest.mark.parametrize("raw_value", ["nan", "inf", "-inf"]) |
| 238 | +def test_load_platform_runtime_settings_rejects_non_finite_reserved_cash_floor( |
| 239 | + monkeypatch, |
| 240 | + raw_value, |
| 241 | +): |
| 242 | + monkeypatch.setenv("IBKR_MIN_RESERVED_CASH_USD", raw_value) |
| 243 | + |
| 244 | + with pytest.raises(ValueError, match="IBKR_MIN_RESERVED_CASH_USD must be finite"): |
| 245 | + resolve_non_negative_float_env("IBKR_MIN_RESERVED_CASH_USD", default=0.0) |
| 246 | + |
| 247 | + |
| 248 | +@pytest.mark.parametrize("raw_value", ["nan", "inf", "-inf"]) |
| 249 | +def test_load_platform_runtime_settings_rejects_non_finite_reserved_cash_ratio( |
| 250 | + monkeypatch, |
| 251 | + raw_value, |
| 252 | +): |
| 253 | + monkeypatch.setenv("IBKR_RESERVED_CASH_RATIO", raw_value) |
| 254 | + |
| 255 | + with pytest.raises(ValueError, match="IBKR_RESERVED_CASH_RATIO must be finite"): |
| 256 | + resolve_optional_ratio_env("IBKR_RESERVED_CASH_RATIO") |
| 257 | + |
| 258 | + |
212 | 259 | def test_load_platform_runtime_settings_reads_ibkr_strategy_plugin_mounts(monkeypatch): |
213 | 260 | mount_config = '{"strategy_plugins":[{"strategy":"soxl_soxx_trend_income","plugin":"crisis_response_shadow","signal_path":"gs://bucket/latest_signal.json"}]}' |
214 | 261 | monkeypatch.setenv("RUNTIME_TARGET_JSON", runtime_target_json("soxl_soxx_trend_income")) |
@@ -431,6 +478,8 @@ def test_print_strategy_switch_env_plan_for_tqqq_growth_income(): |
431 | 478 | assert plan["requires_strategy_config_path"] is False |
432 | 479 | assert json.loads(plan["set_env"]["RUNTIME_TARGET_JSON"])["strategy_profile"] == "tqqq_growth_income" |
433 | 480 | assert "ACCOUNT_GROUP" in plan["keep_env"] |
| 481 | + assert "IBKR_MIN_RESERVED_CASH_USD" in plan["optional_env"] |
| 482 | + assert "IBKR_RESERVED_CASH_RATIO" in plan["optional_env"] |
434 | 483 | assert "IBKR_SAFE_HAVEN_CASH_SUBSTITUTE_THRESHOLD_USD" in plan["optional_env"] |
435 | 484 | assert "IBKR_FEATURE_SNAPSHOT_PATH" in plan["remove_if_present"] |
436 | 485 |
|
|
0 commit comments