Skip to main content

interactive brokers api - 2 years deep review

been on IB for 2 years now.

primary broker for options and futures.

here’s what I’ve learned.

why IB
#

pros:

  • best API in the industry (fight me)
  • lowest commissions for volume
  • global market access
  • solid margin rates
  • professional platform

cons:

  • customer service is meh
  • TWS is bloated
  • API documentation is… interesting
  • learning curve is steep

the python setup
#

ib_insync is the library. nothing else comes close.

from ib_insync import IB, Stock, Option, Future
import asyncio

class IBConnectionManager:
    def __init__(self, host: str = '127.0.0.1', port: int = 7497,
                 client_id: int = 1):
        self.host = host
        self.port = port
        self.client_id = client_id
        self.ib = IB()
        self._connected = False

    async def connect(self) -> bool:
        """Establish connection to TWS/Gateway"""
        try:
            await self.ib.connectAsync(
                self.host, self.port, self.client_id
            )
            self._connected = True
            return True
        except Exception as e:
            print(f"Connection failed: {e}")
            return False

    async def get_option_chain(self, symbol: str,
                                expiry: str) -> list:
        """Fetch full options chain for symbol/expiry"""
        stock = Stock(symbol, 'SMART', 'USD')
        await self.ib.qualifyContractsAsync(stock)

        chains = await self.ib.reqSecDefOptParamsAsync(
            stock.symbol, '', stock.secType, stock.conId
        )

        if not chains:
            return []

        # get the chain for SMART exchange
        chain = next((c for c in chains if c.exchange == 'SMART'), chains[0])

        strikes = chain.strikes
        rights = ['C', 'P']

        contracts = []
        for strike in strikes:
            for right in rights:
                opt = Option(symbol, expiry, strike, right, 'SMART')
                contracts.append(opt)

        # qualify in batches
        qualified = []
        batch_size = 50
        for i in range(0, len(contracts), batch_size):
            batch = contracts[i:i + batch_size]
            result = await self.ib.qualifyContractsAsync(*batch)
            qualified.extend([c for c in result if c])

        return qualified

    async def place_option_order(self, contract, action: str,
                                  quantity: int, order_type: str = 'LMT',
                                  limit_price: float = None) -> dict:
        """Place options order with proper error handling"""
        from ib_insync import LimitOrder, MarketOrder

        if order_type == 'LMT' and limit_price:
            order = LimitOrder(action, quantity, limit_price)
        else:
            order = MarketOrder(action, quantity)

        trade = self.ib.placeOrder(contract, order)

        # wait for fill or timeout
        timeout = 30
        start = asyncio.get_event_loop().time()

        while trade.orderStatus.status not in ['Filled', 'Cancelled']:
            await asyncio.sleep(0.1)
            if asyncio.get_event_loop().time() - start > timeout:
                break

        return {
            'order_id': trade.order.orderId,
            'status': trade.orderStatus.status,
            'filled': trade.orderStatus.filled,
            'avg_price': trade.orderStatus.avgFillPrice,
            'remaining': trade.orderStatus.remaining
        }

commission reality
#

options: $0.65 per contract (no ticket charge)

futures: $0.85 per contract ES, $0.25 per micro

for my volume (500+ contracts/month): saves me $2k+ annually vs Tastyworks

the gotchas
#

1. pacing violations

IB rate limits requests. exceeded pacing = temporary ban.

solution: request queue with delays

import asyncio
from collections import deque

class RateLimiter:
    def __init__(self, requests_per_second: float = 45):
        self.delay = 1.0 / requests_per_second
        self.last_request = 0

    async def wait(self):
        now = asyncio.get_event_loop().time()
        elapsed = now - self.last_request
        if elapsed < self.delay:
            await asyncio.sleep(self.delay - elapsed)
        self.last_request = asyncio.get_event_loop().time()

2. market data farm disconnects

happens during high volatility. exactly when you need data most.

solution: redundant data sources (polygon backup)

3. order routing quirks

SMART routing isn’t always smart.

for SPX options, route to CBOE directly. for ES futures, route to CME.

what I’d change
#

if starting over:

  1. use IB Gateway instead of TWS (lighter, more stable)
  2. implement proper request queuing from day 1
  3. build redundant data feeds immediately
  4. test failure modes extensively before going live

community insights
#

there’s a solid thread on NexusFi about IB API gotchas that helped me avoid some pitfalls early on. worth reading if you’re starting out.

verdict
#

rating: 8.5/10

best API, steepest learning curve. worth it if you’re serious about automation.


2:34am wednesday. 2 years on interactive brokers. best API in the industry, lowest commissions at volume ($0.65/contract options), steep learning curve. key gotchas: pacing violations, data farm disconnects, routing quirks. use ib_insync library. run IB Gateway not TWS. build redundancy. 8.5/10 overall.

-AK

Related

tastyworks vs interactive brokers - python algo trader comparison 2025
been using both for 18 months. time for honest comparison. python automation perspective. my setup # tastyworks: options trading (premium selling).
kraken vs coinbase - crypto algo trading python API comparison 2025
been using both for 2 years. kraken for serious trading. coinbase for fiat onramp. time for comparison. my setup # kraken:
polygon.io vs alpha vantage - python algo data feeds comparison 2025
been using both for 2 years. polygon primary, alpha vantage backup. time for honest comparison. my setup # polygon.io:
backtrader vs vectorbt - python backtesting framework deep comparison
use both backtrader and vectorbt. here’s when to use each. quick verdict # backtrader: event-driven, realistic simulation, slower
thetadata review - options greeks data for algo trading
been using thetadata for 8 months now. here’s the real review for options algo traders. what is thetadata # options-focused market data provider.
vectorbt vs backtrader - python backtesting framework comparison 2025
been using both for 2+ years. here’s when to use each. quick verdict # vectorbt: fast parameter sweeps, simple strategies