NautilusTrader
Integrations

Interactive Brokers

The Interactive Brokers adapter connects NautilusTrader to Trader Workstation (TWS) or IB Gateway through the TWS API. It provides live market data, execution, instrument discovery, historical requests, and optional management of a Dockerized IB Gateway.

The Python package includes the adapter. Follow the installation guide, then use the examples under examples/live/interactive_brokers.

Connect to TWS or IB Gateway

Enable socket API access in TWS or IB Gateway before starting a client. IB uses these default ports:

ApplicationPaper tradingLive trading
TWS74977496
IB Gateway40024001

The pinned ibapi 4.0.1 transport requires TWS or IB Gateway server protocol version 213 or newer. This is the API protocol version, not the application's release number. Older servers are unsupported even when their TCP port accepts connections. Issue #4796 reports this failure with protocol 187 on Gateway 10.41. Upgrade TWS or IB Gateway before connecting.

The transport rejects an older version before sending StartApi when the server completes the initial handshake. If an old server does not answer that handshake, the connection timeout also applies. Increasing the timeout does not add protocol support.

The adapter defaults to 127.0.0.1:4002. Each process connected to the same TWS or Gateway session needs a distinct IB API client_id. An execution client ID cannot be a multiple of 1000 because the adapter partitions order IDs with client_id % 1000.

IB refuses an order ID at or below one the same client_id already used, across sessions (error 103). On connect, the execution client starts above its client_id's highest order ID among IB's open and completed orders. It keeps IB's next valid ID only when it falls in the client's partition. If IB's next valid ID lies above the partition, IB would refuse every ID in it, so connecting fails. Use another client_id. Connecting also fails if the completed orders do not arrive in full within request_timeout.

IB lists completed orders for a limited period only, so a client that left no order open can still start below an ID it used before that period.

The data and execution clients can share one provider configuration:

from nautilus_trader.adapters import interactive_brokers as ib
from nautilus_trader.model import AccountId
from nautilus_trader.model import InstrumentId
from nautilus_trader.model import TraderId


trader_id = TraderId.from_str("TRADER-001")
account_id = AccountId.from_str("IB-DU123456")
provider_config = ib.InteractiveBrokersInstrumentProviderConfig(
    symbology_method=ib.SymbologyMethod.SIMPLIFIED,
    load_ids={InstrumentId.from_str("AAPL.XNAS")},
)

data_config = ib.InteractiveBrokersDataClientConfig(
    host="127.0.0.1",
    port=7497,
    client_id=101,
    market_data_type=ib.MarketDataType.DELAYED_FROZEN,
    instrument_provider=provider_config,
)

exec_config = ib.InteractiveBrokersExecutionClientConfig(
    host="127.0.0.1",
    port=7497,
    client_id=102,
    account_id="DU123456",
    instrument_provider=provider_config,
)

data_factory = ib.InteractiveBrokersDataClientFactory()
exec_factory = ib.InteractiveBrokersExecutionClientFactory()

Pass these factories and configs to LiveNode.builder. The connect_with_tws.py example shows the complete node setup. Its default invocation constructs the node offline. Set IB_V2_RUN_NODE=1 to connect.

Market data modes

Enum valueIB mode
MarketDataType.REALTIMELive subscribed data.
MarketDataType.FROZENLast available live data after market close.
MarketDataType.DELAYEDDelayed data.
MarketDataType.DELAYED_FROZENLast available delayed data.

IB permissions still determine which mode and instruments return data. Delayed or delayed-frozen data can support paper-account checks outside market hours, but it does not prove a live tick path.

Dockerized IB Gateway

DockerizedIBGateway manages the gnzsnz IB Gateway container. Supply credentials in the config or set TWS_USERNAME and TWS_PASSWORD:

from nautilus_trader.adapters import interactive_brokers as ib


gateway = ib.DockerizedIBGateway(
    ib.DockerizedIBGatewayConfig(
        trading_mode=ib.TradingMode.PAPER,
        read_only_api=True,
        timeout=300,
    ),
)
gateway.safe_start_blocking()

data_config = ib.InteractiveBrokersDataClientConfig(
    host=gateway.host,
    port=gateway.port,
    client_id=101,
)

Start the gateway before constructing clients that connect. Python owns the container lifecycle through DockerizedIBGateway. The client configs accept only host and port. Set read_only_api=False only when the gateway must accept orders. Readiness uses login messages from the current container session, so retained logs from an earlier session cannot report a false ready state.

Architecture

The adapter is one Rust implementation exposed through the native Rust API and PyO3 bindings. It translates between IB's TWS API and the Nautilus live engines. It does not own a transport: ibapi speaks the TWS socket protocol and reconnects it. The adapter owns domain mapping, subscription lifecycle, and policy (commands, events, instrument conversion, stream resubscription, and execution reconciliation). That boundary explains the crate's layout, and it is why the http and websocket modules standard in other adapters do not exist here.

Data, execution, and historical clients with the same (host, port, client_id) share one reference-counted ibapi connection. Concurrent acquisition for the same key converges on one connection, and the registry removes it after the final client releases its handle.

ModuleResponsibility
commonContracts, enums, generic spread IDs, symbology, and shared connections.
providersContract qualification, chain discovery, venue resolution, and instrument cache.
dataLive subscriptions, historical request routing, conversion, and stream recovery.
executionCommands, order state, updates, reports, conditions, spreads, and reconciliation.
historicalStandalone instrument, bar, and tick requests.
gatewayDocker container configuration, lifecycle, and readiness.
pythonPyO3 classes, enums, factories, and conversion boundaries.
configTyped data, execution, provider, and gateway configuration.
factoriesDataClientFactory and ExecutionClientFactory implementations.

The integration surface with the rest of Nautilus is deliberately thin. The node builder hands each factory a typed config. The factory builds the client and seeds the instrument provider from the engine cache, which the adapter never writes.

The data client sends typed data events (ticks, bars, instruments, and correlated request responses) and the execution client sends typed execution events (order events, fills, and account state) into the engines through their event channels. These channels are the only paths into the engines. The adapter registers its factories and config extractors with the global PyO3 registry, which is how Python TradingNode configurations reach the Rust factories. Reconciliation is a pull interface driven by the execution engine (see Reconciliation).

Reconnect and resubscribe

The ibapi transport reconnects the socket with Fibonacci backoff up to a bounded attempt count, then establishes a complete session. A TCP connection followed by a transient handshake or startup error consumes an attempt and retries instead of ending recovery. A successful reconnect resets open subscription channels by delivering a connection-reset error to each. On exhaustion the transport shuts down and the adapter reports disconnected.

Each data stream then waits for the transport, subscribes again, and retries failed resubscriptions with a delay. One generic stream driver owns this lifecycle policy for every stream type, so recovery behavior cannot drift between quotes, trades, depth, bars, greeks, and index prices. Market-data farm notices use the same stream policy without treating a farm outage as a socket failure. TWS resets the session's market-data type to realtime after a reconnect. The notice monitor restores the configured frozen or delayed mode before releasing recovered subscriptions.

Order-bound error frames arrive on the order update stream as notices with the originating order or request ID. The transport's routing layer delivers these notices instead of a decoded message variant. Thus, the update stream stays alive across error frames.

Quotes, trades, depth, bars, option greeks, and index prices follow this lifecycle. Before a depth stream applies data from a replacement subscription, it clears the existing book so stale levels cannot survive. If the order-update or global notice stream ends, the execution client reports disconnected instead of appearing healthy with a dead stream.

Order identity and cancellation

Distinct broker permanent IDs sharing one client order reference remain separate physical orders. The adapter reports each additional order under its own client order ID: DUP-<account length>:<account ID>:PERM-<permanent ID>. Thus, the execution engine creates it as an external order. The instrument's external order claim applies, or otherwise the EXTERNAL strategy. An unresolved duplicate group blocks modification.

When an execution arrives for an order the adapter does not track, including such a duplicate, the adapter holds the fill and queries the order's details and executions. It then reports the order together with its real fills, so the engine creates the order at its full quantity. The query is bounded by request_timeout and at most 3 seconds, below the live node's default position_check_threshold_ms of 5 seconds. If the query fails, returns nothing, or times out, the adapter logs a warning and forwards the held fills unchanged.

