error after hours : 10054, 'An existing connection was forcibly closed by the remote host', None, 10054, None

Dear all
I’m using python-binance 0.7.4 and to poll every 60s all my portfolio assets using the get_account function which basically sends the request to Binance API which appears in my log file with the API response :
[DEBUG] - connectionpool.py (line: 452) - https://api.binance.com:443 “GET /api/v3/account?timestamp=1630493485845&signature=8ae86da227e306a7c1c979845315c5578bdf6f72dc345b37714c98 HTTP/1.1” 200 2109

In the same time I have also a multi websocket fetching real time prices

After few 4 to 8 hours I got the error message from the API and the connection is closed.

I’ve check the web but not found really explanations for that : It doesn"t sound like I’m reaching API rates limits as the message is usually explicite then.

Could it be an automatic disconnection and I need to periodically close and reopen my connections ?
Could it be a lost connection from my internet provider during few seconds ?
Could it be I’m considered as attacking their API doing periodic such requests ?

Any clue ?
Thanks & cheers
Stéphane

Could it be an automatic disconnection and I need to periodically close and reopen my connections ?


The websocket connection will definitely disconnect at the 24 hour mark. So reconnection will be required in this case.

Could it be a lost connection from my internet provider during few seconds ?

This is likely to cause a disconnect from the websocket.

Could it be I’m considered as attacking their API doing periodic such requests ?

You should always use websocket for live market data due to the time sensitivity and the high frequency of querying.

Dear Chai,
Many thanks for answering.

There is actually something I don’t understand from the Binance docs. It says

A single connection to stream.binance.com is only valid for 24 hours; expect to be disconnected at the 24 hour mark

Hower my script works fine with live streams websocket without disconnection using the pyhon-binance lib. Possibly the lib takes care about the 24hr disconnection

But it sounds this is only the case for websockets, not for account end-points and the problem I currently have is not on websocket actually but on an account endpoint

And as far as I understand the python-binance lib takes care of connecting the host each time I do the request so that I do not understand why Binance closes the connections after having spent hours polling the account end-point every minute. I would love having the data in a stream but I think there are not available.

I did a test with a script only polling the account endpoint and was unable to reproduce the error so I assume this is linked to the fact I’m also connecting several websockets in parallel… but I don’t understand why yet…

Stephane

If you are trying to subscribe to multiple market streams, i suggest you combine it to a single stream to prevent abnormalities like you mentioned. You can combine streams by: /stream?streams=streamName1/streamName2/streamName3

This is what I’m doing. I combine the streams

Here under are the extracts of the code starting the periodic get_account_data function (Binance get_account endpoint) and the multiplex stream. the variable stream_list contains the 250 crypto I’m collecting data
Clock is periodically syncronized to NTP and error is always < 1s

##### EXTRACT FROM MAIN
#############################################

    # Create a Binance client and connect to API
    secret_file = "secret.cfg"
    trader = Trader(secret_file)

    # Call periodic Binance get_account_data
    get_account_data(trader) # and then call periodic function (every 60s)

    # Call periodic NTP resynchronization
    synchronize_ntp()

    # Initialize the web socket manager
    logging.info('Initialize WebSocket Manager')
    bm = StartWebSocketManager(trader)

    # get all Binance available crypto list from 24h ticker API
    logging.info('Get Binance 24h ticker')
    try:
        Binance_all_symbols_list = trader.client.get_all_tickers()
    except BinanceAPIException as e:
        logging.error(e)

    Binance_all_symbols_list = sorted(Binance_all_symbols_list, key=fctSortDict, reverse=False)

    # start the websocket for all cryptos which filter out only USDT cryptos from 'Binance_all_symbols_list'.
    # call 'process_symbol_message' callback function for processing received messages and fill-in 'crypto_data_stream'
    print('... Starting Symbols websocket ...')
    logging.info('Start symbols kline websockets')
    StartSymbolklineSocket(bm, trader, stream_list)
    print('Wait 10 s for having all the crypto messages responding\n')
    time.sleep(10) # wait a while to have all crypto responding
    print('done\n')
	
	
#### THE multiplex stream socket
#############################################
	
def StartSymbolklineSocket(bm, trader, stream_list):
    conn_key = bm.start_multiplex_socket(stream_list, process_kline_symbol_message)
	


#### THE get_account_data periodic function
#############################################

# Thread function wrapper
def periodic_task(interval, times = -1):
    def outer_wrap(function):
        def wrap(*args, **kwargs):
            stop = threading.Event()
            def inner_wrap():
                i = 0
                while i != times and not stop.isSet():
                    stop.wait(interval)
                    function(*args, **kwargs)
                    i += 1

            t = threading.Timer(0, inner_wrap)
            t.daemon = True
            t.start()
            return stop
        return wrap
    return outer_wrap

