Summary
After the ib_insync → ib_async migration, viewing the broker order stack with a live combo/spread (roll) order produces a stream of ib_async.wrapper warnings, and the combo order is silently omitted from the displayed list.
Steps to reproduce
- Have a live futures spread/roll order at IB (IB represents these as a BAG contract).
- Run interactive_order_stack → 0 (View) → 4 (View IB orders and fills).
Observed behaviour
WARNING ib_async.wrapper Warning 2104, reqId -1: Market data farm connection is OK:cafarm
... (2104 / 2106 / 2158 messages) ...
WARNING ib_async.wrapper Warning 321, reqId 664678: Error validating request.-'bI' :
cause - 'BAG' isn't supported for contract data request. Please enter a valid
security type, contract: Bag(conId=..., symbol='HE', ..., comboLegs=[...])
The combo order does not appear in the order list.
Root cause
_create_broker_control_order_object (sysbrokers/IB/ib_orders.py) passes the raw contract to the instrument-code lookup:
ib_contract = trade_with_contract_from_ib.ibcontract_with_legs.ibcontract
instrument_code = self.futures_instrument_data.get_instrument_code_from_broker_contract_object(ib_contract)
For a combo order that ib_contract is a BAG. The lookup chain ends at ibClient._get_contract_details → self.ib.reqContractDetails(BAG). IB's API does not support reqContractDetails on a BAG contract (Warning 321), so it returns
nothing → missingContract → caught by the bare except in _create_broker_control_order_object → order skipped as "usual behaviour for FX and equities trades".
So a system's own roll orders are silently dropped from "View IB orders and fills". This is a long-standing logic issue, but it was previously masked: commit 741906a ("remove error reporting from ib_client. we get same messages
direct from logger"), part of the ib_async migration, deleted ibClient.error_handler, which used to intercept and filter IB messages. Now ib_async's own logger emits every IB message — including the BAG warning and the harmless
2104/2106/2158 "connection is OK" notices — straight to the console at WARNING level.
Two separable problems
- Combo orders dropped / spurious Warning 321. reqContractDetails should never be called on a BAG. Each resolved leg (already available in ibcontract_with_legs.legs) is an ordinary futures contract for the same instrument and
can be used for the instrument-code lookup instead.
- Console noise. With error_handler removed, routine IB informational warnings (2104/2106/2158) now print at WARNING level on every connection. Consider re-adding a lightweight handler or filtering these, or documenting the
expected log output.
Suggested fix for (1)
When the contract is a BAG with resolved legs, identify the instrument from the first leg rather than the BAG:
def _ib_contract_for_instrument_lookup(ibcontract_with_legs):
ib_contract = ibcontract_with_legs.ibcontract
legs = ibcontract_with_legs.legs
if getattr(ib_contract, "secType", "") == "BAG" and len(legs) > 0:
return legs[0]
return ib_contract
…and call it in _create_broker_control_order_object. Happy to open a PR if useful.
Environment
- pysystemtrade develop (post ib_async migration, commit 741906a present)
- ib_async 2.x
- Python 3.10
Summary
After the ib_insync → ib_async migration, viewing the broker order stack with a live combo/spread (roll) order produces a stream of ib_async.wrapper warnings, and the combo order is silently omitted from the displayed list.
Steps to reproduce
Observed behaviour
WARNING ib_async.wrapper Warning 2104, reqId -1: Market data farm connection is OK:cafarm
... (2104 / 2106 / 2158 messages) ...
WARNING ib_async.wrapper Warning 321, reqId 664678: Error validating request.-'bI' :
cause - 'BAG' isn't supported for contract data request. Please enter a valid
security type, contract: Bag(conId=..., symbol='HE', ..., comboLegs=[...])
The combo order does not appear in the order list.
Root cause
_create_broker_control_order_object (sysbrokers/IB/ib_orders.py) passes the raw contract to the instrument-code lookup:
ib_contract = trade_with_contract_from_ib.ibcontract_with_legs.ibcontract
instrument_code = self.futures_instrument_data.get_instrument_code_from_broker_contract_object(ib_contract)
For a combo order that ib_contract is a BAG. The lookup chain ends at ibClient._get_contract_details → self.ib.reqContractDetails(BAG). IB's API does not support reqContractDetails on a BAG contract (Warning 321), so it returns
nothing → missingContract → caught by the bare except in _create_broker_control_order_object → order skipped as "usual behaviour for FX and equities trades".
So a system's own roll orders are silently dropped from "View IB orders and fills". This is a long-standing logic issue, but it was previously masked: commit 741906a ("remove error reporting from ib_client. we get same messages
direct from logger"), part of the ib_async migration, deleted ibClient.error_handler, which used to intercept and filter IB messages. Now ib_async's own logger emits every IB message — including the BAG warning and the harmless
2104/2106/2158 "connection is OK" notices — straight to the console at WARNING level.
Two separable problems
can be used for the instrument-code lookup instead.
expected log output.
Suggested fix for (1)
When the contract is a BAG with resolved legs, identify the instrument from the first leg rather than the BAG:
def _ib_contract_for_instrument_lookup(ibcontract_with_legs):
ib_contract = ibcontract_with_legs.ibcontract
legs = ibcontract_with_legs.legs
if getattr(ib_contract, "secType", "") == "BAG" and len(legs) > 0:
return legs[0]
return ib_contract
…and call it in _create_broker_control_order_object. Happy to open a PR if useful.
Environment