5

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.

lukehawk
  • 1,423
  • 3
  • 22
  • 48
  • No idea about Python, but in the Java IB API functions like those are callbacks, they _get_ called, you don't call them, you write your code in them. Probably it's the same for the Python API. – SantiBailors Mar 22 '17 at 07:27
  • Thats what I was kinda figuring out, but how do you get the data into the ...terminal? Or back into the code? How do you grab the response? – lukehawk Mar 22 '17 at 13:54

4 Answers4

10

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()
Community
  • 1
  • 1
brian
  • 10,619
  • 4
  • 21
  • 79
  • Thanks!! This seems to work. I appreciate your simplifying the example code – lukehawk Mar 27 '17 at 12:20
  • How do I stop this thing? Ha. It seems to keep running... And I cannot.. request stuff while it is running. As I understand it, this TestApp inherits 'run' method which runs through all of the requests after `# here is where you start using api`. This sends off the requests, which start .. responding.. and continue to respond every 3 minutes with updated values. While this is running, I cannot seem to stop it. And I cannot seem to... add requests 'on the fly'. So, how does one do that? Or is this meant to be run and stopped, within the 'nextValidID' method? – lukehawk Mar 27 '17 at 18:15
  • When I run it, it disconnects after I receive an accountSummaryEnd event. That's what `self.disconnect` is for. There is no user interaction. – brian Mar 27 '17 at 19:38
  • I am an idiot. I had commented that out somehow. I fixed. Apologies. But, I did not realize how this works I guess. So it gets a bunch of messages every three minutes, the last of which will be a... 'closer'? Some line which tells me the current stream of messages is finished? And that will be interpreted by the source code to fire the object's 'accountSummaryEnd' method? Which does whatever I/you tell it to do there? I tried to add 'self.stop()' there to .. get back control of my console, but it throws an error. – lukehawk Mar 27 '17 at 19:49
  • I also have a follow up - I have several different accounts, with several different log in credentials. Will I have to restart IB Gateway under each account and run this to get the various account values? It looks like it is possible to run more than one Gateway at a time, so how do I control which gateway gets which request? – lukehawk Mar 27 '17 at 20:00
  • You have to use a different port for each gateway instance. – brian Mar 27 '17 at 21:28
  • Thank you. I spent 2 hours dealing with IB chat support trying to answer this. I thought this was the answer, but could not get them to confirm. UGH. Their support is the worst. – lukehawk Mar 28 '17 at 13:08
  • Sorry - final question. I thought you would set the port in the TWS application, but that does not appear to be the same port. How do you set the port in IBGateway? I see some configuration files, but do not see where the port is set in those files. – lukehawk Mar 28 '17 at 13:14
  • Click configure on the menu. It's in API->Settings. – brian Mar 28 '17 at 14:26
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/139278/discussion-between-brian-and-lukehawk). – brian Mar 28 '17 at 16:19
  • @brian I have a question about interactive brokers api. I need your help!!!!!! I want to retreive historical stock price from api, but it returns nothing... Here is the link of my question https://stackoverflow.com/questions/57491283/how-to-get-historical-stock-price-data-from-interactive-brokers-api Thank you very much! – Yuan Aug 14 '19 at 14:04
2

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)
0

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.

Maximus12793
  • 95
  • 2
  • 7
0

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()