Interactive Brokers API (IBAPI) - Использование объекта threading.Timer для автоматического выхода при разрыве подключения к данным - PullRequest
1 голос
/ 17 июня 2020

Я пытался реализовать механизм, который запрашивает данные в реальном времени (например, reqRealTimeBars) и автоматически заставляет скрипт завершать работу в случае разрыва подключения к данным.

Я проводил тест с threading.Timer объект (https://docs.python.org/3/library/threading.html#timer -объекты ), который давал хорошие обещания в этом направлении: этот сценарий, например (ниже), является бесконечным l oop, как и Eclient.run(), но завершается через 3 секунды, как и ожидалось, с таймером

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)

Однако, когда я пытаюсь применить тот же logi c к собственно Eclient, это, похоже, не работает. Вот упрощенная версия моего кода. Logi c заключается в том, что таймер установлен с тайм-аутом 10 секунд (или любой продолжительностью, превышающей временной интервал 5 секунд между полосами реального времени) при запуске приложения. Затем каждый раз при получении нового бара таймер отменяется, а затем воссоздается с тем же таймаутом. Это означает, что обычно код никогда не достигнет тайм-аута, если соединение с сервером tws не будет разорвано.

Чтобы проверить код ниже: запустите tws, затем запустите этот скрипт. Он должен начать печатать данные в консоли. Затем вручную закройте файл tws. Это разорвет связь. Обычно после 10 секунд таймер, который не был «обновлен», должен запускать функцию exit и останавливать программу, как в примере выше. Однако он просто бездействует, все еще ожидая входящих данных. Если бы кто-нибудь мог взглянуть, это было бы здорово.

Я думаю, что этот метод может быть очень быстрым и хорошим способом сделать любое приложение для сбора данных в реальном времени надежным. Его нужно только соединить с заданием cron, которое запускает этот скрипт каждые x минут, а затем с некоторым дополнительным logi c в начале, которое предотвращает его запуск во второй раз, если он уже выполняется.

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

Обратите внимание, что я сделал пробу, в которой я бы установил тайм-аут на значение <5 с (например, 3 с) - в этом случае скрипт завершает работу по таймеру ... </p>

1 Ответ

0 голосов
/ 17 июня 2020

Это не совсем ответ на поставленный вопрос, но мета-ответ на мета-вопрос: используйте ib-insync и будьте счастливы.

...