lukehawk
lukehawk

Reputation: 1493

How do I receive the data coming from IBs API in Python?

Interactive Brokers just released a python version of their API. I am trying to get data.

I am using the 'examples' in 'Program.py', and just trying to get account values. I just want to know what the account liquidation value is, and get that into python. This is the documentation. And this is the code to create and send the request:

        app = TestApp()
        app.connect("127.0.0.1", 4001, clientId=0)
        print("serverVersion:%s connectionTime:%s" % (app.serverVersion(),
                                                   app.twsConnectionTime()))
        app.reqAccountSummary(9004, 'All', '$LEDGER')

I can use the IB Gateway, and see the request being sent, and the response coming back into IB Gateway. I cannot figure out how to get the response into Python. If I am reading the docs correctly, I see this:

Receiving

Summarised information is delivered via IBApi.EWrapper.accountSummary and IBApi.EWrapper.accountSummaryEnd

    1 class TestWrapper(wrapper.EWrapper):
...
    1     def accountSummary(self, reqId: int, account: str, tag: str, value: str,
    2                        currency: str):
    3         super().accountSummary(reqId, account, tag, value, currency)
    4         print("Acct Summary. ReqId:", reqId, "Acct:", account,
    5               "Tag: ", tag, "Value:", value, "Currency:", currency)
    6 
...
    1     def accountSummaryEnd(self, reqId: int):
    2         super().accountSummaryEnd(reqId)
    3         print("AccountSummaryEnd. Req Id: ", reqId)

What do I do with this? It seems like I call this function to get the values, but this function is requiring as an input the value I want returned! What am I missing!??!

Thanks for any help anyone can provide.

EDIT:

This is the 'callback' I think:

@iswrapper
# ! [accountsummary]
def accountSummary(self, reqId: int, account: str, tag: str, value: str,
                   currency: str):
    super().accountSummary(reqId, account, tag, value, currency)
    print("Acct Summary. ReqId:", reqId, "Acct:", account,
          "Tag: ", tag, "Value:", value, "Currency:", currency)

And this is where I am confused. This seems to expect a value for the account ('value: str' in the declaration), which is exactly what I am asking it to produce. I cannot find where I would say somehting like the following:

myMonies = whateverTheHellGetsTheValue(reqID)

So, 'myMonies' would then hold the account value, and I can continue on my merry way.

Upvotes: 6

Views: 5966

Answers (4)

ShavedBear
ShavedBear

Reputation: 1

This script (get-account.py) will return the value of the user's account "value" at the line of code:

print(f"myfunds > {app.get_myfunds()}")

... which could (of course) be assigned to a variable for further processing etc.

What's important here is that the account "value" is available within the procedural / scripted portion of the code as a method call to the app object.

I put sections of the scripted portion to sleep within a while loop "time.sleep(1)" to allow time for the asynchronous "EWrapper" callback methods to return a response from IB's API (before proceeding to the next line).

The run_loop() is called from within a thread. I'm fairly new at multi-threaded programming so I don't have any real insight as to why this works but it seems to be a key to the scripts successful execution. I tried running the script without multithreading and it just hung forcing me to kill the process > "kill -9 PID".

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

import threading
import time

class IBapi(EWrapper, EClient):

    def __init__(self):
        EClient.__init__(self, self)

    # Custom attributes
        self.myfunds = ''
        self.connection_status = False

    def get_myfunds(self):
        """ Custom getter method that returns current value of custom attribute self.myfunds. """
        return self.myfunds

    def get_connection_status(self):
        """ Custom getter method that returns current value of custom attribute self.connection_status. """
        return self.connection_status

    # @iswrapper
    def accountSummary(self, reqId:int, account:str, tag:str, value:str, currency:str):
        """ Returns the data from the TWS Account Window Summary tab in response to reqAccountSummary(). """
        # Update value of custom attribute self.myfunds
        self.myfunds = value

    # @iswrapper
    def accountSummaryEnd(self, reqId:int):
        """ This method is called once all account summary data for a given request are received. """
        self.done = True  # This ends the messages loop

    # @iswrapper
    def connectAck(self):
        """ Callback signifying completion of successful connection. """
        # Update value of custom attribute self.connection_status
        self.connection_status = True

