How to loop through contractDetails to get option prices?

Discussion in 'Interactive Brokers' started by chami, Jun 4, 2020.

  1. chami

    chami

    I want to call contractDetails and feed the values from there ('right', 'lastTradeDateOrContractMonth', and 'strike') into tickPrice to get the option prices.

    How do I update the "contract" in the contractDetails function? Right now it tells me "contract is not defined".
    Which I understand why.

    But I don't know how to fix it.

    What does "contract" become? I've tried self.contract too which doesn't work either.

    Here is my code and I've bolded the part where I try to update "contract" in the function:

    from ibapi.client import EClient
    from ibapi.wrapper import EWrapper
    from ibapi.common import *
    from ibapi.contract import *
    import pandas as pd
    from threading import Timer

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

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

    def nextValidId(self, orderId):
    self.start()

    def contractDetails(self, reqId, contractDetails):

    contract.lastTradeDateOrContractMonth = contractDetails.realExpirationDate
    contract.strike = contractDetails.contract.strike
    contract.right = contractDetails.contract.right


    def tickPrice(self, reqId, tickType, price, attrib):
    if tickType == 4 and reqId == 1:
    print(price)

    def contractDetailsEnd(self, reqId):
    print("\ncontractDetails End\n")
    self.stop()

    def start(self):

    contract = Contract()
    contract.symbol = 'AAPL'
    contract.secType = 'OPT'
    contract.currency = 'USD'
    contract.exchange = 'SMART'
    contract.multiplier = '100'
    contract.lastTradeDateOrContractMonth = '20200619'
    contract.strike = '180'
    contract.right = 'C'

    self.reqContractDetails(1, contract)
    self.reqMktData(1, contract, '101', False, False, [])

    def stop(self):
    self.done=True
    self.disconnect()
    print('disconnect')

    def main():
    print('start')
    app = TestApp()
    app.nextOrderId = 0
    app.connect('127.0.0.1',7497,108)
    #Timer(4, app.stop).start()
    app.run()
    print('finish')
    if __name__ == "__main__":
    main()
     
  2. It could be that you are specifying too many contract parameters, and that IB's servers cannot find a contract which matches all these parameters. Maybe you could do a test run with only "AAPL OPT USD C" and see what you get back? From there you could further refine your search.

    Eidt: while doing this I would recommend that you don't call reqMktData() just yet. Enable this once you have found the correct set of contracts which you want to monitor.
     
  3. chami

    chami

    I tested it before to get the right parameters. it works if I set the parameters from the get go, but I want to loop through the different parameters from contractDetails
     
  4. gaussian

    gaussian

    Did you even attempt to investigate? Sure doesn't sound like it.

    It's a class.

    Code:
    dir(contractDetails)
    inside of a python terminal will list it's class members. Look at this list and find the things you need. Store the things you care about in a list and either call them directly or

    Code:
    attr_list = [] # attributes you care about
    
    for attr in attr_list:
        getattr(contractDetails, attr)
    You can also set the attributes in the same way using `setattr`.



    Next time fire up ipython and play with it.
     
  5. Your code is doing two things: reqContractDetails() and reqMktData(). You don't specify which one of these is resulting in the error message. The assumption I made in my reply is that it is the first action.
     
  6. chami

    chami

    How do I pass the attributes to tickPrice()?

    I don't think I explained myself well.
    I know which attributes I need, and how to get them. Right now I'm storing them in a dataframe.
    I just am not able to pass them from contractDetails() to tickPrice().

    I've tried nesting tickPrice() in contractDetails() but I can't set the attributes (e.g contract.strike = contractDetails.contract.strike) because I get an error "NameError: name 'contract' is not defined".

    I tried making contract a global variable but then I get error "Error: 1 321 Error validating request:-'bW' : cause - When the local symbol field is empty, please fill the following fields (right, strike, expiry)"...so it did not pass the attributes to "contract"

    I tried nesting reqMktData() in contractDetails too and I get error "Error: 2 322 Error processing request:-'bW' : cause - Duplicate ticker id" over and over, like for every loop of contractDetails.
    I thought I had to change self.reqMktData(1, contract2, '101', False, False, []) to self.reqMktData(2, contract2, '101', False, False, []).
    It stopped giving an error, but doesn't return anything for tickPrice(). Like it doesn't run it at all.
     
  7. chami

    chami

    Ok my bad.

    The error is that I'm not able to take the results from reqContractDetails() and use them as inputs for reqMktData()
     
  8. The answer is: "you don't". You have already specified a contract very specific before calling reqContractDetails(). As your contract is already that specific that it results in only one possible contract, you can use it directly to call reqMktData(). In this case is it not necessary to call reqContractDetails().
     
  9. chami

    chami

    I want to call reqContractDetails() to get many different option strikes and expiry dates. Then use those to get the option prices.
    So for e.g I pass everything except for strike, and right (call or put) for 2020 to reqContractDetails. It then returns a list of all the different options in 2020. I then want to call reqMktData to get the option price of every one of those options.

    I don't want one specific option from reqMktData(). I want the full option chain that is available from reqContractDetails().

    I want reqMktData() for AAPL at 180, 185, 190, 195 etc...for both calls and puts for multiple expiry dates.
     
  10. In that case you call reqContractDetails() with the contract parameters provided. contractDetails() will respond and you need to store all returned contracts in a list.
    Once you have that list you can loop over all stored contracts: call reqMktData(), collect the prices from tickPrice(), then cancelMktData(). Do this for every contract in the list.
     
    #10     Jun 6, 2020
    chami likes this.