Options Chain Download from Interactive Brokers with Python

Options valuation seems more an art than a discipline.

I am trying at the moment to understand the differences in implied volatility among different strikes and expiry dates.

As a first step, I’ve decided to download the options chain from IB in order to analyze it.

Here it is the code I am going to use for this task.

This script will access the IB API and download to excel the option chain for the underlying
entered in the excel file
from ib.opt import ibConnection, message
from ib.ext.Contract import Contract
import quantacademy.excel_management as excel
import pandas as pd
from time import sleep
from collections import defaultdict
# Class IB_API
class IB_API:
This class will establish a connection to IB and group the different 
# Variables
d_ticker_reqId = {}
reqId = 1
d_opt_contracts = defaultdict(dict)
d_contracts = {}
# Functions
def __init__(self):
Connection to the IB API
print "Calling connection"
# Creation of Connection class
self.connection = ibConnection()
# Register data handlers
# Connect
def process_messages(self, msg):
Function that indicates how to process each different message
if msg.typeName == "contractDetails":
print msg
opt_contract = msg.values()[1]
elif msg.typeName == "tickPrice":
field = msg.values()[1]
price = msg.values()[2]
localSymbol = self.d_ticker_reqId[msg.values()[0]].m_localSymbol
if field == 1:
self.d_opt_contracts[localSymbol]['bid'] = str(price)
elif field == 2:
self.d_opt_contracts[localSymbol]['ask'] = str(price)
elif field == 9:
self.d_opt_contracts[localSymbol]['close'] = str(price)
elif msg.typeName == "tickOptionComputation":
localSymbol = self.d_ticker_reqId[msg.values()[0]].m_localSymbol
field = msg.values()[1]
price = msg.values()[2]
delta = msg.values()[3]
impliedVolatility = msg.values()[4]
optPrice = msg.values()[5]
pvDividend = msg.values()[6]
gamma = msg.values()[7]
vega = msg.values()[8]
theta = msg.values()[9]
undPrice = None
if field == 10:
self.d_opt_contracts[localSymbol]['bid_delta'] = str(delta)
self.d_opt_contracts[localSymbol]['bid_impliedVolatility'] = str(impliedVolatility)
self.d_opt_contracts[localSymbol]['bid_optPrice'] = str(optPrice)
self.d_opt_contracts[localSymbol]['bid_pvDividend'] = str(pvDividend)
self.d_opt_contracts[localSymbol]['bid_gamma'] = str(gamma)
self.d_opt_contracts[localSymbol]['bid_vega'] = str(vega)
self.d_opt_contracts[localSymbol]['bid_theta'] = str(theta)
self.d_opt_contracts[localSymbol]['bid_undPrice'] = str(undPrice)
elif field == 11:
self.d_opt_contracts[localSymbol]['ask_delta'] = str(delta)
self.d_opt_contracts[localSymbol]['ask_impliedVolatility'] = str(impliedVolatility)
self.d_opt_contracts[localSymbol]['ask_optPrice'] = str(optPrice)
self.d_opt_contracts[localSymbol]['ask_pvDividend'] = str(pvDividend)
self.d_opt_contracts[localSymbol]['ask_gamma'] = str(gamma)
self.d_opt_contracts[localSymbol]['ask_vega'] = str(vega)
self.d_opt_contracts[localSymbol]['ask_theta'] = str(theta)
self.d_opt_contracts[localSymbol]['ask_undPrice'] = str(undPrice)
elif field == 24:
self.d_opt_contracts[localSymbol]['iv'] = str(price)
print msg
def get_contract_details(self, reqId, contract_values):
Call for all the options contract for the underlying
print "Calling Contract Details"
# Contract creation
contract = Contract()
contract.m_symbol = contract_values['m_symbol']
contract.m_exchange = contract_values['m_exchange']
contract.m_secType = contract_values['m_secType']
# If expiry is empty it will download all available expiries
if contract_values['m_expiry'] <> "":
contract.m_expiry = contract_values['m_expiry']
self.connection.reqContractDetails(reqId, contract)
def get_market_data(self):
Call for all the options prices and greeks
print "Calling Market Data"
self.reqId = 1
# Loop through all options contracts
for option in self.d_contracts.values():
self.d_ticker_reqId[self.reqId] = option
self.connection.reqMktData(self.reqId, option, None, True)
self.reqId += 1
def save_option_contracts_to_dict(self, opt_contract):
It saves the options contracts downloaded as ContractDetails object
to a dictionary of dictionaries
It saves the options contracts downloaded as ContractDetails object
to a dictionary of contracts
self.d_contracts[opt_contract.m_summary.m_localSymbol] = Contract()
if __name__ == '__main__':
# Connection
ib = IB_API()
# Get contract details
filename = excel.select_excel_file()
xl = pd.ExcelFile(filename)
df_input = xl.parse('input')
#contract_values = {'m_symbol': 'TLT', 'm_exchange': 'SMART', 'm_secType': 'OPT', 
# 'm_expiry': '20140905'}
contract_values = {
'm_symbol': str(df_input['m_symbol'][0]),
'm_exchange': str(df_input['m_exchange'][0]),
'm_secType': str(df_input['m_secType'][0]),
'm_expiry': str(df_input['m_expiry'][0])
ib.get_contract_details(1, contract_values)
# Get Market values
print ib.d_opt_contracts
# Output
columns_after_hours = [
'm_conId', 'm_localSymbol', 'm_symbol', 'm_currency', 'm_exchange', 'm_secType', 'm_multiplier', 'm_right', 'm_strike', 
'm_expiry', 'close', 'bid', 'ask'
columns_open_market = [
'bid_impliedVolatility', 'ask_impliedVolatility', 'bid_delta', 'ask_delta', 
'bid_theta', 'ask_theta', 'bid_gamma', 'ask_gamma', 'bid_pvDividend', 'ask_pvDividend', 'bid_vega', 'ask_vega', 
'bid_optPrice', 'ask_optPrice', 'bid_undPrice', 'ask_undPrice' 
df_option_chain = pd.DataFrame(ib.d_opt_contracts)
df_option_chain = df_option_chain.T
# Check if market is open
if 'bid_impliedVolatility' in df_option_chain.columns:
df_option_chain = df_option_chain[columns_after_hours + columns_open_market]
df_option_chain = df_option_chain[columns_after_hours]
# Save in a new excel tab
excel.save_in_new_tab_of_excel(filename, df_option_chain, "option_chain")

15 Responses to Options Chain Download from Interactive Brokers with Python

  1. nick February 5, 2015 at 6:01 pm #


    thanks for posting the code. I am using C# but perhaps you can help me anyway. I am inside the contractDetails callback for getting an options chain. At this point I want to get the market data such as underlying price, implied volatility etc…

    BUT this opens up a ton of realtime connections … how can I fill out all of the data and manage these connections properly.

    Do you have to write some code to chunk it? I looked at your python code, but I’m not seeing how you are doing that there.. that is managing the connections.


    • alfil June 1, 2015 at 6:24 pm #

      Hi Nick,

      sorry for replying so late. I was very busy working in a project and I left this blog during it. I come back now.

      Hopefully you have already solved this issue. But just in case, I tell you how I managed it (if I have understood well the question).

      I first call the ContractDetails function, for getting the information of all options contracts. Then I wait for 20 seconds. You can see it in my get_contract_details function. After this time I must have received all contract data, so then it is when I require Market Data.

      The connection is always one, but I am making many requirements. Each one I send it with a different Id (reqId) and I store to which contract it belongs, so afterwards, when I receive the data I can link them.

      I don’t know if there is a better way, but this one works. Tell me if I can help you further or if you have found a better way of managing it.

      Thanks for writing,

  2. Petro August 18, 2015 at 7:43 pm #

    You can use this tool to download historical options data from Interactive Brokers. It lets you choose which options expiration and strikes you want to download and downloads them all in parallel.

  3. Matt November 28, 2015 at 5:12 pm #


    When I try to call:
    ib.get_contract_details(1, contract_values)

    I get the error:
    AttributeError: IB_API instance has no attribute ‘get_contract_details’

    Any ideas?



    • alfil November 29, 2015 at 11:31 am #

      Hi Matt,

      thanks for commenting. I am not using at this moment this code, IB might have change its API. It worked when I used it. I will check it again and tell you.


  4. Matt November 28, 2015 at 5:50 pm #


    I am also getting an error at:
    import quantacademy.excel_management as excel



  5. Roman January 26, 2016 at 8:00 am #

    Are you aware that posted code has no identation at all? In most cases is easy to add when reading the code, but there could be some ambiguities

    Nice effort BTW, I will test this IB connection this evening to see if I can use this code at my option analyzer code

    • alfil March 10, 2017 at 7:53 pm #

      Thank you Roman, you are right. I hadn’t realized.

  6. IBridgePy December 20, 2016 at 7:46 am #

    Interactive Brokers posted a recorded webiniar at youtube on Dec 13 2016 about IBridgePy, a flexiable and easy-to-use Python tool to trade at IB. It can handle option chains easily.

    • alfil March 10, 2017 at 7:53 pm #

      Thank you

  7. Harrison Delfino January 30, 2017 at 1:29 pm #

    I am using this. It works great for me.

    • alfil March 10, 2017 at 7:54 pm #

      Thanks a lot Harrison. I will test it.

      • Harrison Delfino April 18, 2017 at 11:23 am #

        My pleasure. Hope it helps. :)

  8. Harrison Delfino April 18, 2017 at 11:22 am #

    I had use MarketXLS. It works great for me.

Leave a Reply

Current day month ye@r *

Powered by WordPress. Designed by Woo Themes