# Periodic tasks
@periodic_task(60)
def get_account_data(trader):
    global account, binance_mutex
    if binance_mutex == False:
        logging.info('Get Binance Account Data')
        try:
            account = trader.client.get_account()
        except BinanceAPIException as e:
            logging.error(e)
            if e.status_code == 10054:
                account = trader.client.get_account()

After upgrading to the last python-binance version, my script still ends with the same error after an apparent random number of hours… the last one 2h only after the start.
The script has a multistream with 250 cryptos, a NTP reading every 10 minutes and this get_account endpoint every 1 minute.

After the error occurs, only the account enpoint seems involved in the 10054 error as the streams are still alive.

I’m stuck !

As a workaround I’m testing right now to catch the exception from the client connection routine and to restart the connection is error is occuring. We’ll see in few hour…

did this work out? If not, how did you manage to solve this issue ?

Hi,
I have actually still problems with Binance websockets from the Python-Binance library.
I’m experiencing disconnections without beeing able to identify why.
I’m running two websockets at the same time : tickers and klines and each of them with all the USDT pair which is currently a bit more than 300 each so 600 websockets actually at the same time. This is maybe too much ???

I’m rewritting my code to use the async method and discovered as well that with a demo code reproducing the problem with only one websocket at a time, regularly the websocket queue is overflowing suddenly. i.e. the length is at 0 most of the time meaning I’m processing the messages as fast as they arrive but suddently the queue length increases up to the limit causing the websocket to stop.
This is apparently not because of my code going to slow when receiving messages as it can run hours with the queue length at 0 before it suddenly increases.

So I would say that the websockets are still not running as it should and I still don’t have clues on how to understand what’s happening…

I’m still working with a minimalist piece of code to try to stabilze the websockets connection before integrating the modification to my bot.

Regards
Stephane

Here is my minimalist code already showing troubles after a while usint PyQt5 and Python-Binance 1.0.17 :

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
from PyQt5.QtCore import pyqtSignal, QObject
import asyncio
import asyncqt
from binance import AsyncClient, BinanceSocketManager

class BinanceWebSocket(QObject):
    new_data = pyqtSignal(dict)

    def __init__(self):
        super().__init__()

    async def connect_to_binance_websocket(self, symbol):
        self.client = await AsyncClient.create()
        self.bsm = BinanceSocketManager(self.client)
        self.socket = self.bsm.trade_socket(symbol)
        async with self.socket as trade_stream:
            while True:
                res = await trade_stream.recv()
                # print('queue lenghth :', trade_stream._queue.qsize())
                self.new_data.emit(res)
        await self.client.close_connection()


    def reset_socket(self):
        self.client.close_connection()
        loop.create_task(self.connect_to_binance_websocket('btcusdt'))
        # if (self._log.isEnabledFor(logging.DEBUG)):
        #   self._log.debug("Reconnecting. Waiting for 5 seconds...")
        #   sleep(5)

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.label = QLabel(self)
        self.label.setGeometry(50, 50, 750, 30)

        self.binance_websocket = BinanceWebSocket()
        self.binance_websocket.new_data.connect(self.handle_new_data)
        self.socket_restart = 0
        loop = asyncio.get_event_loop()
        loop.create_task(self.binance_websocket.connect_to_binance_websocket('btcusdt'))

    def handle_new_data(self, data):
        self.label.setText(str(data))
        # self.binance_websocket.reset_socket()
        # loop.create_task(self.binance_websocket.connect_to_binance_websocket('btcusdt'))
        if ('e' in data):
            if (data['m'] == 'Queue overflow. Message not filled'):
                print("Socket queue full. Resetting connection.")
                # self.binance_websocket.reset_socket()
                self.socket_restart += 1
                print('socket restart :', self.socket_restart)
                loop.create_task(self.binance_websocket.connect_to_binance_websocket('btcusdt'))
                return
            else:
                if data['m'] is not True and data['m'] is not False:
                    print(f"Stream error: {data['m']}")
                    # exit(1)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    loop = asyncqt.QEventLoop(app)
    asyncio.set_event_loop(loop)
    mainWindow = MainWindow()
    mainWindow.show()
    with loop:
        loop.run_forever()
    sys.exit(app.exec_())

I am writing server in swift with vapor. Using NIO web socket I was able to connect and subscribe for price updates. But every 3 hours binance stops sending me price updates and pings without any error message.