Skip to content

IB Gateway Headless API Setup

Source: Notion | Last edited: 2023-08-09 | ID: 0d665745-541...


The Interactive Brokers API does not allow for a headless running of their Gateway program, which is used to access their API. Additionally, their web-based API vis OAuth is only available to institutional clients, which we are currently working on becoming. However, in the meantime, there is a workaround, which I describe here.

IBGA: https://heshiming.github.io/ibga/

It is possible via IBGA to run a docker container that handles all the login stuff so that IB Gateway can be run in a server environment. Simply follow instructions to install and run docker container, using the suggested docker-compose.yml file.

$ sudo docker pull heshiming/ibga

$ sudo docker-compose -f my-own-config.yml up

version: '2'
services:
my-ibga:
image: heshiming/ibga
restart: unless-stopped
environment:
- TERM=xterm
- IB_USERNAME= < username >
- IB_PASSWORD= < password >
- IB_REGION=America
- IB_TIMEZONE=America/New York
- IB_LOGINTAB=IB API
- IB_LOGINTYPE=Live Trading
- IB_LOGOFF=11:55 PM
- IB_APILOG=data
- IB_LOGLEVEL=Error
- IB_PREFER_IBKEY=true
volumes:
- ./run/program:/home/ibg
- ./run/settings:/home/ibg_settings
ports:
- "15800:5800"
- "4000:4000"

This will automatically install IB gateway (it took a long time to install on my computer, approximately 45 minutes).

The .yml file should contain login information for my IB account. There might be a request for 2-factor authentication, which I can approve on my phone’s IB app with a simple click (I’m not sure how often 2-factor will be requested… we will have to check).

Once everything is running, the following code can be used to fetch data (as an example). This code fetches several futures contracts 5-minute candles continuously and saves them to a SQLite database:

from ib_insync import IB, Contract
import time
import sqlite3
def connect_to_ib():
ib = IB()
ib.connect('127.0.0.1', 4000, clientId=0)
return ib
def get_last_5min_bar(ib, contract):
bars = ib.reqHistoricalData(
contract,
endDateTime='',
durationStr='1 D',
barSizeSetting='5 mins',
whatToShow='TRADES',
useRTH=False,
formatDate=1,
keepUpToDate=True)
if bars:
# Return the last 5-minute bar
return bars[-1]
else:
print(f"No bars received for {contract.symbol}.")
return None
def main():
ib = connect_to_ib()
# Connect to the SQLite database
conn = sqlite3.connect('futures_data.db')
cursor = conn.cursor()
symbols = [
('CL', 'NYMEX', 'USD'),
('JPY', 'CME', 'USD'),
('ZS', 'CBOT', 'USD'),
('ZW', 'CBOT', 'USD'),
('ZC', 'CBOT', 'USD'),
('GC', 'COMEX', 'USD'),
('ZN', 'CBOT', 'USD')
]
while True:
for symbol, exchange, currency in symbols:
contract = Contract(secType='FUT', symbol=symbol, exchange=exchange, currency=currency)
cds = ib.reqContractDetails(contract)
front_month_contract = min(cds, key=lambda cd: cd.contract.lastTradeDateOrContractMonth)
contract.lastTradeDateOrContractMonth = front_month_contract.contract.lastTradeDateOrContractMonth
bar = get_last_5min_bar(ib, contract)
if bar:
data = (bar.date, bar.open, bar.high, bar.low, bar.close, bar.volume, symbol, exchange, currency)
# Insert data to database
cursor.execute("""
INSERT INTO futures_bars (date, open, high, low, close, volume, symbol, exchange, currency)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
""", data)
print(f"Saved data for {symbol} on {bar.date} to the database")
# Commit changes to the database
conn.commit()
# Wait for 5 minutes
time.sleep(300)
# Close the database connection when done (though in this infinite loop this line won't be reached unless you break out of the loop)
conn.close()
if __name__ == "__main__":
# Create the database table if it doesn't exist
conn = sqlite3.connect('futures_data.db')
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS futures_bars (
id INTEGER PRIMARY KEY AUTOINCREMENT,
date TEXT NOT NULL,
open REAL NOT NULL,
high REAL NOT NULL,
low REAL NOT NULL,
close REAL NOT NULL,
volume INTEGER NOT NULL,
symbol TEXT NOT NULL,
exchange TEXT NOT NULL,
currency TEXT NOT NULL
)
""")
conn.commit()
conn.close()
main()

ChatGPT is relatively familiar with the Interactive Broker naming convention and its API.

Some symbols don’t return any data… I think this may be due to different expiry dates, they may have to be handled differently. Output:

Terminal window
Error 162, reqId 36: Historical Market Data Service error message:HMDS query returned no data: ZS AUG 23@CBOT Trades, contract: Contract(secType='FUT', symbol='ZS', lastTradeDateOrContractMonth='20230814', exchange='CBOT', currency='USD')
No bars received for ZS.
Saved data for ZW on 2023-08-08 19:45:00-05:00 to the database
Saved data for ZC on 2023-08-08 19:45:00-05:00 to the database
Error 162, reqId 42: Historical Market Data Service error message:HMDS query returned no data: GCQ3@COMEX Trades, contract: Contract(secType='FUT', symbol='GC', lastTradeDateOrContractMonth='20230829', exchange='COMEX', currency='USD')
No bars received for GC.
Saved data for ZN on 2023-08-08 19:45:00-05:00 to the database