使用 Python API 下载数据时如何消除(或从控制台抑制)Interactive Brokers 错误

How to eliminate (or suppress from console) Interactive Brokers error when downloading data with Python API

我编写了以下代码以从我在盈透证券的账户中读取信息:

# Interactive Brokers functions to import data

def read_positions(): #read all accounts positions and return DataFrame with information

    from ibapi.client import EClient 
    from ibapi.wrapper import EWrapper
    from ibapi.common import TickerId
    import pandas as pd

    class ib_class(EWrapper, EClient): 
        def __init__(self): 
            EClient.__init__(self, self)
            self.all_positions = pd.DataFrame([], columns = ['Account','Symbol', 'Quantity', 'Average Cost'])

        def position(self, account, contract, pos, avgCost):
            index = str(account)+str(contract.symbol)
            self.all_positions.loc[index]=account,contract.symbol,pos,avgCost

        def error(self, reqId:TickerId, errorCode:int, errorString:str):
            if reqId > -1:
                print("Error. Id: " , reqId, " Code: " , errorCode , " Msg: " , errorString)

        def positionEnd(self):
            super().positionEnd()
            self.disconnect()

    ib_api = ib_class() 
    ib_api.connect("127.0.0.1", 7496, 0) 
    ib_api.reqPositions()
    current_positions = ib_api.all_positions
    ib_api.run()

    return(current_positions)


def read_navs(): #read all accounts NAVs

    from ibapi.client import EClient 
    from ibapi.wrapper import EWrapper
    from ibapi.common import TickerId
    import pandas as pd

    class ib_class(EWrapper, EClient): 
        def __init__(self): 
            EClient.__init__(self, self)
            self.all_accounts = pd.DataFrame([], columns = ['reqId','Account', 'Tag', 'Value' , 'Currency'])

        def accountSummary(self, reqId, account, tag, value, currency):
            if tag == 'NetLiquidationByCurrency':
                index = str(account)
                self.all_accounts.loc[index]=reqId, account, tag, value, currency

        def error(self, reqId:TickerId, errorCode:int, errorString:str):
            if reqId > -1:
                print("Error. Id: " , reqId, " Code: " , errorCode , " Msg: " , errorString)

        def accountSummaryEnd(self, reqId:int):
                super().accountSummaryEnd(reqId)
                self.disconnect()

    ib_api = ib_class() 
    ib_api.connect("127.0.0.1", 7496, 0) 
    ib_api.reqAccountSummary(9001,"All","$LEDGER")
    current_nav = ib_api.all_accounts
    ib_api.run()

    return(current_nav)

如果我调用 read_positions()read_navs() 这两个函数,我会在 DataFrame 变量上得到我想要的结果。但是,我收到一条错误消息(在控制台上),内容为:

"OSError: [WinError 10038] An operation was attempted on something that is not a socket".

在错误消息本身之前,我收到了很多与错误相关的消息:

unhandled exception in EReader thread Traceback (most recent call last): File "C:\Users\xxxxx\Anaconda3\lib\site-packages\ibapi-9.76.1-py3.7.egg\ibapi\reader.py", line 34, in run data = self.conn.recvMsg() File "C:\Users\xxxxx\Anaconda3\lib\site-packages\ibapi-9.76.1-py3.7.egg\ibapi\connection.py", line 99, in recvMsg buf = self._recvAllMsg() File "C:\Users\xxxxx\Anaconda3\lib\site-packages\ibapi-9.76.1-py3.7.egg\ibapi\connection.py", line 119, in _recvAllMsg buf = self.socket.recv(4096)

IB 的服务台拒绝回答我的问题:我该如何避免或抑制此错误消息?我不知道这是我做错了什么,还是他们 API 上的错误。只要我能避免这些垃圾打印在我的控制台上,我就没事了。非常感谢任何指导。

我在 9.76.01 上遇到了类似的问题API,所以我回到了 9.74.01,没有这个问题。

我试图用 try/catch 块来抑制错误,但我从来没有让它起作用。

Matt 上面的回答是正确的:这是一个 API 错误!我添加此答案只是为了提供有关如何降级到旧版本的更清晰的步骤:

1) 从这里下载旧版本:http://interactivebrokers.github.io/downloads/TWS%20API%20Install%20974.01.msi

IB 不显示旧版本的 links,但他们将文件保留在 Github 上(注意 link 地址末尾的版本名称)

2) 卸载当前版本。在 IB 自己的网站上,执行以下操作:

  • 从 Windows
    中的 "Add/Remove Tool" 卸载 API 像往常一样控制面板
  • 删除 C:\TWS API\ 文件夹,如果仍有任何文件以防止版本不匹配。
  • 找到文件 "C:\Windows\SysWOW64\TwsSocketClient.dll"。删除这个文件。 [没有找到这个文件]
  • 在安装不同的 API 版本之前重新启动计算机。

3) 使用 .msi 文件安装 API

4) 运行 Anaconda 提示符并导航到目录 C:\TWS API\source\pythonclient

5) 运行: "python setup.py install"

6) python setup.py 安装后,重新启动 Spyder(如果它已打开;我在上面的第 5 步之前关闭了我的)

我安装这个旧版本后,错误消失了!

我能够消除错误,但我不确定此修复是否破坏了其他任何东西。也许对API代码有深入了解的人可以告诉我们这样是否可以。

在connection.py

    def _recvAllMsg(self):
    cont = True
    allbuf = b""

    while cont and self.socket is not None:
        try: #this line added
            buf = self.socket.recv(4096)
        except OSError: #this line added
            buf = b'' #this line added
        allbuf += buf
        logger.debug("len %d raw:%s|", len(buf), buf)

        if len(buf) < 4096:
            cont = False

    return allbuf

我终于找到了这个问题的答案:你可以看到下面的解决方案:

https://groups.io/g/twsapi/message/43333

它涉及快速更改 connection.py 文件并重新安装 TWS API。我之前在这里留下了答案,以防有人出于某种原因想要安装旧版本。

因此,我没有降级,而是找到了抑制错误消息的快速修复方法。转到它搞砸的脚本,它应该是 connection.py 并且在最底部的第 119 行。这就是我为捕获错误所做的工作并且它起作用了。

while cont and self.socket is not None:
            try:
                buf = self.socket.recv(4096)
                allbuf += buf
                logger.debug("len %d raw:%s|", len(buf), buf)

                if len(buf) < 4096:
                    cont = False
            except OSError:
                pass