def run_loop():
    app.run()

app = IBapi()

# IP: ipconfig /all > Ethernet adapter Ethernet > IPv4 Address
# Production port: 7496 | Sandbox (paper account) port: 7497
# Client ID: 123 (used to identify this script to the API, can be any unique positive integer).
app.connect('127.0.0.1', 7497, 123)

# Start the socket in a thread
api_thread = threading.Thread(target=run_loop, daemon=True)
api_thread.start()

while app.get_connection_status() == False:
    time.sleep(1) # Sleep interval to allow time for connection to server

print(f"Connection status > {app.get_connection_status()}")

app.reqAccountSummary(reqId = 2, groupName = "All", tags = "TotalCashValue")

while app.get_myfunds() == '':
    time.sleep(1) # Sleep interval to allow time for incoming data

if app.get_myfunds() != '':
    print(f"myfunds > {app.get_myfunds()}")

app.disconnect()

Upvotes: 0

captain vaseline
captain vaseline

Reputation: 21

To other newbies like me:

Note also; that i was trying to:

    print(self.reqHistoricalData(4102, ContractSamples.EurGbpFx(), queryTime,
                               "1 M", "1 day", "MIDPOINT", 1, 1, False, []))

or alternatively get a hold on the return of self.reqHistoricalData(). As mentioned above by brian; EClient sends requests and EWrapper receives back the information.

So it seems like trying to get a handle on self.reqHistoricalData() wont get you anything (i get None type)

However adding the request into

    @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")
        self.reqHistoricalData(4102, ContractSamples.EurGbpFx(), queryTime,
                               "1 M", "1 day", "MIDPOINT", 1, 1, False, [])

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

        self.reqHistoricalData(4103, contract, queryTime,
                               "1 M", "1 day", "MIDPOINT", 1, 1, False, [])

is enough to get the receiver (EWrapper) to print to console

Updated 2019-01-05: The EWrapper needs to know what to do with received messages. In order to allow EWrapper to provide a handle for you to e.g. print to console; the writer of the code must specify decorator statements into the code beyond the line that says "# here is where you start using api"

As an example: if the code includes this code snippet:

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

        queryTime = (datetime.datetime.today() - datetime.timedelta(days=5)).strftime("%Y%m%d %H:%M:%S")        
        self.reqHistoricalData(4102, ContractSamples.EurGbpFx(), queryTime,
                        "1 M", "1 day", "MIDPOINT", 1, 1, False, [])

    @iswrapper
    def historicalData(self, reqId:int, bar: BarData):
        print("HistoricalData. ReqId:", reqId, "BarData.", bar)

then we will get a print to console. if the the wrapper decorator method is neglected, then there is no print to console. such as in this code:

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

        queryTime = (datetime.datetime.today() - datetime.timedelta(days=5)).strftime("%Y%m%d %H:%M:%S")        
        self.reqHistoricalData(4102, ContractSamples.EurGbpFx(), queryTime,
                        "1 M", "1 day", "MIDPOINT", 1, 1, False, [])

    #@iswrapper
    #def historicalData(self, reqId:int, bar: BarData):
    #    print("HistoricalData. ReqId:", reqId, "BarData.", bar)

Upvotes: 2

brian
brian

Reputation: 10969

I answered a very similar question here. https://stackoverflow.com/a/42868938/2855515

Here is a program where I subclass the EWrapper and EClient in the same class and use that for everything, requests and receiving callbacks.

You call EClient methods to request data and it is fed back through the EWrapper methods. Those are the ones with the @iswrapper notation.

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

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)

    @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", 7497, clientId=123)
    app.run()

if __name__ == "__main__":
    main()

Upvotes: 11

Maximus12793
Maximus12793

Reputation: 95

So in your case look for the correct callback. ex if you request an option (i.e. testbed/contractOperations_req). The result goes into contractDetails (@iswrapper) where you can specify what you want to do... maybe print(contractDetails.summary.symbol) etc. So just find the respective callback for the account info and then print/return/etc. it back to your program.

Upvotes: 0

Related Questions