LUCIT-Systems-and-Development / unicorn-binance-websocket-api

A Python SDK by LUCIT to use the Binance Websocket API`s (com+testnet, com-margin+testnet, com-isolated_margin+testnet, com-futures+testnet, com-coin_futures, us, tr, dex/chain+testnet) in a simple, fast, flexible, robust and fully-featured way.
https://unicorn-binance-websocket-api.docs.lucit.tech/
Other
678 stars 166 forks source link

The limit of 200 subscriptions per stream has been exceeded #186

Closed m0nte-cr1st0 closed 2 years ago

m0nte-cr1st0 commented 2 years ago

I have following error

CRITICAL:root:BinanceWebSocketApiManager.stop_stream_as_crash(aa182f58-3b64-47fe-85b3-60aece017e57)
CRITICAL:root:BinanceWebSocketApiManager.subscribe_to_stream(aa182f58-3b64-47fe-85b3-60aece017e57) Info: The limit of 200 subscriptions per stream has been exceeded!
CRITICAL:root:BinanceWebSocketApiManager.stream_is_crashing(aa182f58-3b64-47fe-85b3-60aece017e57)

Versions: unicorn-binance-websocket-api==1.31.0 Python 3.8.10 (default, May 12 2021, 15:46:43)

I'm using following code:

import json
import time
from decimal import Decimal

from django.core.management import BaseCommand
from unicorn_binance_websocket_api import BinanceWebSocketApiManager

from datareader.models import CandlesHistory, Interval, Pair

from .services.trade_service import (
    get_or_create_candles,
)

class Command(BaseCommand):
    def __init__(self):
        super().__init__()
        self.twm = None
        self.twm2 = None
        self.stream = None
        self.stream2 = None

    @staticmethod
    def update_candle(model_data: dict):
        data_for_update = model_data.copy()
        del data_for_update["start_time"]
        candles = CandlesHistory.objects.filter(
            pair=model_data["pair"],
            interval=model_data["interval"],
        )
        candle = candles.last()
        if Decimal(data_for_update["high"]) < Decimal(candle.high):
            del data_for_update["high"]
        if Decimal(data_for_update["low"]) > Decimal(candle.low):
            del data_for_update["low"]
        candles.filter(pk=candle.pk).update(**data_for_update)
        return candle

    def handle(self, *args, **options):
        self.twm = BinanceWebSocketApiManager(exchange="binance.com-futures")
        channels, markets = self.get_channels_and_markets()

        if not self.stream and not self.stream2:
            self.stream = self.twm.create_stream(
                tuple(channels), tuple(markets)
            )

        start_time = time.time()

        while True:
            if self.twm:
                stream = self.twm.pop_stream_data_from_stream_buffer()
            else:
                stream = self.twm2.pop_stream_data_from_stream_buffer()
            if stream:
                msg = json.loads(stream)
                if not msg.get("data"):
                    continue
            # other logic ...
            current_time = time.time()
            elapsed_time = current_time - start_time
            if elapsed_time > 3000:  # after 50 minutes I toggle websockets
                self.toggle_websockets()
                start_time = time.time()

    def toggle_websockets(self):
        channels, markets = self.get_channels_and_markets()
        # If second websocket is active
        if not self.twm:
            self.twm = BinanceWebSocketApiManager(
                exchange="binance.com-futures"
            )
            self.stream = self.twm.create_stream(
                tuple(channels), tuple(markets)
            )

            self.twm2.stop_manager_with_all_streams()
            self.stream2 = None
            self.twm2 = None

        # If first websocket is active
        else:
            self.twm2 = BinanceWebSocketApiManager(
                exchange="binance.com-futures"
            )

            self.stream2 = self.twm2.create_stream(
                tuple(channels), tuple(markets)
            )
            self.twm.stop_manager_with_all_streams()
            self.stream = None
            self.twm = None

    @staticmethod
    def get_channels_and_markets():
        client = None
        channels = set()
        markets = set()
        for pair in Pair.objects.filter(is_active=True, is_deleted=False):
            for interval in Interval.objects.all():
                get_or_create_candles(pair, interval)
                channels.add(f"kline_{interval.alias}")
            markets.add(pair.ticker.lower())
        return channels, markets

I have 102 active pairs and 2 timefimes (1h and 4h)

m0nte-cr1st0 commented 2 years ago

I found this settings https://github.com/oliver-zehentleitner/unicorn-binance-websocket-api/blob/master/unicorn_binance_websocket_api/unicorn_binance_websocket_api_manager.py#L197

Can I to increase this to 204 (102 pairs * 2 timeframes)?

m0nte-cr1st0 commented 2 years ago

If I write self.twm.max_subscriptions_per_stream = 205 I get error

CRITICAL:root:BinanceWebSocketApiSocket.start_socket(...) - Exception ConnectionClosed - error_msg: code = 1006 (connection closed abnormally [internal]), no reason
CRITICAL:root:BinanceWebSocketApiManager.stream_is_crashing(784d9929-4441-44ca-91a6-54495ffdaac7)
CRITICAL:root:BinanceWebSocketApiManager.stream_is_crashing() - Exception ConnectionClosed - error_msg: code = 3001 (registered), reason = illegal request

But I have 1 free slot fot subscriptions?

oliver-zehentleitner commented 2 years ago

No thats not possible. The maximum is defined by binance endpoints: https://binance-docs.github.io/apidocs/futures/en/#change-log look at date 2020-10-27

but you can create more streams :)

oliver-zehentleitner commented 2 years ago

just reopen if needed!