Reputation: 1493
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
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
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
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
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