With strategy_only=True (the default), the strategy issues individual cancellations for its own orders. With strategy_only=False, cancel-all is instrument-wide within the selected account and side. A side-filtered cancel-all skips duplicate orders whose broker side is still unknown. Canceling the original order also considers its known working duplicates.

The adapter cancels only uniquely bound routes owned by the configured API client. Ambiguous or unbound orders remain explicitly unresolved and require TWS binding or operator action. One cancellation confirmation does not establish group completion.

Risk checks and execution use the same account routing. The risk engine denies an order whose account is unresolved rather than skipping account checks.

Execution order flow

The execution client is split along message direction: outbound commands (submit, modify, cancel), inbound venue updates, combo-fill assembly, and account streams are separate modules sharing one order-state owner. That owner holds the client-to-venue ID maps, active orders, and a bounded terminal-order cache behind a single lock. The terminal cache absorbs IB's execution replays after a reconnect. Thus, a completed order's re-sent fills deduplicate instead of duplicating. The client converts each Nautilus order once, applies optional IB tags, and then submits it through ibapi.

Every engine-visible order event originates from venue evidence on the update stream: OrderAccepted requires an order status or open-order message, never local send success. An order-bound IB error notice resolves against tracked orders and is handled by order state.

Before acceptance, an order rejection code in [200, 399] emits a terminal OrderRejected. Any other error code triggers a venue query. The order is rejected only when IB lists it neither as open nor as completed. IB also sends such codes for working orders (10349 sets the time in force from an order preset). A presence query that fails, times out, or ends early leaves the order working.

After acceptance, a notice emits OrderModifyRejected when a modify is pending or OrderCancelRejected when a cancel is pending. Otherwise, it triggers a venue presence query rather than a terminal event. IB reports modify rejections with the same codes while the original order keeps working, so the query prevents a false terminal event.

Warning codes in [2100, 2169], warning-form order messages (code 399 with a Warning: line), and the cancel confirmation (202) never terminalize an order. The global notice stream handles error frames that cannot be routed to an individual request or order.

Ambiguous command outcomes resolve through a venue query. It recovers missed fills from execution history before inferring any terminal state. Thus, a fill can never be misreported as a cancellation. Cancel-all prefers the tracked TWS order ID over the permanent ID, which lets the originating client cancel its own live orders without a cross-client lookup.

Data capabilities

Nautilus data typeLive subscribeHistorical requestNotes
InstrumentNoYesStartup loading and explicit requests.
Quote tickYesYesTick-by-tick or batched reqMktData.
Trade tickYesYesTick-by-tick live and historical trades.
BarYesYesExternal time bars.
Book deltaYesNoMarket depth with book clear on recovery.
Index priceYesNoIndex price events.
Option greeksYesNoGreeks plus option open interest.

Set batch_quotes=False to prefer tick-by-tick bid/ask subscriptions. The client falls back to reqMktData when tick-by-tick quotes are unavailable, and BAG spread quotes always use reqMktData. ignore_quote_tick_size_updates=True filters quote events whose only change is size.

The quote cache assembles bid and ask updates into complete quote ticks. IB no-quote sentinels (price -1 without a size, or a zero price with zero size) are filtered before ticks are built and clear the affected book side, so a one-sided market emits nothing rather than stale values. Genuine zero and negative prices, including a -1 price with a size, which calendar spreads produce routinely, flow through.

For historical data, HistoricalInteractiveBrokersClient accepts an instrument provider and data client config. Constructing this Python client connects immediately, so keep it behind the same explicit run gate as the request:

from nautilus_trader.adapters import interactive_brokers as ib


provider_config = ib.InteractiveBrokersInstrumentProviderConfig()
provider = ib.InteractiveBrokersInstrumentProvider(provider_config)
config = ib.InteractiveBrokersDataClientConfig(
    host="127.0.0.1",
    port=7497,
    client_id=180,
    market_data_type=ib.MarketDataType.DELAYED,
    instrument_provider=provider_config,
)

# This constructor connects to TWS or IB Gateway.
client = ib.HistoricalInteractiveBrokersClient(provider, config)
MethodSelectors and controls
request_instrumentsAccepts Nautilus instrument IDs, IB contract dictionaries, or both.
request_barsAccepts bar specification strings, an end time, and either a start time or IB duration string; contracts or instrument IDs select the instruments.
request_ticksAccepts IbHistoricalTickType.TRADES or BID_ASK, a bounded time range, contracts or instrument IDs, regular-hours filtering, timeout, and a result limit.

Historical tick requests need both a start and an end time. They page backward from the end time, with a default cap of 10,000 ticks when no limit is given. They send only an end bound because IB misinterprets requests with both bounds. They deduplicate the boundary second that IB's second-resolution end encoding re-delivers. When one second holds a full page and the window cannot retreat, the request stops with a warning instead of looping.

A bar request whose segment fails returns an error rather than a series with a silent hole. Historical trade ticks with IB's zero size are skipped before constructing the positive-quantity Nautilus type. Other invalid conversions still fail the request.

IB controls pacing, available history, supported bar sizes, and regular-trading-hours filtering. For continuous futures, IB rejects an explicit bar end time. The adapter omits it and requests one duration segment anchored to the request time, so the result can fall outside the requested start and end range.

Execution capabilities

Order types

Nautilus order typeIB order typePrice inputs
MARKETMarketNone.
LIMITLimitLimit price.
MARKET_TO_LIMITMarket to limitNone.
STOP_MARKETStopTrigger price.
STOP_LIMITStop limitLimit and trigger prices.
MARKET_IF_TOUCHEDMarket if touchedTrigger price.
LIMIT_IF_TOUCHEDLimit if touchedLimit and trigger prices.
TRAILING_STOP_MARKETTrailing stopTrailing offset and optional trigger.
TRAILING_STOP_LIMITTrailing stop limitLimit and trailing offsets.

The adapter maps DAY, GTC, IOC, FOK, GTD, and AT_THE_OPEN time in force values. A market or limit order with AT_THE_CLOSE becomes the corresponding market-on-close or limit-on-close IB order. GTD orders include their Nautilus expiry time in the IB order.

The adapter rejects post-only orders. Quote quantity is valid only for inverse instruments, and only on BUY MARKET orders, which IB sizes by cashQty (IB rejects a cash quantity on any other order type with error 10244). Trailing orders support price offsets and basis-point offsets, which IB receives as a trailing percent. These checks, and any order the adapter cannot resolve or transform for IB, emit coded OrderDenied reasons before the adapter sends an order to IB.

Commands and order attributes

CapabilitySupportNotes
Submit orderYesSingle orders and generic spreads.
Submit order listYesIncludes bracket and linked orders.
Modify orderYesQuantity, price, trigger, and IB parameter updates.
Cancel orderYesUses tracked venue order state.
Cancel all ordersYesScoped through the execution client.
Query orderYesChecks open orders, then executions before inferring cancel.
Mass statusYesOrders, fills, and positions.

Pass params={"exchange": "IEX"} to submit, submit-list, or modify commands to override the cached contract exchange for that command. An omitted or empty value retains the cached exchange.

IB accepts a new trailing stop price only together with a new trailing amount (error 10067). A modify that sets a trailing stop's trigger must pass params={"trailing_offset": <offset>} in the order's offset units: a price amount for PRICE offsets, or basis points for BASIS_POINTS offsets. An offset equal to the current one is rejected by IB, and a trigger modify without the parameter is rejected before it is sent.

IB-specific order fields use a tag prefixed with IBOrderTags: followed by a JSON object. Keys use the ibapi order field names in snake case or lower camel case. Unknown fields fail the order conversion. The adapter normalizes order_type, tif or timeInForce, action, oca_type, trigger_method, origin, short_sale_slot, volatility_type, reference_price_type, rule_80_a, open_close, and NonGuaranteed. Active, stop, cancel, manual, and good-till timestamps use %Y%m%d %H:%M:%S UTC.

The adapter tracks each order by its IB order ID and reference, and checks each execution against the order side. Thus, tags cannot set orderId, clientId, permId, orderRef, totalQuantity, cashQty, parentId, or transmit. A tagged action must keep the order side: a SELL order may use SSHORT or SLONG, but not BUY. Such a tag fails the order conversion.

The optional conditions array accepts these shapes:

ConditionRequired fieldsOptional fields and defaults
priceNoneconId=0, exchange="SMART", price=0, isMore=True, triggerMethod=0.
timeNonetime="", isMore=True.
marginNonepercent=0, isMore=True.
executionsymbolsecType="STK", exchange="SMART".
volumeNoneconId=0, exchange="SMART", volume=0, isMore=True.
percent_changeNoneconId=0, exchange="SMART", changePercent=0, isMore=True.

Every condition accepts conjunction="and" or "or". The default is "and".

Account state

On connect and on each account query, the execution client reads one reqAccountSummary snapshot for the configured account and maps its tags to typed balances and margins. It then reads one reqAccountUpdates snapshot for the same account and cancels that stream once IB signals the download end. Every raw tag and key from both snapshots lands in AccountState.info under its IB name, so values IB publishes only on updateAccountValue (for example PostExpirationExcess and PostExpirationMargin) are readable from Python alongside the summary tags such as TotalCashValue. A key reported once per currency keeps the last value IB sends.

Reconciliation

Mass status requests query three independent IB sources:

  • Open and completed orders produce order status reports.
  • Executions paired with commission reports produce fill reports.
  • Account positions produce position status reports.

Position updates do not create synthetic order status reports. If IB returns a position without matching order or fill history, the execution engine can adopt the position from the position report alone by creating its internal reconciliation fill. This preserves the report boundary: the adapter reports venue state, while the engine owns inferred state needed to reconcile its cache.

IB's position average cost includes commissions, while a position rebuilt from fills averages their prices. The adapter replays an instrument's fills, including the leg executions of combo orders, from the quantity held before the fill window. When the replay passes through flat or flips, the position report carries the average price of the fills after the last crossing, so a position held across a restart reconciles.

Fills that share a timestamp have no known execution order. If such a group mixes sides or flips, the entry price stays unknown until a later fill opens from flat or flips.

The replay infers the quantity held before the window, so a missing execution would change the result. The report carries the replayed entry price only when both conditions hold:

  • Every execution of the instrument was parsed.
  • The price reproduces IB's average cost.

For this check, the expected average cost is the entry price plus opening commissions per unit for a long. For a short, it is the entry price minus those commissions. A lot opened by a flip carries no commission.

Otherwise the report keeps IB's average cost, which the engine's reconciliation fill uses.

On connect, the execution client resolves the instrument of every open position in the account. It publishes any instrument absent from the cache. Thus, a position in a contract outside the provider's load_ids still recovers at startup instead of aborting the node.

For a pending-cancel order missing from the open-orders snapshot, the adapter checks execution history before emitting a canceled event. Replayed executions are deduplicated after terminal order state is evicted, including generated spread-leg fills.

Set track_option_exercise_from_position_update=True only when position changes should drive option exercise tracking. This setting does not restore synthetic position-derived order reports.

After a restart, orders a previous session left working return as open external orders. IB's PreSubmitted status, used for example while an order waits for its goodAfterTime, maps to ACCEPTED. The execution client resolves each restored order's IB order ID from its PERM- venue order ID and tracks it, so later IB status updates, fills, and cancels reach the owning strategy. Filled orders from the previous session reconcile from their real executions. The adapter reports no price for market-type orders, so reconciliation never infers a fill at price 0.

Replies to execution queries (reqExecutions) also arrive on IB's order update stream. The adapter treats only unsolicited execution details there as live fills, so startup and periodic execution queries do not apply the same fills again.

Symbology and instruments

InteractiveBrokersInstrumentProviderConfig.symbology_method selects one of two public methods:

MethodUse
SymbologyMethod.SIMPLIFIEDReadable IDs for normal instrument lookup and examples.
SymbologyMethod.RAWIDs that retain the IB security type for explicit lookup.

One symbology value built from this setting drives every mapping site in the adapter, so data, execution, and provider paths always resolve identical IDs. Raw symbology (AAPL=STK.SMART) is the lossless escape hatch: it preserves the IB local symbol and security type for instruments the simplified format rules cannot express, such as complex international listings.

Futures and futures-option IDs carry the local symbol reported by IB, such as YMM6.XCBT and YMM6 C45000.XCBT. The adapter does not rewrite the contract year, so identifiers stay stable across catalogs and caches.

