Tinkoff / invest-python

Tinkoff Invest Python gRPC client
https://tinkoff.github.io/invest-python/
Apache License 2.0
301 stars 87 forks source link

[Bug] create_market_data_stream возвращает неверные стаканы #218

Closed Che4ako closed 12 months ago

Che4ako commented 1 year ago

Что случилось?

Здравствуйте! После создания стрима с подписокой на стаканы периодически возникают временные промежутки, когда приходят неверные стаканы: цены и количество лотов лучшего бида и лучшега аска отклоняются от данных в приложении/терминале. Более того, случается, что цена лучшего бида становится выше цены лучшего аска и такие стаканы возвращаются на протяжении 5-10 секунд. После чего данные синхронизируются с данными в приложении/терминале.

Например, такая проблема видна в конце логов (бид=215.95, аск=215.91). Подскажите, пожалуйста, на чьей стороне проблема и как с этим бороться? Флаг is_consistent часто приходит False, поэтому фильтровать по нему невозможно.

P.S. Дополнительно протестировал 3 wifi-соединения как в синхронном (https://github.com/Tinkoff/invest-python/blob/main/examples/easy_stream_client.py), так и в асинхронном (https://github.com/Tinkoff/invest-python/blob/main/examples/easy_async_stream_client.py) виде для тикера 'SBER'. Проблема с некорректным стаканом возникает стабильно. Флаг is_consistent=False примерно в 50% полученных стаканов.

Воспроизведение

with Client(TOKEN) as client:
    data_stream = client.create_market_data_stream()
    data_stream.order_book.subscribe([OrderBookInstrument(figi='BBG004730N88', depth=10)])
    for market_data in data_stream:
        if market_data.orderbook is None:
            continue
        print(market_data.orderbook.is_consistent, market_data.orderbook.bids[0], market_data.orderbook.asks[0])

Tinkoff Invest Version

0.2.0-beta50

Python Version

3.10

OS

Linux

Логи

False Order(price=Quotation(units=215, nano=890000000), quantity=58) Order(price=Quotation(units=215, nano=910000000), quantity=410)
False Order(price=Quotation(units=215, nano=890000000), quantity=58) Order(price=Quotation(units=215, nano=910000000), quantity=237)
False Order(price=Quotation(units=215, nano=890000000), quantity=58) Order(price=Quotation(units=215, nano=910000000), quantity=237)
False Order(price=Quotation(units=215, nano=890000000), quantity=58) Order(price=Quotation(units=215, nano=910000000), quantity=237)
False Order(price=Quotation(units=215, nano=890000000), quantity=58) Order(price=Quotation(units=215, nano=910000000), quantity=237)
False Order(price=Quotation(units=215, nano=890000000), quantity=58) Order(price=Quotation(units=215, nano=910000000), quantity=237)
False Order(price=Quotation(units=215, nano=890000000), quantity=58) Order(price=Quotation(units=215, nano=910000000), quantity=237)
False Order(price=Quotation(units=215, nano=890000000), quantity=58) Order(price=Quotation(units=215, nano=910000000), quantity=237)
False Order(price=Quotation(units=215, nano=890000000), quantity=58) Order(price=Quotation(units=215, nano=910000000), quantity=237)
False Order(price=Quotation(units=215, nano=890000000), quantity=58) Order(price=Quotation(units=215, nano=910000000), quantity=237)
False Order(price=Quotation(units=215, nano=890000000), quantity=58) Order(price=Quotation(units=215, nano=910000000), quantity=237)
False Order(price=Quotation(units=215, nano=890000000), quantity=58) Order(price=Quotation(units=215, nano=910000000), quantity=235)
False Order(price=Quotation(units=215, nano=880000000), quantity=17) Order(price=Quotation(units=215, nano=860000000), quantity=225)
False Order(price=Quotation(units=215, nano=880000000), quantity=17) Order(price=Quotation(units=215, nano=860000000), quantity=225)
False Order(price=Quotation(units=215, nano=880000000), quantity=17) Order(price=Quotation(units=215, nano=860000000), quantity=225)
False Order(price=Quotation(units=215, nano=900000000), quantity=252) Order(price=Quotation(units=215, nano=910000000), quantity=235)
False Order(price=Quotation(units=215, nano=900000000), quantity=252) Order(price=Quotation(units=215, nano=910000000), quantity=235)
False Order(price=Quotation(units=215, nano=900000000), quantity=252) Order(price=Quotation(units=215, nano=910000000), quantity=235)
False Order(price=Quotation(units=215, nano=910000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=910000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=910000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=910000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=910000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=910000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=910000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=910000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=910000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=910000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=910000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=910000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=910000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=910000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=910000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=910000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=910000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=920000000), quantity=226) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
False Order(price=Quotation(units=215, nano=950000000), quantity=25) Order(price=Quotation(units=215, nano=910000000), quantity=200)
Che4ako commented 1 year ago

Проблема повторилась сегодня (04.05.2023) снова, в районе 10:00 и 15:00. По нескольким акциям (AFLT, POLY) некорректные стаканы (типа bid 631.70 > ask 630.40) приходили в течение 70 секунд!

Che4ako commented 1 year ago

Снова возникла такая проблема со стаканом AFKS (~11:35), bid 15.21000000 >= ask 15.19800000. Некорректные стаканы приходили в течение 60 секунд.

Che4ako commented 1 year ago

В дни активной торговли на бирже проблема возникает постоянно.

PaSol1 commented 1 year ago

Здравствуйте, при подписке на минутные свечи тоже приходит что то странное. Свечи не раз в минуту приходят, а чаще

код:

def request_iterator(instruments):
        figi_instrument = CandleInstrument(
            figi="BBG004730N88",
            interval=SubscriptionInterval.SUBSCRIPTION_INTERVAL_ONE_MINUTE,
        )

        yield MarketDataRequest(
            subscribe_candles_request=SubscribeCandlesRequest(
                waiting_close=True,
                subscription_action=SubscriptionAction.SUBSCRIPTION_ACTION_SUBSCRIBE,
                instruments=[figi_instrument],
            )
        )
        while True:
            time.sleep(1)

with Client(TOKEN) as client:
        for marketdata in client.market_data_stream.market_data_stream(
                request_iterator(stocks)
        ):
            if (marketdata.candle != None):
                print(marketdata.candle)

Например, 26 мая в 12:40 по SBER пришло

Candle(figi='BBG004730N88', interval=<SubscriptionInterval.SUBSCRIPTION_INTERVAL_ONE_MINUTE: 1>, open=Quotation(units=244, nano=0), high=Quotation(units=244, nano=0), low=Quotation(units=244, nano=0), close=Q
uotation(units=244, nano=0), volume=8, time=datetime.datetime(2023, 5, 26, 9, 40, tzinfo=datetime.timezone.utc), last_trade_ts=datetime.datetime(2023, 5, 26, 9, 40, 0, 305230, tzinfo=datetime.timezone.utc), instrument_uid='e6123145-9665-43e0-8413-cd61b8aa9b13')

Candle(figi='BBG004730N88', interval=<SubscriptionInterval.SUBSCRIPTION_INTERVAL_ONE_MINUTE: 1>, open=Quotation(units=244, nano=0), high=Quotation(units=244, nano=0), low=Quotation(units=244, nano=0), close=Q
uotation(units=244, nano=0), volume=419, time=datetime.datetime(2023, 5, 26, 9, 40, tzinfo=datetime.timezone.utc), last_trade_ts=datetime.datetime(2023, 5, 26, 9, 40, 0, 999837, tzinfo=datetime.timezone.utc),
 instrument_uid='e6123145-9665-43e0-8413-cd61b8aa9b13')

Candle(figi='BBG004730N88', interval=<SubscriptionInterval.SUBSCRIPTION_INTERVAL_ONE_MINUTE: 1>, open=Quotation(units=244, nano=0), high=Quotation(units=244, nano=0), low=Quotation(units=244, nano=0), close=Q
uotation(units=244, nano=0), volume=424, time=datetime.datetime(2023, 5, 26, 9, 40, tzinfo=datetime.timezone.utc), last_trade_ts=datetime.datetime(2023, 5, 26, 9, 40, 1, 322282, tzinfo=datetime.timezone.utc),
 instrument_uid='e6123145-9665-43e0-8413-cd61b8aa9b13')

Candle(figi='BBG004730N88', interval=<SubscriptionInterval.SUBSCRIPTION_INTERVAL_ONE_MINUTE: 1>, open=Quotation(units=244, nano=0), high=Quotation(units=244, nano=0), low=Quotation(units=244, nano=0), close=Q
uotation(units=244, nano=0), volume=464, time=datetime.datetime(2023, 5, 26, 9, 40, tzinfo=datetime.timezone.utc), last_trade_ts=datetime.datetime(2023, 5, 26, 9, 40, 1, 715507, tzinfo=datetime.timezone.utc),
 instrument_uid='e6123145-9665-43e0-8413-cd61b8aa9b13')

Candle(figi='BBG004730N88', interval=<SubscriptionInterval.SUBSCRIPTION_INTERVAL_ONE_MINUTE: 1>, open=Quotation(units=244, nano=0), high=Quotation(units=244, nano=10000000), low=Quotation(units=243, nano=9000
00000), close=Quotation(units=243, nano=900000000), volume=22910, time=datetime.datetime(2023, 5, 26, 9, 40, tzinfo=datetime.timezone.utc), last_trade_ts=datetime.datetime(2023, 5, 26, 9, 40, 59, 209182, tzin
fo=datetime.timezone.utc), instrument_uid='e6123145-9665-43e0-8413-cd61b8aa9b13')

а ожидал только цена открытия 244, цена закрытия 243,9, объем 22910

AlexanderVolkovTCS commented 12 months ago

Была такая проблема из-за потерь пакетов на одном из каналов связи с биржей, в июне коллеги поправили. Кстати, количество is_consistent=false тоже должно уменьшится.