Basics

Let's first take a look at what's inside the ib_insync package:

In [1]:
import ib_insync
print(ib_insync.__all__)
['util', 'Event', 'OrderComboLeg', 'OrderState', 'SoftDollarTier', 'PriceIncrement', 'Execution', 'CommissionReport', 'BarList', 'BarDataList', 'RealTimeBarList', 'BarData', 'RealTimeBar', 'HistogramData', 'NewsProvider', 'DepthMktDataDescription', 'ScannerSubscription', 'ScanDataList', 'FundamentalRatios', 'ExecutionFilter', 'PnL', 'PnLSingle', 'AccountValue', 'TickData', 'TickByTickAllLast', 'TickByTickBidAsk', 'TickByTickMidPoint', 'HistoricalTick', 'HistoricalTickBidAsk', 'HistoricalTickLast', 'TickAttrib', 'TickAttribBidAsk', 'TickAttribLast', 'MktDepthData', 'DOMLevel', 'TradeLogEntry', 'TagValue', 'FamilyCode', 'SmartComponent', 'PortfolioItem', 'Position', 'Fill', 'OptionComputation', 'OptionChain', 'Dividends', 'NewsArticle', 'HistoricalNews', 'NewsTick', 'NewsBulletin', 'ConnectionStats', 'Contract', 'Stock', 'Option', 'Future', 'ContFuture', 'Forex', 'Index', 'CFD', 'Commodity', 'Bond', 'FuturesOption', 'MutualFund', 'Warrant', 'Bag', 'ComboLeg', 'DeltaNeutralContract', 'ContractDetails', 'ContractDescription', 'ScanData', 'Trade', 'OrderStatus', 'Order', 'LimitOrder', 'MarketOrder', 'StopOrder', 'StopLimitOrder', 'BracketOrder', 'OrderCondition', 'ExecutionCondition', 'MarginCondition', 'TimeCondition', 'PriceCondition', 'PercentChangeCondition', 'VolumeCondition', 'Ticker', 'IB', 'Client', 'Wrapper', 'FlexReport', 'FlexError', 'IBC', 'IBController', 'Watchdog']

Importing

The following two lines are used at the top of all notebooks. The first line imports everything and the second starts an event loop to keep the notebook live updated:

In [2]:
from ib_insync import *
util.startLoop()

Note that startLoop() only works in notebooks, not in regular Python programs.

Connecting

The main player of the whole package is the "IB" class. Let's create an IB instance and connect to a running TWS/IBG application:

In [3]:
ib = IB()
ib.connect('127.0.0.1', 7497, clientId=10)
Out[3]:
<IB connected to 127.0.0.1:7497 clientId=10>

If the connection failed, then verify that the application has the API port enabled and double-check the hostname and port. For IB Gateway the default port is 4002. Make sure the clientId is not already in use.

If the connection succeeded, then ib will be synchronized with TWS/IBG. The "current state" is now available via methods such as ib.positions(), ib.trades(), ib.openTrades(), ib.accountValues() or ib.tickers(). Let's list the current positions:

In [4]:
ib.positions()
Out[4]:
[]

Or filter the account values to get the liquidation value:

In [5]:
[v for v in ib.accountValues() if v.tag == 'NetLiquidationByCurrency' and v.currency == 'BASE']
Out[5]:
[AccountValue(account='U172554', tag='NetLiquidationByCurrency', value='2039.4021', currency='BASE', modelCode='')]

The "current state" will automatically be kept in sync with TWS/IBG. So an order fill will be added as soon as it is reported, or account values will be updated as soon as they change in TWS.

Contracts

Contracts can be specified in different ways:

  • The ibapi way, by creating an empty Contract object and setting its attributes one by one;
  • By using Contract and giving the attributes as keyword argument;
  • By using the specialized Stock, Option, Future, Forex, Index, CFD, Commodity, Bond, FuturesOption, MutualFund or Warrant contracts.

Some examples:

In [6]:
Contract(conId=270639)
Stock('AMD', 'SMART', 'USD')
Stock('INTC', 'SMART', 'USD', primaryExchange='NASDAQ')
Forex('EURUSD')
CFD('IBUS30')
Future('ES', '20180921', 'GLOBEX')
Option('SPY', '20170721', 240, 'C', 'SMART')
Bond(secIdType='ISIN', secId='US03076KAA60');

Sending a request

The IB class has nearly all request methods that the IB API offers. The methods that return a result will block until finished and then return the result. Take for example reqContractDetails:

In [7]:
contract = Stock('TSLA', 'SMART', 'USD')
ib.reqContractDetails(contract)
Out[7]:
[ContractDetails(contract=Contract(secType='STK', conId=76792991, symbol='TSLA', exchange='SMART', primaryExchange='NASDAQ', currency='USD', localSymbol='TSLA', tradingClass='NMS', comboLegs=[]), marketName='NMS', minTick=0.01, orderTypes='ACTIVETIM,ADJUST,ALERT,ALGO,ALLOC,AON,AVGCOST,BASKET,BENCHPX,COND,CONDORDER,DARKONLY,DARKPOLL,DAY,DEACT,DEACTDIS,DEACTEOD,DIS,GAT,GTC,GTD,GTT,HID,IBKRATS,ICE,IMB,IOC,LIT,LMT,LOC,MIDPX,MIT,MKT,MOC,MTL,NGCOMB,NODARK,NONALGO,OCA,OPG,OPGREROUT,PEGBENCH,POSTONLY,PREOPGRTH,REL,RPI,RTH,SCALE,SCALEODD,SCALERST,SNAPMID,SNAPMKT,SNAPREL,STP,STPLMT,SWEEP,TRAIL,TRAILLIT,TRAILLMT,TRAILMIT,WHATIF', validExchanges='SMART,AMEX,NYSE,CBOE,PHLX,ISE,CHX,ARCA,ISLAND,DRCTEDGE,BEX,BATS,EDGEA,CSFBALGO,JEFFALGO,BYX,IEX,EDGX,FOXRIVER,TPLUS1,NYSENAT,PSX', priceMagnifier=1, underConId=0, longName='TESLA INC', contractMonth='', industry='Consumer, Cyclical', category='Auto Manufacturers', subcategory='Auto-Cars/Light Trucks', timeZoneId='EST (Eastern Standard Time)', tradingHours='20191231:0400-20191231:2000;20200101:CLOSED;20200102:0400-20200102:2000;20200103:0400-20200103:2000;20200104:CLOSED;20200105:CLOSED;20200106:0400-20200106:2000;20200107:0400-20200107:2000;20200108:0400-20200108:2000;20200109:0400-20200109:2000;20200110:0400-20200110:2000;20200111:CLOSED;20200112:CLOSED;20200113:0400-20200113:2000;20200114:0400-20200114:2000;20200115:0400-20200115:2000;20200116:0400-20200116:2000;20200117:0400-20200117:2000;20200118:CLOSED;20200119:CLOSED;20200120:0400-20200120:2000;20200121:0400-20200121:2000;20200122:0400-20200122:2000;20200123:0400-20200123:2000;20200124:0400-20200124:2000;20200125:CLOSED;20200126:CLOSED;20200127:0400-20200127:2000;20200128:0400-20200128:2000;20200129:0400-20200129:2000;20200130:0400-20200130:2000;20200131:0400-20200131:2000;20200201:CLOSED;20200202:CLOSED;20200203:0400-20200203:2000', liquidHours='20191231:0930-20191231:1600;20200101:CLOSED;20200102:0930-20200102:1600;20200103:0930-20200103:1600;20200104:CLOSED;20200105:CLOSED;20200106:0930-20200106:1600;20200107:0930-20200107:1600;20200108:0930-20200108:1600;20200109:0930-20200109:1600;20200110:0930-20200110:1600;20200111:CLOSED;20200112:CLOSED;20200113:0930-20200113:1600;20200114:0930-20200114:1600;20200115:0930-20200115:1600;20200116:0930-20200116:1600;20200117:0930-20200117:1600;20200118:CLOSED;20200119:CLOSED;20200120:0930-20200120:1600;20200121:0930-20200121:1600;20200122:0930-20200122:1600;20200123:0930-20200123:1600;20200124:0930-20200124:1600;20200125:CLOSED;20200126:CLOSED;20200127:0930-20200127:1600;20200128:0930-20200128:1600;20200129:0930-20200129:1600;20200130:0930-20200130:1600;20200131:0930-20200131:1600;20200201:CLOSED;20200202:CLOSED;20200203:0930-20200203:1600', evRule='', evMultiplier=0, mdSizeMultiplier=100, aggGroup=1, underSymbol='', underSecType='', marketRuleIds='26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26', secIdList=[], realExpirationDate='', lastTradeTime='', stockType='COMMON', cusip='', ratings='', descAppend='', bondType='', couponType='', callable=False, putable=False, coupon=0, convertible=False, maturity='', issueDate='', nextOptionDate='', nextOptionType='', nextOptionPartial=False, notes='')]

Current state vs request

Doing a request involves network traffic going up and down and can take considerable time. The current state on the other hand is always immediately available. So it is preferable to use the current state methods over requests. For example, use ib.openOrders() in preference over ib.reqOpenOrders(), or ib.positions() over ib.reqPositions(), etc:

In [8]:
%time l = ib.positions()
CPU times: user 5 µs, sys: 3 µs, total: 8 µs
Wall time: 9.06 µs
In [9]:
%time l = ib.reqPositions()
CPU times: user 0 ns, sys: 745 µs, total: 745 µs
Wall time: 32.7 ms

Logging

The following will put log messages of INFO and higher level under the current active cell:

In [10]:
util.logToConsole()

To see all debug messages (including network traffic):

In [11]:
import logging
util.logToConsole(logging.DEBUG)

Disconnecting

The following will disconnect ib and clear all its state:

In [12]:
ib.disconnect()
2019-12-31 13:28:29,252 ib_insync.ib INFO Disconnecting from 127.0.0.1:7497, 160 B sent in 9 messages, 21.0 kB received in 418 messages, session time 920 ms.
2019-12-31 13:28:29,255 ib_insync.client INFO Disconnecting