Skip to content

Commit 3731e3d

Browse files
authored
Merge pull request #405 from QuantStrategyLab/fix/readonly-shadow-gateway-connect
fix: use readonly Gateway sessions for shadow runs
2 parents a73dbe9 + 923e3d4 commit 3731e3d

5 files changed

Lines changed: 38 additions & 9 deletions

File tree

main.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,19 @@ def build_broker_adapters(*, dry_run_only_override: bool | None = None):
585585
if RUNTIME_SETTINGS.runtime_target is not None
586586
else None
587587
)
588+
589+
def connect_runtime_ib(host, port, client_id, *, timeout):
590+
# Shadow and dry-run cycles need account and market reads only. Mark
591+
# their Gateway sessions read-only so they cannot trigger an IBKR
592+
# write-access confirmation or acquire trading authority.
593+
return ibkr_connect_ib(
594+
host,
595+
port,
596+
client_id,
597+
timeout=timeout,
598+
readonly=effective_dry_run_only,
599+
)
600+
588601
return build_runtime_broker_adapters(
589602
host_resolver=get_ib_host,
590603
refresh_host_fn=refresh_ib_host,
@@ -596,7 +609,7 @@ def build_broker_adapters(*, dry_run_only_override: bool | None = None):
596609
connect_retry_delay_seconds=IB_CONNECT_RETRY_DELAY_SECONDS,
597610
client_id_retry_offset=IB_CLIENT_ID_RETRY_OFFSET,
598611
ensure_event_loop_fn=ensure_event_loop,
599-
connect_ib_fn=ibkr_connect_ib,
612+
connect_ib_fn=connect_runtime_ib,
600613
fetch_portfolio_snapshot_fn=fetch_market_portfolio_snapshot,
601614
fetch_quote_snapshots_fn=fetch_market_quote_snapshots,
602615
submit_order_intent_fn=submit_market_order_intent,

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ dependencies = [
2121
"google-cloud-secret-manager",
2222
"google-cloud-storage",
2323
"yfinance",
24-
"quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@aae333fe8b3fe5aeb32e1ff135ab14ea7db32420",
24+
"quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@4d716cb1c6b42747fb96be3d398c528b26cd5826",
2525
"us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@6776c59d709848abdfb513ef5f1853be029f99b1",
2626
"hk-equity-strategies @ git+https://github.com/QuantStrategyLab/HkEquityStrategies.git@e385485cf1db306ce7efd30bfb9e181139767fa7",
2727
]
@@ -64,5 +64,5 @@ include = [
6464

6565
[tool.uv]
6666
override-dependencies = [
67-
"quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@aae333fe8b3fe5aeb32e1ff135ab14ea7db32420",
67+
"quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@4d716cb1c6b42747fb96be3d398c528b26cd5826",
6868
]

qsl.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ upgrade_ring = "ring_d"
55
allow_legacy = false
66

77
[qsl.requires]
8-
quant_platform_kit = "aae333fe8b3fe5aeb32e1ff135ab14ea7db32420"
8+
quant_platform_kit = "4d716cb1c6b42747fb96be3d398c528b26cd5826"
99
us_equity_strategies = "6776c59d709848abdfb513ef5f1853be029f99b1"
1010
hk_equity_strategies = "e385485cf1db306ce7efd30bfb9e181139767fa7"
1111

tests/test_event_loop.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def worker():
2020
assert not loop.is_closed()
2121

2222

23-
def test_connect_ib_prepares_event_loop_before_connect(strategy_module, monkeypatch):
23+
def test_connect_ib_prepares_readonly_event_loop_before_dry_run_connect(strategy_module, monkeypatch):
2424
observed = {}
2525

2626
def fake_ibkr_connect(host, port, client_id, **kwargs):
@@ -32,7 +32,23 @@ def fake_ibkr_connect(host, port, client_id, **kwargs):
3232
with ThreadPoolExecutor(max_workers=1) as executor:
3333
executor.submit(strategy_module.connect_ib).result()
3434

35-
assert observed["args"] == ("127.0.0.1", 4001, 1, {"timeout": 60})
35+
assert observed["args"] == ("127.0.0.1", 4001, 1, {"timeout": 60, "readonly": True})
36+
37+
38+
def test_live_runtime_adapter_keeps_writable_gateway_session(strategy_module_factory, monkeypatch):
39+
module = strategy_module_factory(IBKR_DRY_RUN_ONLY="false")
40+
observed = {}
41+
42+
def fake_ibkr_connect(host, port, client_id, **kwargs):
43+
observed["args"] = (host, port, client_id, kwargs)
44+
return object()
45+
46+
monkeypatch.setattr(module, "ibkr_connect_ib", fake_ibkr_connect)
47+
48+
adapters = module.build_broker_adapters()
49+
adapters.connect_ib_fn("127.0.0.1", 4001, 1, timeout=60)
50+
51+
assert observed["args"] == ("127.0.0.1", 4001, 1, {"timeout": 60, "readonly": False})
3652

3753

3854
def test_connect_ib_retries_with_offset_client_ids(strategy_module_factory, monkeypatch):

uv.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)