简体   繁体   中英

Interactive Brokers API (IBAPI) - Using threading.Timer object to auto exit when the data connection is broken

I have been trying to implement a mechanism that request live data (such as reqRealTimeBars ) and automatically make the script to exit in case the data connection is broken.

I have been making test with the threading.Timer object ( https://docs.python.org/3/library/threading.html#timer-objects ), that was showing good promises in that direction: That script for instance (below) is an infinite loop just like the Eclient.run() , yet it quits after 3 seconds, as expected with the timer

import threading
import time
import sys
import _thread

def exit():
    _thread.interrupt_main()

if __name__ == '__main__':
    t = threading.Timer(3.0, exit)
    t.start()
    while True:
        time.sleep(3)

However, when I try to apply the same logic to the Eclient proper, it doesn't seem to work. Here below a simplified version of my code. The logic is that a timer is set with a timeout of 10s (or any duration superior to the 5s timespan between realtimebars) when the app is started. Then each time a new bar is received, the timer is canceled then recreated with the same timeout. This means that normally the code would never reach the timeout, unless the connection with the tws server is broken.

To test the code below: start he tws, then start this script. It should start printing the data in the console. Then, manually close the tws. That will break the connection. Normally after the 10s, the timer, that has not been "refreshed" should trigger the exit function and make the program stop, just like the example above. However, it just stays idle, still waiting for the incoming data. If anybody could have a look, that would be awesome.

I think this technique could be a very nimble and nice way to make any live data collection app robust. It only needs to be coupled with a cronjob that run that script every x minutes, and then some extra logic at the beginning that prevents it from being run a second time in case it is already doing so.

from ibapi.wrapper import EWrapper
from ibapi.client import EClient
from ibapi.contract import Contract
from datetime import timedelta, datetime as dt

import threading
import _thread


def exit():
    _thread.interrupt_main()


class App(EWrapper, EClient):

    def __init__(self):
        EWrapper.__init__(self)
        EClient.__init__(self, wrapper=self)
        self.timeout = threading.Timer(10.0, exit)
        self.timeout.start()


    def realtimeBar( self, reqId, datetime, open_, high, low, close, volume, wap, count):
        bar = {
                'open' : open_,
                'high' : high,
                'low' : low,
                'close' : close,
                'volume' : volume
                }
        print(bar)  
        self.refresh_timeout(reqId)


    def refresh_timeout(self, reqId):
        self.timeout.cancel()
        self.timeout = threading.Timer(10.0, exit)
        self.timeout.start()


def make_contracts(app):
    contract  = Contract()
    contract.__dict__.update({'symbol' : 'CL', 'exchange' : 'NYMEX', 'secType': 'FUT', 'lastTradeDateOrContractMonth' : '202008'})
    app.reqRealTimeBars(i, contract, 5, "TRADES", 0, [])


if __name__ == '__main__':
    app = App()
    app.connect("127.0.0.1", 4002, clientId=0)
    make_contracts(app)
    app.run()

Note that i have made a trial where i would set the timeout to a value < 5s (for instance 3s) - in this case the script does exit thx to the timer...

This is not really an answer to the question as stated, but the meta-answer to the meta question is: use ib-insync and be happy.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM