[英]How do I receive the data coming from IBs API in Python?
Interactive Brokers just released a python version of their API.盈透证券刚刚发布了他们 API 的 Python 版本。 I am trying to get data.
我正在尝试获取数据。
I am using the 'examples' in 'Program.py', and just trying to get account values.我正在使用“Program.py”中的“示例”,只是试图获取帐户值。 I just want to know what the account liquidation value is, and get that into python.
我只想知道账户清算价值是多少,然后把它输入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.我可以使用 IB 网关,查看正在发送的请求,以及返回到 IB 网关的响应。 I cannot figure out how to get the response into Python.
我无法弄清楚如何将响应输入 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.
这似乎期望帐户的值(声明中的'value:str'),这正是我要求它产生的。 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.因此,“myMonies”将保留账户价值,我可以继续我的快乐之路。
I answered a very similar question here.我在这里回答了一个非常相似的问题。 https://stackoverflow.com/a/42868938/2855515
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.这是一个程序,我将
EWrapper
和EClient
子类在同一个类中,并将其用于所有内容、请求和接收回调。
You call EClient methods to request data and it is fed back through the EWrapper methods.您调用 EClient 方法来请求数据,并通过 EWrapper 方法反馈。 Those are the ones with the
@iswrapper
notation.这些是带有
@iswrapper
符号的那些。
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()
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()
.或者暂停
self.reqHistoricalData()
的返回。 As mentioned above by brian;正如上面提到的布赖恩;
EClient
sends requests and EWrapper
receives back the information. EClient
发送请求, EWrapper
接收回信息。
So it seems like trying to get a handle on self.reqHistoricalData()
wont get you anything (i get None
type)所以似乎试图处理
self.reqHistoricalData()
不会让你得到任何东西(我得到None
类型)
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足以让接收器(
EWrapper
)打印到控制台
Updated 2019-01-05: The EWrapper
needs to know what to do with received messages. 2019-01-05 更新:
EWrapper
需要知道如何处理收到的消息。 In order to allow EWrapper
to provide a handle for you to eg print to console;为了让
EWrapper
为您提供一个句柄,例如打印到控制台; the writer of the code must specify decorator statements into the code beyond the line that says "# here is where you start using api"
代码的编写者必须在代码中指定装饰器语句,超出
"# 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)
So in your case look for the correct callback.所以在你的情况下寻找正确的回调。 ex if you request an option (ie testbed/contractOperations_req ).
例如,如果您请求一个选项(即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.
结果进入contractDetails (@iswrapper),您可以在其中指定您想要做什么......也许是print(contractDetails.summary.symbol)等。所以只需找到帐户信息的相应回调,然后打印/返回/等。 it back to your program.
它回到你的程序。
This script (get-account.py) will return the value of the user's account "value" at the line of code:此脚本 (get-account.py) 将在以下代码行返回用户帐户“值”的值:
print(f"myfunds > {app.get_myfunds()}") 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).我将脚本部分的部分放在一个while循环“time.sleep(1)”中休眠,以便异步“EWrapper”回调方法有时间从IB的API返回响应(在继续下一行之前)。
The run_loop() is called from within a thread.从线程内调用 run_loop()。 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".
我尝试在没有多线程的情况下运行脚本,它只是挂起迫使我终止进程>“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()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.