ib-async: Interactive Brokers API Wrapper
ib-async is an asynchronous and synchronous Python framework for the Interactive Brokers API, providing a user-friendly interface to TWS/Gateway for trading, market data, and account management. It is a fork/continuation of the popular ib_insync library. The current version is 2.1.0, with releases occurring semi-regularly, focusing on bug fixes and usability improvements.
Common errors
-
ModuleNotFoundError: No module named 'ib_async'
cause Attempting to import the library using its PyPI install name (`ib_async`) instead of its internal package name.fixChange your import statements from `from ib_async import ...` to `from ib_insync import ...`. -
ConnectionRefusedError: [Errno 111] Connection refused
cause The Python client could not establish a connection to the specified host and port. Usually, TWS/Gateway is not running, is running on a different port/host, or firewall is blocking the connection.fix1. Ensure TWS or IB Gateway is running. 2. Verify the host (e.g., '127.0.0.1') and port (e.g., 7497) in your `ib.connect()` call match your TWS/Gateway API settings. 3. Check your firewall settings to allow connections on the specified port. -
RuntimeError: Event loop is already running.
cause This typically occurs when you try to start an asyncio event loop (e.g., with `asyncio.run()` or `IB.run()`) when one is already active.fixEnsure you are calling `IB.run()` or `asyncio.run()` only once to start your main async function. If you are integrating `ib-async` into an existing async application, avoid starting a new loop; instead, schedule `ib-async` coroutines within the existing event loop. -
Historical data request error: Not a valid historical data subscription for contract...
cause The contract definition or historical data parameters are incorrect or not supported by IB for that specific security/exchange, or you lack the necessary market data subscriptions.fix1. Double-check your `Contract` definition (symbol, secType, exchange, currency). 2. Ensure your IB account has the required market data subscriptions. 3. Verify `whatToShow`, `barSizeSetting`, and `useRTH` parameters are valid for the given contract and time period. Use `ib.reqContractDetails(contract)` to get valid contract information.
Warnings
- gotcha The PyPI package name is `ib-async`, but the actual Python package to import is `ib_insync`.
- gotcha ib-async requires a running Interactive Brokers TWS (Trader Workstation) or IB Gateway instance to connect to. It does not connect directly to IB servers.
- breaking Between versions 1.x (original ib_insync) and 2.x (ib-async fork), there were significant internal changes and some API adjustments. For example, `util.startLoop()` is less commonly used, with `IB.run()` or direct `asyncio.run()` preferred for managing the event loop.
- gotcha Incorrectly mixing `asyncio.run()` with `IB.run()` or calling `IB.run()` multiple times in a single script can lead to `RuntimeError: Event loop is already running.`
Install
-
pip install ib-async
Imports
- IB
from ib_async import IB
from ib_insync import IB
- Contract
from ib_insync import Contract
- util
from ib_insync import util
Quickstart
from ib_insync import IB, Contract, util
import asyncio
async def main():
ib = IB()
try:
# Connect to TWS/Gateway. Default is localhost:7497 for TWS, 4002 for Gateway.
# Change host/port if TWS/Gateway is running elsewhere.
await ib.connect('127.0.0.1', 7497, clientId=1)
print("Connected to IB TWS/Gateway")
# Define a contract
contract = Contract(symbol='SPY', secType='STK', exchange='SMART', currency='USD')
# Request market data
# Ensure you have subscribed to market data for SPY in TWS/Gateway
# Data from reqMktData is real-time, consider historical data for backtesting
# for data in ib.reqMktData(contract):
# print(f"Time: {data.time}, Bid: {data.bid}, Ask: {data.ask}")
# Request historical data for the last 10 minutes
bars = await ib.reqHistoricalData(
contract,
endDateTime='',
durationStr='10 T',
barSizeSetting='1 min',
whatToShow='TRADES',
useRTH=True
)
if bars:
print(f"Retrieved {len(bars)} historical bars for {contract.symbol}")
for bar in bars:
print(f"Time: {bar.date}, Open: {bar.open}, Close: {bar.close}, Volume: {bar.volume}")
else:
print(f"No historical data found for {contract.symbol}")
except ConnectionRefusedError:
print("Connection refused. Is TWS/Gateway running and configured for API access?")
except Exception as e:
print(f"An error occurred: {e}")
finally:
if ib.isConnected():
ib.disconnect()
print("Disconnected from IB TWS/Gateway")
# ib-async recommends using IB.run() for managing the event loop for simpler cases
# or asyncio.run() for more complex applications.
# To run the async main function:
if __name__ == '__main__':
# Use IB.run() for simple script execution without manually managing asyncio loop
IB.run(main())
# Alternatively, for more control over the asyncio event loop:
# asyncio.run(main())