Pearl
Pearl

Reputation: 452

How to obtain option chain data from Interactive Brokers TWS API

I am trying to build option chain data much like the major exchanges present it on their websites IE: Sort by expiration dates, then strike prices and display the bids/asks for the puts/calls etc.

I am trying to get the data but have only been able to obtain the expiry and strike prices.

I am using their ibapi library with TWS

I have tried using the reqSecDefOptParams() but keep receiving errors like: Error: 1 321 Error validating request.-'cB' : cause - Invalid security type -

Here is my code:

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


class OptionDataApp(EWrapper, EClient):
    def __init__(self):
        EClient.__init__(self, self)

    def error(self, reqId, errorCode, errorString):
        print("Error:", reqId, errorCode, errorString)

    def contractDetails(self, reqId, contractDetails):
        contract = contractDetails.contract
        print("Symbol:", contract.symbol)
        print("Expiry:", contract.lastTradeDateOrContractMonth)
        print("Strike Price:", contract.strike)
        self.request_option_chain(contract)

    def request_option_chain(self, contract):
        self.reqSecDefOptParams(
            1, contract.exchange, "", contract.tradingClass, contract.conId
        )

    def contractDetailsEnd(self, reqId):
        self.disconnect()


def main():
    app = OptionDataApp()
    app.connect("127.0.0.1", 7496, clientId=0)
    contract = Contract()
    contract.symbol = "AAPL"  # Specify the symbol for which you want option data
    contract.secType = "OPT"
    contract.exchange = "SMART"
    contract.currency = "USD"
    app.reqContractDetails(1, contract)
    app.run()
    

if __name__ == "__main__":
    main()

This codes prints what appears to be all the Expiry/Strike prices one after the other like this:

Symbol: AAPL
Expiry: 20230811
Strike Price: 105.0
Symbol: AAPL
Expiry: 20230811
Strike Price: 115.0

And then at the end(with a few mixed in the above data), many errors like this:

Error: 1 321 Error validating request.-'cB' : cause - Invalid security type -
Error: 1 321 Error validating request.-'cB' : cause - Invalid security type -
Error: 1 321 Error validating request.-'cB' : cause - Invalid security type -
Error: 1 321 Error validating request.-'cB' : cause - Invalid security type -

Any help would be appreciated, Thanks

Upvotes: 3

Views: 6146

Answers (2)

Juan_at_Austin
Juan_at_Austin

Reputation: 21

You have two main problems with your code. reqContractDetails can build the options chain if you leave it ambiguous (not fully specified) but is slow and throttled. You just need to save each received contract at contractDetails like:

def contractDetails(self, reqId, contractDetails):
    super().contractDetails(reqId, contractDetails)
    self.chain.append(contractDetails.contract)

of course you need to set chain = [] at some place like __init__ or reqContractDetails.

Now that you have the chain (list of contracts) you need to request the prices for each one and process them tick by tick.

reqSecDefOptParams is faster but then you have to loop to create the chain like:

for expiry in expirations:
    for strike in strikes:
        for right in ["C", "P"]:
            # create a contract object
            self.temp = Contract()
            self.temp.secType = 'OPT' # mandatory
            self.temp.exchange = exchange # mandatory
            self.temp.currency = 'USD'
            # either localSymbol
            #self.temp.localSymbol = f"{self.underlyingSymbol;<6}{expiry[-6:]}C{int(strike*1000):08d}")
            # or
            self.temp.symbol = self.underlyingSymbol
            self.temp.right = right
            self.temp.lastTradeDateOrContractMonth = expiry
            self.temp.strike = strike
            self.chain.append(self.temp)

inside securityDefinitionOptionParameter

Remember that this is all asynchronous, so if you call app.run() main will be blocked until app.disconnect()

You may want to put it in a thread.

Upvotes: 2

misantroop
misantroop

Reputation: 2563

You already obtained the option contract parameters (strike, expiry etc) and then you're running the same request again in request_option_chain which doesn't make sense.

As per the official API page: "IBApi::EClient::reqSecDefOptParams returns a list of expiries and a list of strike prices."

You're already getting this when making a reqContractDetails request.

Bids and asks are received via a call to request ticks, for example reqTickByTickData.

Upvotes: 1

Related Questions