简体   繁体   中英

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

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, (eg a dictionary that uses the tickerId as key).

Goal 1: can be achieved as code below:

class BasicApp(EWrapper, EClient):
  def __init__(self):
    EClient.__init__(self,self)
    self.reqId_last_price_dict = {}  # This dictionary uses reqId as key, last price as value

  @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)
    self.reqId_last_price_dict[reqId] = price  # This line updates the dictionary value with the same reqId whenever a new price returned.

Goal 2:
IB allows 3 simultaneous market tick data requests if you subscribed to one of their live feeds as in their documents below:

Limitations Given the potentially high amount of data being sent, market depth request's are much more limited. Just as with historical data requests, the amount of active depth requests is related to the amount of market data lines, with a minimum of three and maximum of 60:

There is no technical difficulties, just request tick data for 3 contracts at the same time with 3 different reqIds. I also like to initialize a dictionary to store contract information for convenience when writing data into database, but don't forget to add the reqId and contract into the dictionary before requesting data.

class BasicApp(EWrapper, EClient):
  def __init__(self):
    EClient.__init__(self,self)
    self.reqId_last_price_dict = {}  # This dictionary uses reqId as key, last price as value
    self.reqId_contract_dict = {}  # This dictionary uses reqId as key, contract as value

  @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)
    self.reqId_last_price_dict[reqId] = price  # This line updates the dictionary value with the same reqId whenever a new price returned.
    print('last price for {} is {}.'.format(self.reqId_contract_dict[reqId].symbol, price))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM