python program that downloads options data using IBKR

447 views Asked by At

So I have written the following program:

from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract

import threading
import time


class IBapi(EWrapper, EClient):
    def __init__(self):
        EClient.__init__(self, self)
    def tickPrice(self, reqId, tickType, price, attrib):
        if tickType == 2 and reqId == 1:
            print('The current ask price is: ', price)

def run_loop():
    app.run()

app = IBapi()
app.connect('127.0.0.1', 7497, 123)

#Start the socket in a thread
api_thread = threading.Thread(target=run_loop, daemon=True)
api_thread.start()

time.sleep(1) #Sleep interval to allow time for connection to server

#Create contract object
contract = Contract()
contract.symbol = 'TSLA'
contract.secType = 'OPT'
contract.exchange = 'SMART'
contract.lastTradeDateOrContractMonth = '2023120'
contract.strike = 100
contract.right = 'C'
contract.multiplier = '100'


#Request Market Data
app.reqMktData(1, contract, '', False, False, [])

time.sleep(9) #Sleep interval to allow time for incoming price data
app.disconnect()

The output I get is

ERROR -1 2104 Market data farm connection is OK:usfarm.nj
ERROR -1 2104 Market data farm connection is OK:cashfarm
ERROR -1 2104 Market data farm connection is OK:usfarm
ERROR -1 2106 HMDS data farm connection is OK:ushmds
ERROR -1 2158 Sec-def data farm connection is OK:secdefnj

As you can see there is no price of the option, I looked at the interactive brokers API guide I changed the code a bit but still no price came

from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract

import threading
import time


class IBapi(EWrapper, EClient):
    def __init__(self):
        EClient.__init__(self, self)
    def tickOptionComputation(self, reqId, tickType, tickAttrib, impliedVol, delta, optPrice, pvDividend, gamma, vega, theta, undPrice):
             super().tickOptionComputation(reqId, tickType, tickAttrib, impliedVol, delta,
                                          optPrice, pvDividend, gamma, vega, theta, undPrice)
             print("TickOptionComputation. TickerId:", reqId, "TickType:", tickType, "TickAttrib:", (tickAttrib), "ImpliedVolatility:", (impliedVol), "Delta:", (delta), "OptionPrice:", (optPrice), "pvDividend:", (pvDividend), "Gamma: ", (gamma), "Vega:", (vega), "Theta:", (theta), "UnderlyingPrice:", (undPrice))

def run_loop():
    app.run()

app = IBapi()
app.connect('127.0.0.1', 7497, 123)

#Start the socket in a thread
api_thread = threading.Thread(target=run_loop, daemon=True)
api_thread.start()

time.sleep(1) #Sleep interval to allow time for connection to server

#Create contract object
contract = Contract()
contract.symbol = 'TSLA'
contract.secType = 'OPT'
contract.exchange = 'SMART'
contract.lastTradeDateOrContractMonth = '2023120'
contract.strike = 100
contract.right = 'C'
contract.multiplier = '100'


#Request Market Data
app.reqMktData(1, contract, '', False, False, [])

time.sleep(9) #Sleep interval to allow time for incoming price data
app.disconnect()

Output

ERROR -1 2104 Market data farm connection is OK:usfarm.nj
ERROR -1 2104 Market data farm connection is OK:cashfarm
ERROR -1 2104 Market data farm connection is OK:usfarm
ERROR -1 2106 HMDS data farm connection is OK:ushmds
ERROR -1 2158 Sec-def data farm connection is OK:secdefnj

I really don't know what I am getting wrong but it is probably in my calculation of the option price I have followed the API calculation guide ( https://interactivebrokers.github.io/tws-api/option_computations.html#opt_calculations) in the second edition of the code, So I still don't know.

I would appreciate it if someone could help me.

Thank you for your time!

I wanted to download options data using python from IBKR it didn't work

1

There are 1 answers

0
user11717481 On

There are some cases that use self.nextValidOrderId variable and before call app.run set app.nextorderId = None that should be defined by:

def nextValidId(self, orderId: int):
    super().nextValidId(orderId)
    self.nextorderId = orderId 

now after initialize api_thread

api_thread.start() 
while True:
    if isinstance(app.nextorderId, int):
        print('connected') 
        break
    else:
        print('waiting for connection')
        time.sleep(1)

it will print:

...
waiting for connection
ERROR -1 2104 Market data farm connection is OK:usfarm.nj
ERROR -1 2104 Market data farm connection is OK:cashfarm
ERROR -1 2104 Market data farm connection is OK:usfarm
ERROR -1 2106 HMDS data farm connection is OK:ushmds
ERROR -1 2158 Sec-def data farm connection is OK:secdefnj
...
...
...
connected

By this way i see that is used Order instances and app.placeOrder method, and maybe it is not what you desire. This script wraps tickOptionComputation and use multithreading to create a infinite loop to connect to the api, the difference to the above code is that you need to modify it to manage a while loop to print a connection status otherwise you also should check on Settings section for any improperly stablished feature that generates connection issues.

from ibapi import wrapper
from ibapi.client import EClient
from ibapi.utils import iswrapper
from ibapi.common import *
from ibapi.contract import *
from ibapi.ticktype import * 

import threading
import time

class myThread (threading.Thread):
   def __init__(self, app, threadId):
      threading.Thread.__init__(self)
      self.threadId = threadId
      self.app = app

   def run(self): 
      self.app.run() 

class TestApp(wrapper.EWrapper, EClient):
    def __init__(self):
        wrapper.EWrapper.__init__(self)
        EClient.__init__(self, wrapper=self) 
        self.nextValidOrderId = 0 

@iswrapper
def nextValidId(self, orderId:int): 
    print("setting nextValidOrderId:", orderId)
    self.nextValidOrderId = orderId  
    contract = Contract()
    contract.symbol = 'TSLA'
    contract.secType = 'OPT'
    contract.exchange = 'SMART'
    contract.lastTradeDateOrContractMonth = '2023120'
    contract.strike = 100
    contract.right = 'C'
    contract.multiplier = '100'
    self.reqMktData(1, contract, "", False, [])

@iswrapper
def error(self, reqId:TickerId, errorCode:int, errorString:str):
    print("Error. Id: " , reqId, " Code: " , errorCode , " Msg: " , errorString) 

@iswrapper 
def tickOptionComputation(self, reqId, tickType, tickAttrib, impliedVol, delta, optPrice, pvDividend, gamma, vega, theta, undPrice):
    super().tickOptionComputation(reqId, tickType, tickAttrib, impliedVol, delta,
                                  optPrice, pvDividend, gamma, vega, theta, undPrice)
    print("TickOptionComputation. TickerId:", reqId, "TickType:", tickType, "TickAttrib:", (tickAttrib), "ImpliedVolatility:", (impliedVol), "Delta:", (delta), "OptionPrice:", (optPrice), "pvDividend:", (pvDividend), "Gamma: ", (gamma), "Vega:", (vega), "Theta:", (theta), "UnderlyingPrice:", (undPrice)) 
app = TestApp()
app.connect("127.0.0.1", 7496, clientId=123)
print("serverVersion:%s connectionTime:%s" % (app.serverVersion(),
                                            app.twsConnectionTime()))

threadApp = myThread(app, 1) 
threadApp.start()  
  
time.sleep(9) #Sleep interval to allow time for incoming price data
app.disconnect()

additional info:

  • Warning messages code (2104, 2106, 2158)

    ... This is a notification and not a true error condition, and is expected on first establishing connection.

  • Tick Types