The symbology method controls symbol conversion. Venue selection is a separate step with this precedence:

  1. CFD and commodity contracts use the adapter pseudo-venues IBCFD and IBCMDTY.
  2. A matching symbol_to_mic_venue prefix wins for other security types.
  3. Stock primary exchange and a compatible cached venue take precedence over SMART routing.
  4. Contract details can supply a non-SMART valid exchange.
  5. convert_exchange_to_mic_venue=True converts a known exchange to its MIC.
  6. The remaining IB exchange value becomes the venue.

The pseudo-venues are part of the adapter namespace under both symbology methods. For example, simplified symbology can produce IBDE30.IBCFD or XAUUSD.IBCMDTY, while raw symbology adds the security type to the symbol. These venues take precedence over symbol_to_mic_venue and convert_exchange_to_mic_venue. They do not describe a separate IB routing mechanism.

Use the same provider config for data and execution clients so both resolve identical IDs. Startup load_ids and load_contracts are required entries: client initialization fails if a configured instrument cannot be resolved.

Provider configuration

OptionDefaultPurpose
symbology_methodSIMPLIFIEDSelect simplified or raw symbol conversion.
load_idsEmptyLoad Nautilus instrument IDs at startup.
load_contractsEmptyLoad IB contract dictionaries at startup.
min_expiry_daysNoneMinimum relative expiry for chain loading.
max_expiry_daysNoneMaximum relative expiry for chain loading.
build_options_chainNoneOverride option chain construction.
build_futures_chainNoneOverride futures chain construction.
cache_validity_daysNoneLifetime of persisted instrument data.
convert_exchange_to_mic_venueFalseConvert known IB exchanges to MIC venues.
symbol_to_mic_venueEmptyOverride venues for matching symbol prefixes.
filter_sec_typesEmptyExclude selected IB security types.
filter_callableNoneApply a Python callable by fully qualified import path.
cache_pathNonePersist the instrument cache at the selected path.

Contract dictionaries use IB field names. Chain bounds are days from the request date:

from nautilus_trader.adapters import interactive_brokers as ib


provider_config = ib.InteractiveBrokersInstrumentProviderConfig(
    load_contracts=[
        {
            "secType": ib.IbSecurityType.STOCK.as_str(),
            "symbol": "SPY",
            "exchange": "SMART",
            "primaryExchange": "ARCA",
            "build_options_chain": True,
            "min_expiry_days": 7,
            "max_expiry_days": 45,
        },
        {
            "secType": ib.IbSecurityType.CONTINUOUS_FUTURE.as_str(),
            "symbol": "ES",
            "exchange": "CME",
            "build_futures_chain": True,
            "min_expiry_days": 30,
            "max_expiry_days": 180,
        },
    ],
)

Without a chain flag, CONTFUT represents IB's continuous future. IB limits continuous futures to historical data. They do not support live subscriptions or orders.

Generic spreads

Build spread IDs with new_generic_spread_id. Do not format their leg grammar by hand. All legs must use the same venue, and the ratio sign selects the IB leg action:

from nautilus_trader.model import new_generic_spread_id


spread_id = new_generic_spread_id(
    [
        (long_leg.id, 1),
        (short_leg.id, -1),
    ],
)

Load the leg instruments before requesting the spread. The provider qualifies each leg, constructs the IB BAG contract, and caches the resulting spread instrument before data subscription or order submission.

Spread executions come back from IB as a combo-level fill for the spread order and one execution per leg. Each leg execution becomes an OrderFilled event on the leg instrument under the spread order's strategy. It has a -LEG- client order ID. The execution engine applies it to the leg position without an order of its own. IB sends commission reports for the leg executions only, so the combo-level fill carries zero commission.

On connect, the execution client loads and publishes the spread and leg instruments of every open or completed combo order, so startup reconciliation restores those orders even when the node does not load the spread itself. Startup fill reports hold each combo order's combo-level fills. Its leg executions are left out, and the leg positions reconcile from IB's position reports.

Configuration reference

Data client

OptionDefaultPurpose
host127.0.0.1TWS or IB Gateway host.
port4002TWS or IB Gateway socket port.
client_id1IB API client ID.
use_regular_trading_hoursTrueRestrict requests to regular trading hours.
market_data_typeMarketDataType.REALTIMESelect real-time, frozen, delayed, or delayed-frozen data.
ignore_quote_tick_size_updatesFalseFilter quote changes that update only size.
connection_timeout300 secondsSet the socket connection timeout.
request_timeout60 secondsSet the IB request timeout.
handle_revised_barsFalsePublish every revision of an open bar instead of each completed bar once.
batch_quotesTruePrefer reqMktData for quote subscriptions.
all_last_tradesTrueInclude AllLast trades; set False to request Last trades only.
subscription_idle_timeout_secsNoneEmit a custom-data event after this many seconds without subscription data.
instrument_providerDefault provider configConfigure contract and instrument loading.
dockerized_gatewayNoneReserved and rejected; start the gateway separately.

With handle_revised_bars=False, a bar IB keeps up to date is published once it completes. IB revises the open bar every 5 seconds and sends its final values about half a second after the bar closes, so the bar is published when that update arrives. If none arrives, because the last 5 seconds had no trades, the bar is published 2 seconds after its close or on the next bar's first update, whichever comes first.

When subscription_idle_timeout_secs is set, each live subscription emits InteractiveBrokersSubscriptionIdle once per interval of inactivity. A new market-data update rearms the notification. Subscribe to DataType("InteractiveBrokersSubscriptionIdle") through the message bus to receive these events in on_data. Each event identifies the data client, instrument, subscription, timeout, and last local data receipt time. A quiet instrument or closed market can also trigger an event. Inactivity alone does not restart a subscription.

Execution client

OptionDefaultPurpose
host127.0.0.1TWS or IB Gateway host.
port4002TWS or IB Gateway socket port.
client_id1IB API client ID.
account_idNoneRaw IB account code such as DU123456.
connection_timeout300 secondsSet the socket connection timeout.
request_timeout60 secondsSet the IB request timeout.
fetch_all_open_ordersFalseRequest all open orders visible to the session.
track_option_exercise_from_position_updateFalseTrack option exercise through position updates.
instrument_providerDefault provider configConfigure contract and instrument loading.
dockerized_gatewayNoneReserved and rejected; start the gateway separately.

Dockerized gateway

OptionDefaultPurpose
usernameTWS_USERNAMESet the IB login username.
passwordTWS_PASSWORDSet the IB login password; debug output and serialization redact it.
trading_modeTradingMode.PAPERSelect paper or live login and port mapping.
read_only_apiTrueDisable order entry through the Gateway API.
timeout300 secondsBound startup readiness; valid values are 1 through 3600.
container_imageghcr.io/gnzsnz/ib-gateway:stableSelect the container image reference.
vnc_portNoneExpose VNC on a port from 5900 through 5999; None disables it.

DockerizedIBGateway exposes asynchronous and blocking start, safe_start, and stop methods, plus container_status. The safe start variants reuse a ready container and replace an unhealthy one.

Python enum reference

All public Python enum names use SCREAMING_SNAKE_CASE. IB conversion enums expose as_str() or as_i32() when callers need the corresponding wire value.

Connection, contracts, and instruments

EnumPurpose and key members
ContainerStatusGateway lifecycle: NO_CONTAINER, CONTAINER_CREATED, CONTAINER_STARTING, CONTAINER_STOPPED, NOT_LOGGED_IN, READY, or UNKNOWN.
MarketDataTypeSubscription mode: REALTIME, FROZEN, DELAYED, or DELAYED_FROZEN.
SymbologyMethodInstrument ID mapping: SIMPLIFIED or RAW.
TradingModeGateway login mode: PAPER or LIVE.
IbSecurityTypeIB contract types: stock, option, future, continuous future, index, futures option, FX, spread, warrant, bond, commodity, news, fund, crypto, and CFD.
IbOptionRightOption side: CALL or PUT.
IbBondIdentifierKindBond identifier: CUSIP or ISIN.
IbFundAssetTypeFund asset classification: none, other, money market, fixed income, multi-asset, equity, sector, guaranteed, or alternative.
IbFundDistributionPolicyIndicatorFund distribution policy: NONE, ACCUMULATION_FUND, or INCOME_FUND.

Market and historical data

EnumPurpose and key members
IbHistoricalBarSizeHistorical bar intervals from one second through one month.
IbHistoricalTickTypeHistorical ticks: TRADES or BID_ASK.
IbHistoricalWhatToShowHistorical source such as trades, midpoint, bid, ask, volatility, fee rate, schedule, or adjusted last.
IbRealtimeBarSizeIB real-time bar size; IB supports SEC5.
IbRealtimeWhatToShowReal-time bar source: TRADES, MIDPOINT, BID, or ASK.
IbTradingHoursRegular or extended trading hours.
IbTickTypeThe full IB numeric tick-field set, including live and delayed prices, sizes, option values, yields, NAVs, and volumes.

Orders and conditions

EnumPurpose and key members
IbActionOrder action and execution side: buy, sell, bought, sold, sell short, or sell long.
IbOrderTypeNative IB order types used by conversion and IBOrderTags; direct Nautilus support is limited to the order table above.
IbOrderStatusNative lifecycle status from API pending through submitted, pending cancel, canceled, filled, or inactive.
IbTimeInForceIB time in force values used for order conversion.
IbBuilderTimeInForceTime in force values accepted by IB order builders, including good-till-crossing and opening auction.
IbOrderOpenCloseOpen or close designation.
IbOrderOriginCustomer or firm origin.
IbShortSaleSlotNo short-sale slot, broker, or third party.
IbAuctionStrategyMatch, improvement, or transparent auction strategy.
IbAuctionTypeOpening, closing, or volatility auction.
IbReferencePriceTypeAverage of NBBO or NBBO.
IbVolatilityTypeDaily or annual volatility.
IbRule80AIB Rule 80A account and agency classifications.
IbOcaTypeNo OCA, cancel with block, reduce with block, or reduce without block.
IbTriggerMethodDefault, double bid/ask, last, double last, bid/ask, last or bid/ask, or midpoint.
IbLiquidityNone, added, removed, routed out, or explicitly unknown liquidity.
IbComboLegOpenCloseSame, open, close, or unknown combo-leg designation.
IbLegActionBuy or sell combo-leg action.
IbConditionKindPrice, time, margin, execution, volume, or percent-change condition.
IbConditionConjunctionAND or OR.
IbExerciseActionExercise or lapse an option.
IbTwapStrategyTypeMarketable, matching midpoint, matching same side, or matching last.
IbRiskAversionGet done, aggressive, neutral, or passive.
IbArticleTypeText or binary news article.

Test the adapter

For market data, examples/live/interactive_brokers/data_tester.py streams the configured instrument with the built-in DataTester actor, and the Rust equivalent runs with cargo run --example ib-data-tester --package nautilus-interactive-brokers --features examples. Both connect to a locally running TWS or IB Gateway and place no orders.

The Python examples construct offline by default. Their run flags separate connection from order submission. The Rust execution tester uses the same boundary:

# Construct the tester without connecting.
cargo run --example ib-exec-tester \
  --package nautilus-interactive-brokers \
  --features examples

# Connect in dry-run mode. This can subscribe but cannot submit tester orders.
NAUTILUS_IB_ACCOUNT_ID=DU123456 \
NAUTILUS_IB_RUN=1 \
cargo run --example ib-exec-tester \
  --package nautilus-interactive-brokers \
  --features examples

# Submit paper-account stop orders only after the second opt-in.
NAUTILUS_IB_ACCOUNT_ID=DU123456 \
NAUTILUS_IB_RUN=1 \
NAUTILUS_IB_LIVE_ORDERS=1 \
NAUTILUS_IB_EXEC_PROFILE=stop \
cargo run --example ib-exec-tester \
  --package nautilus-interactive-brokers \
  --features examples

Available execution profiles are lifecycle, cancel-modify, rejection, options, stop, stop-limit, trailing, bracket, and unsupported-flags. Run live tests only against an account and instruments intended for the selected profile.

Troubleshooting

  • Confirm TWS or IB Gateway is running, logged in, and configured for socket API access.
  • Confirm the port matches the application and trading mode.
  • Confirm no other process uses the same IB API client ID.
  • Confirm the account has permission for the requested market data type and instrument.
  • Run the ignored connection smoke explicitly when a paper session is available: cargo test -p nautilus-interactive-brokers --test connection -- --ignored.

For IB error codes, pacing, and connection settings, see the official TWS API reference.

On this page