pythonfinancequantitative-financeinteractive-brokerscomputational-finance

Setting variables to Interactive Brokers API responses in Python


I have some code where I request real time market data for a futures contract using the Interactive Brokers API and Python, in this case a VIX contract. I receive back a stream of data that prints via the patched up wrappers. This is using the actual Python API from IB, not a third party library.

What I would like to do is two fold: first, set a variable to the last price, which is tickType 4 in the response (13.0). Second, I would like to then stop streaming data for the current contract and request data for another contract (eg. the next expiry date, 20170816.) Otherwise, if I could request both sets of data simultaneously and set them each to a variable then stop streaming that would also be amazing. This is the code I have so far which makes a successful request from IB. Assuming the API is on and you have access to VIX futures market data (CFE exchange) the response is this:

from ibapi.wrapper import EWrapper
from ibapi.client import EClient
from ibapi.utils import iswrapper
from ibapi.common import *
from ibapi.contract import *
from ibapi.ticktype import *
# Request IB Data in less than 50 lines of code
class BasicApp(EWrapper, EClient):
  def __init__(self):
    EClient.__init__(self,self)

  def error(self, reqId: TickerId, errorCode:int, errorString:str):
    print('Error:', reqId, " ", errorCode, " ", errorString)

  @iswrapper
  def tickPrice(self, reqId: TickerId, tickType: TickType, price: float, attrib: TickAttrib):
    super().tickPrice(reqId, tickType, price, attrib)
    print("Tick Price. Ticker Id:", reqId, "tickType:", tickType, "Price:", price, "CanAutoExecute:", attrib.canAutoExecute, "PastLimit", attrib.pastLimit)

  @iswrapper
  def tickSize(self, reqId: TickerId, tickType: TickType, size: int):
    super().tickSize(reqId, tickType, size)
    print("Tick Size. Ticker Id:", reqId, "tickType:", tickType, "Size:", size)

  @iswrapper
  def tickString(self, reqId: TickerId, tickType: TickType, value: str):
    super().tickString(reqId, tickType, value)
    print("Tick string. Ticker Id:", reqId, "Type:", tickType, "Value:", value)

  @iswrapper
  def tickGeneric(self, reqId: TickerId, tickType: TickType, value: float):
    super().tickGeneric(reqId, tickType, value)
    print("Tick Generic. Ticker Id:", reqId, "tickType:", tickType, "Value:", value)

def main():
  app = BasicApp()
  app.connect("127.0.0.1", 4001, 0)
  contract = Contract();
  contract.symbol = "VIX";
  contract.secType = "FUT";
  contract.exchange = "CFE";
  contract.currency = "USD";
  contract.lastTradeDateOrContractMonth = "20170719";
  app.reqMktData(1001, contract, "", False, False, [])
  app.run()

if __name__ == '__main__':
  main()

This is the wrappers above printing the response from IB:

Error: -1   2119   Market data farm is connecting:usfuture.us
Error: -1   2104   Market data farm connection is OK:usfuture.us
Tick string. Ticker Id: 1001 Type: 45 Value: 1499398651
Tick Price. Ticker Id: 1001 tickType: 4 Price: 13.0 CanAutoExecute: False PastLimit False
Tick Size. Ticker Id: 1001 tickType: 5 Size: 1
Tick Size. Ticker Id: 1001 tickType: 5 Size: 1
Tick Size. Ticker Id: 1001 tickType: 8 Size: 3072
Tick Price. Ticker Id: 1001 tickType: 6 Price: 13.15 CanAutoExecute: False PastLimit False
Tick Price. Ticker Id: 1001 tickType: 7 Price: 12.95 CanAutoExecute: False PastLimit False
Tick Price. Ticker Id: 1001 tickType: 9 Price: 13.0 CanAutoExecute: False PastLimit False
Tick Price. Ticker Id: 1001 tickType: 14 Price: 12.3 CanAutoExecute: False PastLimit False
Tick Price. Ticker Id: 1001 tickType: 1 Price: 12.95 CanAutoExecute: True PastLimit False
Tick Size. Ticker Id: 1001 tickType: 0 Size: 140
Tick Price. Ticker Id: 1001 tickType: 2 Price: 13.0 CanAutoExecute: True PastLimit False
Tick Size. Ticker Id: 1001 tickType: 3 Size: 138
Tick Size. Ticker Id: 1001 tickType: 0 Size: 140
Tick Size. Ticker Id: 1001 tickType: 3 Size: 138

Solution

  • To stop streaming data for the current contract, call

    app.cancelMktData(tickerId); 
    

    For tickerId use the same value as in app.reqMktData (1001 in your example).

    Keeping the last price shouldn't be a problem. Insert

    lastPrice = price;
    

    in tickPrice method.

    You can receive market data for several instruments parallel by calling app.reqMktData with different tickerId. In this case lastprice can be stored in a collection, (e.g. a dictionary that uses the tickerId as key).