Skip to content
Open
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
1 change: 1 addition & 0 deletions docs/user-guide/brokers.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ await broker.connect()
- `7496` is the usual TWS live port
- `4002` and `4001` are the usual paper/live IB Gateway ports
- TWS or IB Gateway must be running with API access enabled before you connect
- Submitted orders use `DAY` time in force so TWS presets do not change their duration.

## Alpaca

Expand Down
2 changes: 2 additions & 0 deletions src/ml4t/live/brokers/ib.py
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,8 @@ def _create_ib_order(
else:
raise ValueError(f"Unsupported order type: {order_type}")

# Send a concrete TIF so TWS presets cannot change it after submission.
order.tif = "DAY"
# Honor the caller's extended-hours intent (no-op before this was set).
order.outsideRth = outside_rth
return order
Expand Down
3 changes: 3 additions & 0 deletions tests/unit/test_ib_broker.py
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,8 @@ async def test_submit_limit_order(self, mock_ib_class):
assert order.quantity == 50
assert order.order_type == OrderType.LIMIT
assert order.limit_price == 150.0
_, ib_order = mock_ib.placeOrder.call_args.args
assert ib_order.tif == "DAY"

@pytest.mark.asyncio
@patch("ml4t.live.brokers.ib.IB")
Expand Down Expand Up @@ -713,6 +715,7 @@ async def test_submit_market_order_defaults_rth_only(self, mock_ib_class):

_, ib_order = mock_ib.placeOrder.call_args.args
assert ib_order.outsideRth is False
assert ib_order.tif == "DAY"

@pytest.mark.asyncio
@patch("ml4t.live.brokers.ib.IB")
Expand Down
5 changes: 3 additions & 2 deletions tests/unit/test_provider_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ def test_tampered_reported_contract_fails_closed(
assert classification.reason == "reported contract does not match its evidence commit"


def test_pending_candidate_preserves_v012_ib_contract() -> None:
def test_ib_tif_change_invalidates_v012_evidence() -> None:
repository = Path(__file__).resolve().parents[2]
tag = subprocess.run(
["git", "cat-file", "-e", "v0.1.2^{commit}"],
Expand All @@ -238,4 +238,5 @@ def test_pending_candidate_preserves_v012_ib_contract() -> None:
pytest.skip("v0.1.2 history is required")
classification = _classification(repository, "ib", "v0.1.2", "HEAD")

assert classification.reusable is True
assert classification.reusable is False
assert "src/ml4t/live/brokers/ib.py" in classification.changed_inputs
Loading