sammchardy / python-binance

Binance Exchange API python implementation for automated trading
https://python-binance.readthedocs.io/en/latest/
MIT License
5.98k stars 2.2k forks source link

There is something wrong with the new version threading v1.0.16 #1174

Open saeedsamie opened 2 years ago

saeedsamie commented 2 years ago

I update my python-binance lib version to v1.0.16 and suddenly this error came up.

Traceback (most recent call last): File "C:\Users\saeed\AppData\Local\Programs\Python\Python38\lib\site-packages\binance\threaded_stream.py", line 46, in start_listener msg = await asyncio.wait_for(s.recv(), 3) File "C:\Users\saeed\AppData\Local\Programs\Python\Python38\lib\asyncio\tasks.py", line 483, in wait_for return fut.result() File "C:\Users\saeed\AppData\Local\Programs\Python\Python38\lib\site-packages\binance\streams.py", line 197, in recv res = await asyncio.wait_for(self._queue.get(), timeout=self.TIMEOUT) File "C:\Users\saeed\AppData\Local\Programs\Python\Python38\lib\asyncio\tasks.py", line 483, in wait_for return fut.result() File "C:\Users\saeed\AppData\Local\Programs\Python\Python38\lib\asyncio\queues.py", line 163, in get await getter RuntimeError: Task <Task pending name='Task-10' coro=<Queue.get() running at C:\Users\saeed\AppData\Local\Programs\Python\Python38\lib\asyncio\queues.py:163> cb=[_release_waiter(()]>)() at C:\Users\saeed\AppData\Local\Programs\Python\Python38\lib\asyncio\tasks.py:429]> got Future attached to a different loop

@sammchardy Is it caused by my code or this is a bug?

jef0525 commented 2 years ago

I got the same error too. Here is code to reproduce the error, it's works with v1.0.15.

python version: 3.8.0 python-binance: 1.0.16

from binance import Client, ThreadedWebsocketManager

def handle_socket_message(msg):
    print(f"message type: {msg['e']}")
    print(msg)

twm = ThreadedWebsocketManager()
twm.start()
twm.start_kline_socket(callback=handle_socket_message, symbol='BNBBTC')
twm.join()
jiancongs commented 2 years ago

same error here when I use start_futures_user_socket() right after I upgrade to 1.0.16.

halfelf commented 2 years ago

This error seems only thrown on python < 3.10. However, on 3.10, the threaded socket just hang there without any message processed.

I believe a quick fix could be done by set threaded event loop to the OS one:

https://github.com/sammchardy/python-binance/blob/master/binance/threaded_stream.py#L19

class ThreadedApiManager(threading.Thread):

    def __init__(
        self, api_key: Optional[str] = None, api_secret: Optional[str] = None,
        requests_params: Optional[Dict[str, str]] = None, tld: str = 'com',
        testnet: bool = False
    ):
        """Initialise the BinanceSocketManager
        """
        super().__init__()
        self._loop: asyncio.AbstractEventLoop = asyncio.new_event_loop()  # <-------- change this to `asyncio.get_event_loop()`
        self._client: Optional[AsyncClient] = None
        self._running: bool = True
        self._socket_running: Dict[str, bool] = {}
        self._client_params = {
            'api_key': api_key,
            'api_secret': api_secret,
            'requests_params': requests_params,
            'tld': tld,
            'testnet': testnet
        }

Hope someone could test this fix and open a pull request since I don't use threaded socket.

MoeQatoum commented 2 years ago

@halfelf suggestion worked for issue #1172 , thanks.

thisismygitrepo commented 2 years ago

Same on my side. Went to my old machine that has an old installation and the code works but fails on the latest. Python 3.9

Kncokoff commented 2 years ago

tried @halfelf solution but when running two sockets got another problem

self.tdcm = ThreadedDepthCacheManager()
        self.twsm= ThreadedWebsocketManager()
        self.twsm.start()
        self.tdcm.start()

RuntimeError: This event loop is already running

any work around?

mikkokotila commented 2 years ago

any work around?

pip install python-binance==1.0.15

alxkos commented 2 years ago

Any news?! Still not working and it makes the module kinda useless (((

halfelf commented 2 years ago

Since lots of attention to this thread, it comes to me that I have to say, one can always try the coroutine way, which should be a better solution for python. Threaded socket is hard to maintain and causes much trouble in several releases.

For anyone with skilled python programming, I have a forked and modified version of this module, working only in trio event loop.

curiouscod3 commented 2 years ago

any work around?

pip install python-binance==1.0.15

same issue on 1.0.15 and 1.016 as well

slikdijit commented 2 years ago

@halfelf solution worked on my machine Ubuntu 21.10

qraxiss commented 1 year ago

For this problem in my own code I changed the async websocket method to Thread. I hope it works.

from binance.client import Client
from helpers import socket_parser
from threading import Thread
from time import sleep
import binance
import asyncio

# ignore
from logic.exchange.streams.helpers import kline_stream_formatter
from api import request

class WebSocket:
    def __init__(self, client) -> None:
        self.client = client
        self.klines = dict()

    async def kline_async(self, socket: str, limit: int = 40):
        symbol, interval = socket_parser(socket)
        klines = self.client.futures_klines(symbol=symbol, interval=interval, limit=limit)
        value = request('/klines', 'post', value=f'/{socket}', json=klines)  # ignore
        async_client = await binance.AsyncClient.create()
        bm = binance.BinanceSocketManager(async_client)
        ts = bm.futures_multiplex_socket(streams=[socket])
        self.klines[socket] = True
        async with ts as tscm:
            while self.klines[socket]:
                res = await tscm.recv()
                kline_stream_formatter(res)  # ignore 
        await async_client.close_connection()

    def kline(self, **kwargs):
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        loop.run_until_complete(self.kline_async(**kwargs))
        loop.close()

    def kline_thread(self, **kwargs):
        Thread(target=self.kline, kwargs=kwargs).start()

    def kline_close(self, socket:str):
        self.klines[socket]=False

ws = WebSocket(Client())
ws.kline_thread(socket="btcusdt@kline_1m", limit=50)

sleep(15)# for thread still running
ws.kline_close(socket="btcusdt@kline_1m")
sinaqahremani commented 1 year ago

I have the same problem. Is there any solution or update?

sinaqahremani commented 1 year ago

It is really shameful. They updated the library 9 months ago, and still it has bugs.

thisismygitrepo commented 1 year ago

@sinaqahremani

sinaqahremani commented 1 year ago

@thisismygitrepo Thank you Alex,

If someone from the team is available and can help me just by answering basic questions, I can work voluntarily on this bug. Actually, we have used this library since 2021. Moreover, I need to use start_futures_user_socket which is available in 1.0.16.

halfelf commented 1 year ago

@sinaqahremani

I don't think there is a "team". And the license has declared clearly there is no liability or warranty this SDK works as anyone expects.

Back to this perticular issue, as I said before, forget about threads and switch to pure async codes is the pythonic way and best shot.

This codes of this library, IMHO, have been organized very well, for both reading and writing with. It won't be a big trouble to fix this bug. As you can see, it has been located and there is a way to fix it (just need some additional effort to make it work with multiple websockets.)

@thisismygitrepo

I almost read every issue from time to time. At least 95% of them are not bugs, but programming issues suitable for stackoverflow.