Bar data

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

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

Historical data

To get the earliest date of available bar data the "head timestamp" can be requested:

In [2]:
contract = Stock('TSLA', 'SMART', 'USD')

ib.reqHeadTimeStamp(contract, whatToShow='TRADES', useRTH=True)
Out[2]:
datetime.datetime(2010, 6, 29, 8, 0)

To request hourly data of the last 60 trading days:

In [3]:
bars = ib.reqHistoricalData(
        contract,
        endDateTime='',
        durationStr='60 D',
        barSizeSetting='1 hour',
        whatToShow='TRADES',
        useRTH=True,
        formatDate=1)
In [4]:
bars[0]
Out[4]:
BarData(date=datetime.datetime(2019, 10, 4, 15, 30), open=231.82, high=234.78, low=230.29, close=233.06, volume=12066, average=232.914, barCount=5981)

Convert the list of bars to a data frame and print the first and last rows:

In [5]:
df = util.df(bars)

display(df.head())
display(df.tail())
date open high low close volume average barCount
0 2019-10-04 15:30:00 231.82 234.78 230.29 233.06 12066 232.914 5981
1 2019-10-04 16:00:00 233.02 233.19 228.07 228.69 15847 229.846 7664
2 2019-10-04 17:00:00 228.62 230.87 228.30 230.56 8396 229.421 4324
3 2019-10-04 18:00:00 230.56 231.49 230.28 230.85 7069 230.899 3605
4 2019-10-04 19:00:00 230.84 231.48 230.04 231.00 3518 230.765 2125
date open high low close volume average barCount
409 2019-12-30 17:00:00 413.03 421.06 412.61 419.18 14920 416.886 8149
410 2019-12-30 18:00:00 419.18 420.45 417.32 418.65 7629 419.017 4769
411 2019-12-30 19:00:00 418.70 420.78 416.13 416.42 7476 418.900 3883
412 2019-12-30 20:00:00 416.41 416.78 413.51 414.90 6936 415.059 3700
413 2019-12-30 21:00:00 415.00 415.00 413.00 414.62 9204 414.130 5979

Instruct the notebook to draw plot graphics inline:

In [6]:
%matplotlib inline

Plot the close data

In [7]:
df.plot(y='close');

There is also a utility function to plot bars as a candlestick plot. It can accept either a DataFrame or a list of bars. Here it will print the last 100 bars:

In [8]:
util.barplot(bars[-100:], title=contract.symbol);

Historical data with realtime updates

A new feature of the API is to get live updates for historical bars. This is done by setting endDateTime to an empty string and the keepUpToDate parameter to True.

Let's get some bars with an keepUpToDate subscription:

In [9]:
contract = Forex('EURUSD')

bars = ib.reqHistoricalData(
        contract,
        endDateTime='',
        durationStr='900 S',
        barSizeSetting='10 secs',
        whatToShow='MIDPOINT',
        useRTH=True,
        formatDate=1,
        keepUpToDate=True)

Replot for every change of the last bar:

In [10]:
from IPython.display import display, clear_output
import matplotlib.pyplot as plt

def onBarUpdate(bars, hasNewBar):
    plt.close()
    plot = util.barplot(bars)
    clear_output(wait=True)
    display(plot)

bars.updateEvent += onBarUpdate

ib.sleep(10)
ib.cancelHistoricalData(bars)

Realtime bars

With reqRealTimeBars a subscription is started that sends a new bar every 5 seconds.

First we'll set up a event handler for bar updates:

In [11]:
def onBarUpdate(bars, hasNewBar):
    print(bars[-1])

Then do the real request and connect the event handler,

In [12]:
bars = ib.reqRealTimeBars(contract, 5, 'MIDPOINT', False)
bars.updateEvent += onBarUpdate

let it run for half a minute and then cancel the realtime bars.

In [13]:
ib.sleep(30)
ib.cancelRealTimeBars(bars)
Error 162, reqId 5: Historical Market Data Service error message:API historical data query cancelled: 5
RealTimeBar(time=datetime.datetime(2019, 12, 31, 12, 27, 5, tzinfo=datetime.timezone.utc), endTime=-1, open_=1.122925, high=1.122975, low=1.122925, close=1.122975, volume=-1, wap=-1.0, count=-1)
RealTimeBar(time=datetime.datetime(2019, 12, 31, 12, 27, 10, tzinfo=datetime.timezone.utc), endTime=-1, open_=1.122975, high=1.122975, low=1.122975, close=1.122975, volume=-1, wap=-1.0, count=-1)
RealTimeBar(time=datetime.datetime(2019, 12, 31, 12, 27, 15, tzinfo=datetime.timezone.utc), endTime=-1, open_=1.122975, high=1.122975, low=1.122975, close=1.122975, volume=-1, wap=-1.0, count=-1)
RealTimeBar(time=datetime.datetime(2019, 12, 31, 12, 27, 20, tzinfo=datetime.timezone.utc), endTime=-1, open_=1.122975, high=1.123025, low=1.122975, close=1.123025, volume=-1, wap=-1.0, count=-1)
RealTimeBar(time=datetime.datetime(2019, 12, 31, 12, 27, 25, tzinfo=datetime.timezone.utc), endTime=-1, open_=1.123025, high=1.123025, low=1.122975, close=1.122975, volume=-1, wap=-1.0, count=-1)
RealTimeBar(time=datetime.datetime(2019, 12, 31, 12, 27, 30, tzinfo=datetime.timezone.utc), endTime=-1, open_=1.122975, high=1.122975, low=1.122975, close=1.122975, volume=-1, wap=-1.0, count=-1)

The advantage of reqRealTimeBars is that it behaves more robust when the connection to the IB server farms is interrupted. After the connection is restored, the bars from during the network outage will be backfilled and the live bars will resume.

reqHistoricalData + keepUpToDate will, at the moment of writing, leave the whole API inoperable after a network interruption.

In [14]:
ib.disconnect()
In [ ]: