1

(sorry if the terminology/explanation isn't right) I want to print "My account balance in USD is: xxx". The purpose is to understand how to use the class method parameter (not sure if this is the right terminology) as a code input However, the result is: "My account balance in USD is: None". Account balance is printed but on a separate line.

from ibapi.wrapper import EWrapper  # handles incoming messages
from ibapi.contract import Contract
from ibapi.order import *

import threading
import time


class IBapi(EWrapper, EClient):
    def __init__(self):
        EClient.__init__(self, self)
        self.contract_details = {}
        self.bardata = {}  # initialise directory to store bar data
        self.USD_cash_balance = 0

    def nextValidId(self, orderId: int):
        super().nextValidId(orderId)
        self.nextorderId = orderId
        print('The next valid order id is: ', self.nextorderId)

    def accountSummary(self, reqId: int, account: str, tag: str, value: str,
                       currency: str):
        if tag == "CashBalance":
            print(value)
        IBapi.USD_cash_balance = value
        if reqId == 131:
            return value

def run_loop():
    app.run()  # starts communication with TWS


app = IBapi()
app.nextorderId = None
app.connect('127.0.0.1', 7497, 123)

# Start the socket in a thread
api_thread = threading.Thread(target=run_loop, daemon=True)  # Algo doesn't have "daemon=True"
api_thread.start()

# Check if the API is connected via orderid
while True:
    if isinstance(app.nextorderId,
                  int):  # the IB API sends out the next available order ID as soon as connection is made
        # The isinstance() function returns True if the specified object is of the specified type, otherwise False.
        print('connected')
        break
    else:
        print('waiting for connection')
        time.sleep(2)

print("My account balance in USD is: " + str(app.reqAccountSummary(131, "All", "$LEDGER:USD")))
  • `reqAccountSummary` takes 5 arguments, but you only pass in 3. Arg 4 is `value` which is what is returned, but since you pass in nothing, the return is `None` – match Dec 05 '21 at 09:37
  • @match The IB API replies are determined by the wrapper, not the request, argument count does not have to match. – misantroop Dec 05 '21 at 10:42
  • thanks for the explanation. I knew that what @match pointed out wasn't quite right, but didn't know the terminology to explain it – Bryce Turner Dec 05 '21 at 18:53

1 Answers1

1

First you don't assign USD_cash_balance to the class but the class instance (using self instead of class name). Secondly, you have to wait for a reply and there's many ways to do this. One is to wait for the value and sleep on it, you can extend it by implementing a timeout/retry if necessary. You can also use a Queue. Also, don't forget to disconnect your session when you're done.

from ibapi.client import EClient
from ibapi.wrapper import EWrapper  # handles incoming messages
from ibapi.contract import Contract
from ibapi.order import *

import threading
import time


class IBapi(EWrapper, EClient):
    def __init__(self):
        EClient.__init__(self, self)
        self.contract_details = {}
        self.bardata = {}  # initialise directory to store bar data
        self.USD_cash_balance = 0

    def nextValidId(self, orderId: int):
        super().nextValidId(orderId)
        self.nextorderId = orderId
        print('The next valid order id is: ', self.nextorderId)

    def accountSummary(self, reqId: int, account: str, tag: str, value: str,
                       currency: str):
        if tag == "CashBalance" and reqId == 131:
            self.USD_cash_balance = value

def run_loop():
    app.run()  # starts communication with TWS


app = IBapi()
app.nextorderId = None
app.connect('127.0.0.1', 7600, 123)

# Start the socket in a thread
api_thread = threading.Thread(target=run_loop, daemon=True)  # Algo doesn't have "daemon=True"
api_thread.start()

# Check if the API is connected via orderid
while True:
    if isinstance(app.nextorderId,
                  int):  # the IB API sends out the next available order ID as soon as connection is made
        # The isinstance() function returns True if the specified object is of the specified type, otherwise False.
        print('connected')
        break
    else:
        print('waiting for connection')
        time.sleep(2)

while not getattr(app, 'USD_cash_balance', None):
    app.reqAccountSummary(131, "All", "$LEDGER:USD")
    time.sleep(0.5)

print("My account balance in USD is: " + app.USD_cash_balance)

app.disconnect()
misantroop
  • 2,276
  • 1
  • 16
  • 24
  • thank you so much! this worked perfectly! spent hours searching, and I was totally stuck without your help. – Bryce Turner Dec 05 '21 at 18:55
  • 1
    Mark it as an accepted answer if you're satisfied with the solution. – misantroop Dec 06 '21 at 17:58
  • I am currently trying to get the python API to work but once I start the message loop, the app effectively locks out user input, remaining in execution state. I was about to log a question, but I saw your code here - what is this api_thread? Does that prevent lock out of further user input? – DISC-O May 17 '22 at 19:19