0

I am using the IB API to retrieve historical stock data, and I would like my code to run multiple times with different variables (different stocks and timeframes).

Currently I am using the following code:

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


def print_to_file(*args):
    with open('text6.txt', 'a') as fh:
        fh.write(' '.join(map(str,args)))
        fh.write('\n')
print = print_to_file


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


    Layout = "{!s:1} {!s:2} {!s:3} {!s:4} {!s:5} {!s:6} {!s:7} {!s:8} {!s:8} '\n'"
    print(Layout.format("Ticker;", "Date;", "None;", "Time;", "Open;", "High;", "Low;", "Close;", "Volume"))


    def historicalData(self, reqId, bar):
        print("AAPL", ";", bar.date.replace(' ', '; '), ";", bar.open, ";", bar.high, ";", bar.low, ";", bar.close, ";", bar.volume)


def main():
    app = TestApp()

    app.connect("127.0.0.1", 7497, 0)

    contract = Contract ()
    contract.symbol = "AAPL"
    contract.secType = "STK"
    contract.exchange = "SMART"
    contract.currency = "USD"
    contract.primaryExchange = "NASDAQ"

    app.reqHistoricalData(0, contract, "20180201 10:00:00", "1 M", "1 min", "TRADES", 0, 1, False, [])

    app.run()

if __name__ == "__main__":
    main()

I have tried the following for multiple stocks:

contract.symbol = ["AAPL", "GOOG"]

But this gives me the error message:

No security definition has been found for the request

And using the following code for time & date:

app.reqHistoricalData(0, contract, ["20180201 10:00:00", "20180301 10:00:00"], "1 M", "1 min", "TRADES", 0, 1, False, [])

Gives me the error message:

Error validating request:-'bP' : cause - Historical data query end date/time string [['20180201 10:00:00', '20180301 10:00:00']] is invalid.  Format is 'YYYYMMDD{SPACE}hh:mm:ss[{SPACE}TMZ]'.

Basically I would like this .py file to run multiple requests in a single run, using multiple variables so that I can receive data for multiple stocks in a single run.

Could anybody here help me to achieve this?

Thanks!

Hoogoo
  • 15
  • 1
  • 8

1 Answers1

0

You can create a class that derives from the Contract class in order to create multiple Contract objects at one time. Then, make a loop that passes your Contract objects into the client in order to get the data. What you are currently doing is pretty far off from any implementation that would actually work. Check out this blog for help with the set-up of a working system -> https://qoppac.blogspot.com/2017/03/interactive-brokers-native-python-api.html As far as the contract class, look at the relevant parameters in the documentation and create a class as necessary. Here is an example of my futures class:

class IBFutures(Contract):
    def __init__(self, symbol:str,  exchange:str, secType:str,
                 currency = 'USD', localSymbol = ""):
        Contract.__init__(self)

        self.symbol = symbol
        self.secType = secType
        self.exchange = exchange
        self.currency = currency
        self.localSymbol = localSymbol

Then, in your client object, make a function similar to this:

    def getHistoricalData(self, contracts, durationStr="3 D", barSizeSetting="30 mins", whatToShow = "TRADES"):
    """
    Returns historical prices for a contract, up to today
    ibcontract is a Contract
    :returns list of prices in 4 tuples: Open high low close volume
    """

    defaultid = 80
    prices = {}
    for symbol in contracts:
        defaultid += 1 # update defaultid

        # Make a place to store the data we're going to return
        historic_data_queue = finishableQueue(self.init_historicprices(defaultid))

        # Should endDateTime be set to 9:00AM EST??
        # Request some historical data. Native method in EClient
        self.reqHistoricalData(reqId=defaultid, contract = contracts[symbol],
            endDateTime=datetime.datetime.today().strftime("%Y%m%d %H:%M:%S"),
            durationStr=durationStr, barSizeSetting=barSizeSetting,
            whatToShow=whatToShow, useRTH=0, formatDate=1,
            keepUpToDate=False, chartOptions=[])

        # Wait until we get a completed data, an error, or time-out
        MAX_WAIT_SECONDS = 30
        logger.info("Getting %s historical data from the server..." % symbol)

        historic_data = historic_data_queue.get(timeout=MAX_WAIT_SECONDS)
        clean_data = cleanPrice(data=historic_data)
        prices[symbol] = clean_data

        if historic_data_queue.timed_out():
            logger.info("Exceeded maximum wait for wrapper to confirm finished")

        self.cancelHistoricalData(defaultid)

    logger.info("Prices retrieved for %d contracts" % len(prices))

    return prices
Jared Marks
  • 948
  • 8
  • 15
  • Thank you for your comment Jared, I have been able to find a lot of information about the subject and it's verry helpfull. Unfortunately I am really new to coding (this is the second thing I have done, the first thing was historical data from yahoo finance which was a lot easier :P) If I use your code I get the error message that "self" is not defined, and when I add your code to the client object, the client object stops working. With the code I am using now, i get the data that I want to receive and also in the right format, – Hoogoo May 09 '19 at 08:13
  • Unfortunately, you wont be able to copy/paste my code. It was just a template. I would take a look at the blog I referenced if you are still stuck. – Jared Marks May 10 '19 at 00:20
  • Thanks for the comment, I am still working on it but I think I will first try to let a main file call all the seperate scripts, I think that must work some way to. Thanks for the information you linked! – Hoogoo May 10 '19 at 12:04