【问题标题】:How do I receive the data coming from IBs API in Python?如何在 Python 中接收来自 IBs API 的数据?
【发布时间】:2017-08-13 19:58:02
【问题描述】:

Interactive Brokers 刚刚发布了其 API 的 Python 版本。我正在尝试获取数据。

我正在使用“Program.py”中的“示例”,只是试图获取帐户值。我只想知道账户清算价值是多少,然后把它输入python。这是documentation. 这是创建和发送请求的代码:

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

我可以使用 IB 网关,查看正在发送的请求,以及返回到 IB 网关的响应。我无法弄清楚如何将响应输入 Python。如果我正确阅读文档,我会看到:

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)

我该怎么办?好像我调用这个函数来获取值,但是这个函数需要我想要返回的值作为输入!我错过了什么!??!

感谢任何人提供的任何帮助。

编辑:

这是我认为的“回调”:

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

这就是我感到困惑的地方。这似乎期望帐户的值(声明中的'value:str'),这正是我要求它产生的。我找不到像下面这样说的地方:

myMonies = whateverTheHellGetsTheValue(reqID)

因此,“myMonies”将保留帐户价值,我可以继续我的快乐之路。

【问题讨论】:

  • 不知道 Python,但在 Java IB API 中,像这些函数是回调,它们被调用,你不调用它们,你用它们编写代码。 Python API 可能也是如此。
  • 这就是我想知道的,但是您如何将数据输入...终端?还是回到代码中?您如何获取响应?

标签: python interactive-brokers ibpy


【解决方案1】:

我在这里回答了一个非常相似的问题。 https://stackoverflow.com/a/42868938/2855515

这是一个程序,我将EWrapperEClient 子类在同一个类中,并将其用于所有内容、请求和接收回调。

您调用 EClient 方法来请求数据,并通过 EWrapper 方法反馈。这些是带有@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()

【讨论】:

  • 谢谢!!这似乎有效。感谢您简化示例代码
  • 我该如何阻止这件事?哈。它似乎一直在运行......而且我不能......在它运行时请求东西。据我了解,这个TestApp 继承了运行# here is where you start using api 之后的所有请求的“运行”方法。这会发送请求,这些请求开始 .. 响应.. 并继续每 3 分钟响应一次更新值。虽然它正在运行,但我似乎无法阻止它。而且我似乎无法...“即时”添加请求。那么,如何做到这一点呢?或者这是否意味着在“nextValidID”方法中运行和停止?
  • 当我运行它时,它会在我收到 accountSummaryEnd 事件后断开连接。这就是self.disconnect 的用途。没有用户交互。
  • 我是个白痴。我已经以某种方式评论了这一点。我解决了。道歉。但是,我没有意识到我猜这是如何工作的。所以它每三分钟就会收到一堆消息,最后一个是......“更近”?某行告诉我当前的消息流已完成?这将由源代码解释以触发对象的“accountSummaryEnd”方法吗?我/你告诉它在那里做什么?我试图在那里添加“self.stop()”以..重新控制我的控制台,但它会引发错误。
  • 我还有一个跟进 - 我有几个不同的帐户,有几个不同的登录凭据。我是否必须在每个账户下重新启动 IB Gateway 并运行它来获取各种账户值?看起来一次可以运行多个网关,那么如何控制哪个网关获取哪个请求?
【解决方案2】:

致像我这样的其他新手:

请注意;我试图:

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

或者等待self.reqHistoricalData() 的返回。 正如上面提到的布赖恩; EClient 发送请求,EWrapper 接收回信息。

所以似乎试图处理 self.reqHistoricalData() 不会让你得到任何东西(我得到 None 类型)

但是将请求添加到

    @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, [])

足以让接收者 (EWrapper) 打印到控制台

2019 年 1 月 5 日更新: EWrapper 需要知道如何处理收到的消息。 为了让EWrapper 为您提供一个句柄,例如打印到控制台;代码的编写者必须在代码中指定装饰器语句,超出 "# here is where you start using api" 的行

例如: 如果代码中包含这个代码sn-p:

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

然后我们将打印到控制台。 如果包装装饰器方法被忽略,则没有打印到控制台。 比如这段代码:

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

【讨论】:

    【解决方案3】:

    所以在你的情况下寻找正确的回调。例如,如果您请求一个选项(即 testbed/contractOperations_req)。结果进入 contractDetails (@iswrapper),您可以在其中指定要执行的操作...也许 print(contractDetails.summary.symbol) 等。所以只需找到帐户信息的相应回调,然后打印/返回/等。它回到你的程序。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-08
      • 2013-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-14
      相关资源
      最近更新 更多