When to Use
Invoke this when code builds an IBKR Contract and picks a destination for it — across US,
European, Hong Kong or other IBKR markets. IBKR's own boilerplate put its reach at "over 170
markets" as of 1 July 2026, and a single symbol string can match several of them, so the
question this skill answers is which contract you actually addressed and where the order
will go.
Two fields carry that weight:
exchangeis the destination. EitherSMART(IBKR's SmartRouting, which evaluates price, transaction cost and add/remove-liquidity fees across venues and can split an order) or a direct venue code such asISLAND,DTBorSEHK.primaryExchangeis not a destination. It names the contract's native listing venue and exists to break ties: "For smart routed contracts, used to define contract in case of ambiguity."
The helper in scripts/ is a pre-flight screen, not an oracle. It catches the parameter
mistakes that produce error 200 ("No security definition has been found for the request") or
an ambiguity error, plus order-field mistakes IBKR rejects at entry. It cannot tell you a
contract exists.
When NOT to Use
- You already hold a
conId.Contract.conIdis "the unique IB contract identifier". Submitting on a conId removes symbol ambiguity entirely — none of the symbol heuristics here add anything. - You need to know whether a venue is actually available for a contract. That is
ContractDetails.validExchanges("Valid exchange fields when placing an order for this contract") andContractDetails.aggGroup == -1(contract cannot be smart-routed). No local table substitutes for the lookup. - You are comparing execution quality across brokers or venues. This skill validates
addressing, not outcomes — see
smart-order-routing-across-venuesandpost-trade-execution-quality-scorecard. - You are on IBKR's Client Portal Web API. Different contract-resolution endpoints and a different identifier flow; the TWS API field semantics here do not transfer.
- You need connectivity, session or process management. That is
ibkr-tws-gateway-headless-launch.
Prerequisites
- A running IB Gateway or TWS with API access enabled, and an
ibapi/ib_insyncclient able to callreqContractDetails. Validation without that call is half a workflow. - Market-data and trading permissions for the destination market — a permission failure looks nothing like a malformed contract, and this skill will not catch it.
- The order payload:
symbol,sec_type,currency,exchange, optionalprimary_exchange, a localrouting_mode, plusaction,order_type,quantityandlmt_price.
Workflow
-
Screen the payload locally with
IbkrGlobalRoutingEngine.audit_and_route_order. It rejects only on a positive contradiction of documented IBKR behaviour and returns everything else aswarnings, because rejecting a valid order is as much a production failure as accepting an invalid one. Readreport.warningseven onIBKR_ROUTING_VALIDATED— that is where "SMART with no listing hint, currency unchecked" lives. -
Keep
routing_modeconsistent withexchange, and know what it is not.SMART_BEST_EXECUTION/SMART_MAX_REBATErequireexchange='SMART';DIRECT_EXCHANGErequires a venue code. The engine rejects the contradiction rather than letting a config that reads as direct-routed be silently smart-routed.SMART_MAX_REBATEis a local label only: rebate-seeking routing of non-marketable orders is an account/TWS election under the Cost Plus commission structure, not an order field, so the engine flags it and emits nothing on the wire. -
Set
primaryExchangeon stocks when the symbol is ambiguous — and nowhere else. IBKR calls it "good practice to include for all stocks" but does not require it; its own shippedUSStockAtSmartsample smart-routesIBKR/USDwith noprimaryExchangeat all. So a missing hint on a smart-routed stock is a warning, not a rejection, and a missing hint on an option, future or forex pair is neither. If the venue name contains a period, pass only the part before it (ENEXT, notENEXT.BE).primaryExchange='SMART'is always wrong. -
Do not reformat symbols to match a market-data vendor's display convention. HKEX publishes zero-padded display codes (
00700), but IBKR's shipped SEHK contract sample usessymbol = "1"for the security listed under HKEX code 00001 — the plain code, unpadded. The engine therefore validates the shape and returns the symbol unchanged; a zero-padded input passes with a warning rather than being rewritten in either direction. Confirm the exact string withreqContractDetails. -
Treat currency as a property of the line, not of the region. Venue-currency rules break on real instruments: HKEX runs the HKD-RMB Dual Counter Model, so an SEHK line can be CNH; IBKR's Stock Connect venues (
SEHKNTL,SEHKSZSE) carry 6-digit mainland codes quoted in CNH; Eurex lists CHF-denominated SMI products alongside its EUR book. ForsecType='CASH'the rule is inverted entirely —symbolis the base currency andcurrencythe quote currency (EUR/GBPonIDEALPRO), so no region rule applies. When the destination isSMART, the currency is checked against theprimaryExchangelisting venue; with no hint, it is not checked at all and says so. -
Resolve with
reqContractDetails, then submit on the returnedconId. ReconcileexchangeagainstvalidExchanges, checkaggGroup != -1before assumingSMARTis available, and confirm the currency IBKR reports. A local pass is a precondition; this call is the gate.report.requires_contract_details_checkis alwaysTruefor exactly this reason.
Full step-by-step procedure: see
references/workflows.md. Venue table, field semantics and sources: seereferences/standards.md. Printable pre-flight checklist: seeassets/checklist.md.
Common Pitfalls
- Zero-padding Hong Kong codes to five digits. A vendor feed showing
00700does not mean IBKR wants00700. IBKR's own SEHK sample issymbol = "1". Padding a symbol IBKR lists unpadded converts a resolvable contract into error 200 — and the failure surfaces at order entry, not at import. - Hard-coding "SEHK means HKD" or "Eurex means EUR". Both are false for real, routable lines (RMB dual counters; CHF SMI products). A currency rule that rejects a valid instrument costs you the trade just as surely as one that accepts an invalid one.
- Applying an equity symbol rule by currency. Keying off
currency == 'HKD'alone drags HKEX derivatives into it and rejectsHSIonHKFEfor not being a numeric stock code. Scope symbol-format rules to security type and venue. - Requiring
primaryExchangeon everything smart-routed. It is a stock-ambiguity tie-breaker. Demanding it on a smart-routed option or future rejects contracts IBKR accepts. - Validating currency only on direct venues. The
SMARTpath is the common path. A validator that skips it passescurrency='EUR'withprimaryExchange='NASDAQ'— the exact mistake it was written to catch. - Letting
routing_modeandexchangedisagree. A config labelledDIRECT_EXCHANGEthat still carriesexchange='SMART'is smart-routed. The label is documentation; onlyContract.exchangereaches IBKR. - Expecting an order-level "maximise rebate" flag. There isn't one. Rebate-seeking routing of non-marketable orders is elected at the account/TWS level under Cost Plus, and IBKR is explicit that best execution stays the priority, so not all trades earn rebates.
- Skipping order-field validation because "IBKR will reject it anyway". A
LMTorder with no limit price, a negative quantity oraction='LONG'costs a round trip and an unexplained rejection in the middle of a live session.lmtPriceis documented as used for limit, stop-limit and relative orders and zero otherwise. - Typing quantity as
int. TWS API v10 typestotalQuantityasDecimal; an int-only payload cannot express a fractional-share or forex size at all. - Treating a local pass as a routable contract. It means "no known-bad parameter found".
Only
reqContractDetailsknows whether the contract exists and where it may go.
Verification
- Run the unit suite:
python -m unittest discover -s skills/interactive-brokers-global-multi-exchange-routing/scripts— all tests must pass. - Route
symbol='700',secType='STK',currency='HKD',exchange='SEHK',routing_mode='DIRECT_EXCHANGE'and confirmreport.symbol == '700'— the audit must not rewrite it. - Route
currency='EUR'withexchange='SMART',primaryExchange='NASDAQ'and confirmREJECTED_CURRENCY_MISMATCH; the same contract withexchange='ISLAND'must reject too. - Route a
FUTonDTBinCHFand anSTKonSEHKinCNH, and confirm both areIBKR_ROUTING_VALIDATED— venue-currency rules must not reject real instruments. - Route a smart-routed
OPTwith noprimaryExchangeand confirmIBKR_ROUTING_VALIDATED; route a smart-routedSTKwith noprimaryExchangeand confirm it also validates, but carries a warning. - Route
routing_mode='DIRECT_EXCHANGE'withexchange='SMART'and confirmREJECTED_ROUTING_MODE_CONFLICT. - Route an unknown venue code and confirm it validates with a warning rather than rejecting.
- Route
quantity=0,lmt_price=Noneon aLMT, andaction='LONG'and confirm each givesREJECTED_INVALID_ORDER_PARAMS. - Against a live Gateway, call
reqContractDetailsfor every contract you validated and confirmvalidExchangescontains yourexchange, thataggGroup != -1if you routedSMART, and that the reported currency matches.