循环中对 IB 的请求响应不同

request to IB responds differently when in a loop

我只是不明白这是怎么回事。我对包装器和 IB 有点陌生。这是我的函数,它覆盖并解析 XML。 XML 应该在 main 中解析吗?我只想获取 CSV 文件中所有交易品种的基本数据。当我注释掉循环和 运行 一个单独的请求时,它有时会起作用。这是怎么回事?

class TestApp(EWrapper, EClient):
    def __init__(self):
        EWrapper.__init__(self)
        EClient.__init__(self, wrapper=self)

        self.csv = pd.read_csv('getfund.csv');

        self.symbols = self.csv['Symbol']
        self.exchanges = self.csv['Exchange']

    def nextValidId(self, reqId: int):
        reqs_do()

    def reqs_do():

        for i in range(len(symbols)):
            contract = Contract()
            contract.symbol = self.symbols[i]
            contract.secType = "STK"
            contract.exchange = self.exchanges[i]
            contract.currency = "USD"
            contract.primaryExchange = "NASDAQ"

            print(contract)
            print(symbols[i])
            print(exchanges[i])
            print(i)

            app.reqFundamentalData(8001 , contract, "ReportsFinSummary", [])

    def error(self, reqID:TickerId, errorCode:int, errorString:str):
        print("Error: ", reqID, " " , errorCode, " ", errorString)

    def fundamentalData(self, reqId: TickerId, data: str):
        super().fundamentalData(reqId, data)
        print("FundamentalData. ", reqId, data)

        e = ET.fromstring(data)

        e.tag

        e.attrib

        ##code to parse the XML file returned from the ib reqfundamentaldata function.
        ##there are multiple report types and I am uncertain what they mean, worth
        ##looking into later.

        row_list = []
        for atype in e.iter('TotalRevenue'):
            if atype.attrib['reportType']=="A"  and atype.attrib['period']=="3M":
                dict1 = {"Date": atype.attrib['asofDate'], 
                                      'Revenue':atype.text}
                row_list.append(dict1)

        columns = ['Date', 'Revenue']
        tr = pd.DataFrame(row_list, columns=columns)


        row_list = []
        for atype in e.iter('DividendPerShare'):
            if atype.attrib['reportType']=="A" and atype.attrib['period']=="3M":
                dict1 = {"Date": atype.attrib['asofDate'],
                                      'Dividend':atype.text}
                row_list.append(dict1)

        columns = ['Date', 'Dividend']
        dps = pd.DataFrame(row_list, columns=columns)


        row_list = []
        for atype in e.iter('EPS'):
            if atype.attrib['reportType']=="A" and atype.attrib['period']=="3M":
                dict1 = {"Date": atype.attrib['asofDate'],
                                      'EPS':atype.text}
                row_list.append(dict1)

        columns = ['Date', 'EPS']
        eps = pd.DataFrame(row_list, columns=columns)

        temp = tr.merge(dps, left_on='Date', right_on='Date', how='left')
        fin = temp.merge(eps, left_on='Date', right_on='Date', how='left')

        print(fin)
        #fin.to_csv("fin.csv", sep=',')

        if done: app.disconnect()


def main():
    app = TestApp()
    app.connect("127.0.0.1", 4001, clientId=123)
    print("serverVersion:%s connectionTime:%s" % (app.serverVersion(),
                                                app.twsConnectionTime()))
    app.run()


if __name__ == "__main__":
    main()

您的逻辑是连接然后请求所有数据,同时在两次请求之间等待 60 秒....然后监听响应 (app.run)。

app.run() 启动一个从套接字读取响应的循环。没有一些线程,你不能在这个调用之后做任何事情。您可以编写程序以异步方式执行操作。

通过读取循环运行建立连接后,您就可以开始请求数据了。 nextValidId 用于此目的,因为它是 TWS(IBG) 发送的第一个响应。所以在 nextValidId 中你才真正开始你的程序。

您的代码永远不会断开连接,因为 app.run() 正在阻塞线程。您需要使用异步逻辑来决定何时断开连接。在这个简单的例子中,只需计算请求数。

不是真正的程序,只是为了说明逻辑流程。

class TestApp(EWrapper, EClient):
    def __init__(self):
        #other stuff
        #make the following members instead of global
        self.csv = pd.read_csv('getfund.csv');
        self.symbols = csv['Symbol']
        self.exchanges = csv['Exchange']

    def nextValidId(self, reqId: int):
        reqs_do()

    def reqs_do():
        for i in range(len(symbols)):
            # same, just use self.symbols etc..

    def fundamentalData(self, reqId: TickerId, data: str):
        # similar but disconnect after everything has been rec'd 
        if done: app.disconnect()

def main():
    app = TestApp()
    app.connect("127.0.0.1", 4001, clientId=123)
    app.run()

if __name__ == "__main__": main()
  • 该程序将首先创建 TestApp 并读取 csv 文件。
  • 然后您将通过套接字连接到 IB 网关,但不是 一直读到 app.run().
  • 一旦你开始阅读,你就会 rec'v nextValidId 和一些关于 联系。
  • 一旦接收到 nextValidiD,您就可以开始请求数据了。
  • 它可以随时来,但通常马上就来,也许星期五除外 一切都关闭的夜晚。
  • 如果收到,它将打印在您拥有的数据回调中。