4

New to Python and IB API and stuck on this simple thing. This application works correctly and prints IB server reply. However, I cannot figure out how to get this data into a panda's dataframe or any other variable for that matter. How do you "get the data out?" Thanks!

Nothing on forums, documentation or youtube that I can find with a useful example. I think the answer must be to return accountSummary to pd.Series, but no idea how.

Expected output would be a data series or variable that can be manipulated outside of the application.

from ibapi import wrapper
from ibapi.client import EClient
from ibapi.utils import iswrapper #just for decorator
from ibapi.common import *
import pandas as pd

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

    @iswrapper
    def nextValidId(self, orderId:int):
        print("setting nextValidOrderId: %d", orderId)
        self.nextValidOrderId = orderId
        # here is where you start using api
        self.reqAccountSummary(9002, "All", "$LEDGER")

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

    @iswrapper
    def accountSummary(self, reqId:int, account:str, tag:str, value:str, currency:str):
        print("Acct Summary. ReqId:" , reqId , "Acct:", account, 
            "Tag: ", tag, "Value:", value, "Currency:", currency)
    #IB API data returns here, how to pass it to a variable or pd.series

    @iswrapper
    def accountSummaryEnd(self, reqId:int):
        print("AccountSummaryEnd. Req Id: ", reqId)
        # now we can disconnect
        self.disconnect()

def main():
    app = TestApp()
    app.connect("127.0.0.1", 4001, clientId=123)
    test = app.accountSummary
    app.run()

if __name__ == "__main__":
    main()
trderjoe
  • 41
  • 3

2 Answers2

2

Hi had the same problem and collections did it for me. Here is my code for CFDs data. Maybe it will help somebody. You will have your data in app.df. Any suggestion for improvement are more than welcome.

import collections
import datetime as dt
from threading import Timer
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
import pandas as pd

# get yesterday and put it to correct format yyyymmdd{space}{space}hh:mm:dd
yesterday = str(dt.datetime.today() - dt.timedelta(1))
yesterday = yesterday.replace('-','')

IP = '127.0.0.1'
PORT = 7497

class App(EClient, EWrapper):

    def __init__(self):
        super().__init__(self)
        self.data = collections.defaultdict(list)
    
    def error(self, reqId, errorCode, errorString):
        print(f'Error {reqId}, {errorCode}, {errorString}')
    
    def historicalData(self, reqId, bar):
        self.data['date'].append(bar.date)
        self.data['open'].append(bar.open)
        self.data['high'].append(bar.high)
        self.data['low'].append(bar.low)
        self.data['close'].append(bar.close)
        self.data['volume'].append(bar.volume)
        self.df = pd.DataFrame.from_dict(self.data)

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

# create App object
app = App()
print('App created...')
app.connect(IP, PORT, 0)
print('App connected...')

# create contract
contract = Contract()
contract.symbol = 'IBDE30'
contract.secType = 'CFD' 
contract.exchange = 'SMART' 
contract.currency = 'EUR' 
print('Contract created...')

# request historical data for contract
app.reqHistoricalData(reqId=1, 
                    contract=contract, 
                    endDateTime=yesterday,
                    durationStr='1 W',  
                    barSizeSetting='15 mins', 
                    whatToShow='ASK', 
                    useRTH=0, 
                    formatDate=1, 
                    keepUpToDate=False, 
                    chartOptions=[])

Timer(4, app.stop).start()
app.run()
Qwido
  • 21
  • 3
1

I'd store the data to a dictionary, create a dataframe from the dictionary, and append the new dataframe to the main dataframe using the concat function. Here's an example:

def accountSummary(self, reqId:int, account:str, tag:str, value:str, currency:str):
    acct_dict = {"account": account, "value": value, "currency": currency}
    acct_df = pd.DataFrame([acct_dict], columns=acct_dict.keys())
    main_df = pd.concat([main_df, acct_df], axis=0).reset_index()

For more information, you might like Algorithmic Trading with Interactive Brokers

MatthewScarpino
  • 5,672
  • 5
  • 33
  • 47
  • Matt, Could you please clarify? Your solution seems to throw an error because, I think, the api is asynchronous. The only thing I have seen since to get the data out of the thread is a queue.Queue, but I'm only able to get out the last item in a queue. Thanks for your response though. I don't see queues covered in your book, but will keep it in mind for future reference. – trderjoe Sep 07 '19 at 12:04