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:
- use IB Gateway instead of TWS (lighter, more stable)
- implement proper request queuing from day 1
- build redundant data feeds immediately
- 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