Interactive Brokers ¶
Interactive Brokers (IB) is a trading platform that allows trading across a wide range of financial instruments, including stocks, options, futures, currencies, bonds, funds, and cryptocurrencies. NautilusTrader offers an adapter to integrate with IB using their Trader Workstation (TWS) API through their Python library, ibapi .
The TWS API serves as an interface to IB’s standalone trading applications: TWS and IB Gateway. Both can be downloaded from the IB website. If you haven’t installed TWS or IB Gateway yet, refer to the
Initial Setup
guide. In NautilusTrader, you’ll establish a connection to one of these applications via the
InteractiveBrokersClient
.
Alternatively, you can start with a dockerized version of the IB Gateway, which is particularly useful when deploying trading strategies on a hosted cloud platform. This requires having Docker installed on your machine, along with the docker Python package, which NautilusTrader conveniently includes as an extra package.
Note
The standalone TWS and IB Gateway applications require manually inputting username, password, and trading mode (live or paper) at startup. The dockerized version of the IB Gateway handles these steps programmatically.
Installation ¶
To install the latest nautilus-trader package along with the
ibapi
and optional
docker
dependencies using pip, execute:
pip install -U "nautilus_trader[ib,docker]"
For installation via poetry, use:
poetry add "nautilus_trader[ib,docker]"
Note
Because IB does not provide wheels for
ibapi
, NautilusTrader
repackages
it for release on PyPI.
Getting Started ¶
Before deploying strategies, ensure that TWS / IB Gateway is running. Launch one of the standalone applications and log in with your credentials, or start the dockerized IB Gateway using
InteractiveBrokersGateway
:
from nautilus_trader.adapters.interactive_brokers.gateway import InteractiveBrokersGateway
gateway_config = InteractiveBrokersGatewayConfig(
username="test",
password="test",
trading_mode="paper",
start=True
)
# This may take a short while to start up, especially the first time
gateway = InteractiveBrokersGateway(
config=gateway_config
)
# Confirm you are logged in
print(gateway.is_logged_in(gateway.container))
# Inspect the logs
print(gateway.container.logs())
Note
: To supply credentials to the Interactive Brokers Gateway, either pass the
username
and
password
to the config dictionaries, or set the following environment variables:
-
TWS_USERNAME
-
TWS_PASSWORD
Overview ¶
The adapter includes several major components:
-
InteractiveBrokersClient
- Executes TWS API requests usingibapi
. -
HistoricInteractiveBrokersClient
- Provides methods for retrieving instruments and historical data, useful for backtesting. -
InteractiveBrokersInstrumentProvider
- Retrieves or queries instruments for trading. -
InteractiveBrokersDataClient
- Connects to the Gateway for streaming market data. -
InteractiveBrokersExecutionClient
- Handles account information and executes trades.
The Interactive Brokers Client ¶
The
InteractiveBrokersClient
serves as the central component of the IB adapter, overseeing a range of critical functions. These include establishing and maintaining connections, handling API errors, executing trades, and gathering various types of data such as market data, contract/instrument data, and account details.
To ensure efficient management of these diverse responsibilities, the
InteractiveBrokersClient
is divided into several specialized mixin classes. This modular approach enhances manageability and clarity. The key subcomponents are:
-
InteractiveBrokersClientConnectionMixin
- This class is dedicated to managing the connection with TWS/Gateway. -
InteractiveBrokersClientErrorMixin
- It focuses on addressing all encountered errors and warnings. -
InteractiveBrokersClientAccountMixin
- Responsible for handling requests related to account information and positions. -
InteractiveBrokersClientContractMixin
- Handles retrieving contracts (instruments) data -
InteractiveBrokersClientMarketDataMixin
- Handles market data requests, subscriptions and data processing -
InteractiveBrokersClientOrderMixin
- Oversees all aspects of order placement and management.
Tip
To troubleshoot TWS API incoming message issues, consider starting at the
InteractiveBrokersClient._process_message
method, which acts as the primary gateway for processing all messages received from the API.
Instruments & Contracts ¶
In IB, a NautilusTrader
Instrument
is equivalent to a
Contract
. Contracts can be either a
basic contract
or a more
detailed
version (ContractDetails). The adapter models these using
IBContract
and
IBContractDetails
classes. The latter includes critical data like order types and trading hours, which are absent in the basic contract. As a result,
IBContractDetails
can be converted to an
Instrument
while
IBContract
cannot.
To search for contract information, use the IB Contract Information Center .
Examples of
IBContracts
:
from nautilus_trader.adapters.interactive_brokers.common import IBContract
# Stock
IBContract(secType='STK', exchange='SMART', primaryExchange='ARCA', symbol='SPY')
# Bond
IBContract(secType='BOND', secIdType='ISIN', secId='US03076KAA60')
# Option
IBContract(secType='STK', exchange='SMART', primaryExchange='ARCA', symbol='SPY', lastTradeDateOrContractMonth='20251219', build_options_chain=True)
# CFD
IBContract(secType='CFD', symbol='IBUS30')
# Future
IBContract(secType='CONTFUT', exchange='CME', symbol='ES', build_futures_chain=True)
# Forex
IBContract(secType='CASH', exchange='IDEALPRO', symbol='EUR', currency='GBP')
# Crypto
IBContract(secType='CRYPTO', symbol='ETH', exchange='PAXOS', currency='USD')
Historical Data & Backtesting ¶
When developing strategies with the IB adapter, the first step usually involves acquiring historical data for backtesting. The
HistoricInteractiveBrokersClient
offers methods to request and save this data.
Here’s an example of retrieving and saving instrument and bar data. A more comprehensive example is available here .
import datetime
from nautilus_trader.adapters.interactive_brokers.common import IBContract
from nautilus_trader.adapters.interactive_brokers.historic import HistoricInteractiveBrokersClient
from nautilus_trader.persistence.catalog import ParquetDataCatalog
async def main():
contract = IBContract(
secType="STK",
symbol="AAPL",
exchange="SMART",
primaryExchange="NASDAQ",
)
client = HistoricInteractiveBrokersClient()
instruments = await client.request_instruments(
contracts=[contract],
)
bars = await client.request_bars(
bar_specifications=["1-HOUR-LAST", "30-MINUTE-MID"],
end_date_time=datetime.datetime(2023, 11, 6, 16, 30),
tz_name="America/New_York",
duration="1 D",
contracts=[contract],
)
catalog = ParquetDataCatalog("./catalog")
catalog.write_data(instruments)
catalog.write_data(bars)
Live Trading ¶
Engaging in live or paper trading requires constructing and running a
TradingNode
. This node incorporates both
InteractiveBrokersDataClient
and
InteractiveBrokersExecutionClient
, which depend on the
InteractiveBrokersInstrumentProvider
to operate.
InstrumentProvider ¶
The
InteractiveBrokersInstrumentProvider
class functions as a bridge for accessing financial instrument data from IB. Configurable through
InteractiveBrokersInstrumentProviderConfig
, it allows for the customization of various instrument type parameters. Additionally, this provider offers specialized methods to build and retrieve the entire futures and options chains.
from nautilus_trader.adapters.interactive_brokers.config import InteractiveBrokersInstrumentProviderConfig
instrument_provider_config = InteractiveBrokersInstrumentProviderConfig(
build_futures_chain=False, # Set to True if fetching futures
build_options_chain=False, # Set to True if fetching options
min_expiry_days=10, # Relevant for futures/options with expiration
max_expiry_days=60, # Relevant for futures/options with expiration
load_ids=frozenset(
[
"EUR/USD.IDEALPRO",
"BTC/USD.PAXOS",
"SPY.ARCA",
"V.NYSE",
"YMH24.CBOT",
"CLZ27.NYMEX",
"ESZ27.CME",
],
),
load_contracts=frozenset(
[
IBContract(secType='STK', symbol='SPY', exchange='SMART', primaryExchange='ARCA'),
IBContract(secType='STK', symbol='AAPL', exchange='SMART', primaryExchange='NASDAQ')
]
),
)
Data Client ¶
InteractiveBrokersDataClient
interfaces with IB for streaming and retrieving market data. Upon connection, it configures the
market data type
and loads instruments based on the settings in
InteractiveBrokersInstrumentProviderConfig
. This client can subscribe to and unsubscribe from various market data types, including quote ticks, trade ticks, and bars.
Configurable through
InteractiveBrokersDataClientConfig
, it allows adjustments for handling revised bars, trading hours preferences, and market data types (e.g.,
IBMarketDataTypeEnum.REALTIME
or
IBMarketDataTypeEnum.DELAYED_FROZEN
).
from nautilus_trader.adapters.interactive_brokers.config import IBMarketDataTypeEnum
from nautilus_trader.adapters.interactive_brokers.config import InteractiveBrokersDataClientConfig
data_client_config = InteractiveBrokersDataClientConfig(
ibg_port=4002,
handle_revised_bars=False,
use_regular_trading_hours=True,
market_data_type=IBMarketDataTypeEnum.DELAYED_FROZEN, # Default is REALTIME if not set
instrument_provider=instrument_provider_config,
gateway=gateway_config,
)
Execution Client ¶
The
InteractiveBrokersExecutionClient
facilitates executing trades, accessing account information, and processing order and trade-related details. It encompasses a range of methods for order management, including reporting order statuses, placing new orders, and modifying or canceling existing ones. Additionally, it generates position reports, although fill reports are not yet implemented.
from nautilus_trader.adapters.interactive_brokers.config import InteractiveBrokersExecClientConfig
from nautilus_trader.config import RoutingConfig
exec_client_config = InteractiveBrokersExecClientConfig(
ibg_port=4002,
account_id="DU123456", # Must match the connected IB Gateway/TWS
gateway=gateway_config,
instrument_provider=instrument_provider_config,
routing=RoutingConfig(
default=True,
)
)
Full Configuration ¶
Setting up a complete trading environment typically involves configuring a
TradingNodeConfig
, which includes data and execution client configurations. Additional configurations are specified in
LiveDataEngineConfig
to accommodate IB-specific requirements. A
TradingNode
is then instantiated from these configurations, and factories for creating
InteractiveBrokersDataClient
and
InteractiveBrokersExecutionClient
are added. Finally, the node is built and run.
For a comprehensive example, refer to this script .
from nautilus_trader.adapters.interactive_brokers.common import IB_VENUE
from nautilus_trader.adapters.interactive_brokers.factories import InteractiveBrokersLiveDataClientFactory
from nautilus_trader.adapters.interactive_brokers.factories import InteractiveBrokersLiveExecClientFactory
from nautilus_trader.config import LiveDataEngineConfig
from nautilus_trader.config import LoggingConfig
from nautilus_trader.config import TradingNodeConfig
from nautilus_trader.live.node import TradingNode
# ... [continuing from prior example code] ...
# Configure the trading node
config_node = TradingNodeConfig(
trader_id="TESTER-001",
logging=LoggingConfig(log_level="INFO"),
data_clients={"IB": data_client_config},
exec_clients={"IB": exec_client_config},
data_engine=LiveDataEngineConfig(
time_bars_timestamp_on_close=False, # Use opening time as `ts_event`, as per IB standard
validate_data_sequence=True, # Discards bars received out of sequence
),
)
node = TradingNode(config=config_node)
node.add_data_client_factory("IB", InteractiveBrokersLiveDataClientFactory)
node.add_exec_client_factory("IB", InteractiveBrokersLiveExecClientFactory)
node.build()
node.portfolio.set_specific_venue(IB_VENUE)
if __name__ == "__main__":
try:
node.run()
finally:
# Stop and dispose of the node with SIGINT/CTRL+C
node.dispose()