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
677 stars 166 forks source link

Stream data not udpated after got event "listenKeyExpired" #275

Closed bobwng closed 1 year ago

bobwng commented 2 years ago

Version of this library.

unicorn_fy: 0.11.0 unicorn_binance_local_depth_cache: not found unicorn_binance_rest_api: not found unicorn_binance_trailing_stop_loss: not found unicorn_binance_websocket_api: 1.41.0

Solution to Issue cannot be found in the documentation or other Issues and also occurs in the latest version of this library.

Hardware?

VPS or other cloud hosting

Operating System?

Linux

Python version?

Python3.8

Installed packages

Package                       Version
----------------------------- -----------
aiohttp                       3.8.1
aiosignal                     1.2.0
aniso8601                     9.0.1
apprise                       0.9.2
argon2-cffi                   21.1.0
async-timeout                 4.0.2
attrs                         21.2.0
autobahn                      21.3.1
Automat                       20.2.0
backcall                      0.2.0
backports.zoneinfo            0.2.1
bidict                        0.21.4
bleach                        4.1.0
cachetools                    4.2.2
certifi                       2021.10.8
cffi                          1.15.0
charset-normalizer            2.0.7
cheroot                       8.5.2
click                         8.0.3
colorama                      0.4.4
constantly                    15.1.0
cryptography                  35.0.0
cycler                        0.10.0
dateparser                    1.1.0
debugpy                       1.5.1
decorator                     5.1.0
defusedxml                    0.7.1
dnspython                     1.16.0
entrypoints                   0.3
eventlet                      0.30.2
Flask                         1.1.2
Flask-Cors                    3.0.10
Flask-RESTful                 0.3.9
Flask-SocketIO                5.0.1
frozenlist                    1.3.0
greenlet                      1.1.2
gunicorn                      20.1.0
hyperlink                     21.0.0
idna                          3.3
importlib-resources           5.4.0
incremental                   21.3.0
influxdb-client               1.25.0
ipykernel                     6.5.1
ipython                       7.30.0
ipython-genutils              0.2.0
ipywidgets                    7.6.5
itsdangerous                  2.0.1
jaraco.functools              3.3.0
jedi                          0.18.1
Jinja2                        3.0.2
jsonschema                    4.2.1
jupyter                       1.0.0
jupyter-client                7.1.0
jupyter-console               6.4.0
jupyter-core                  4.9.1
jupyterlab-pygments           0.1.2
jupyterlab-widgets            1.0.2
kiwisolver                    1.3.2
Markdown                      3.3.4
MarkupSafe                    2.0.1
matplotlib                    3.4.3
matplotlib-inline             0.1.3
mistune                       0.8.4
more-itertools                8.10.0
multidict                     6.0.2
nbclient                      0.5.9
nbconvert                     6.3.0
nbformat                      5.1.3
nest-asyncio                  1.5.1
notebook                      6.4.6
numpy                         1.21.3
oauthlib                      3.1.1
packaging                     21.3
pandas                        1.3.4
pandocfilters                 1.5.0
parso                         0.8.2
pathlib                       1.0.1
pexpect                       4.8.0
pickleshare                   0.7.5
Pillow                        8.4.0
pip                           22.1.1
prometheus-client             0.12.0
prompt-toolkit                3.0.23
psutil                        5.8.0
psycopg2-binary               2.9.1
ptyprocess                    0.7.0
pyasn1                        0.4.8
pyasn1-modules                0.2.8
pycparser                     2.20
Pygments                      2.10.0
pyOpenSSL                     21.0.0
pyparsing                     3.0.2
pyrsistent                    0.18.0
python-binance                1.0.16
python-dateutil               2.8.2
python-engineio               4.3.0
python-socketio               5.2.1
pytz                          2021.3
pytz-deprecation-shim         0.1.0.post0
PyYAML                        6.0
pyzmq                         22.3.0
qtconsole                     5.2.1
QtPy                          1.11.2
redis                         3.5.3
regex                         2021.10.23
requests                      2.26.0
requests-oauthlib             1.3.0
Rx                            3.2.0
schedule                      1.1.0
Send2Trash                    1.8.0
service-identity              21.1.0
setuptools                    56.0.0
six                           1.16.0
SQLAlchemy                    1.4.15
sqlitedict                    1.7.0
terminado                     0.12.1
testpath                      0.5.0
tornado                       6.1
traitlets                     5.1.1
Twisted                       21.7.0
txaio                         21.2.1
typing-extensions             3.10.0.2
tzdata                        2021.5
tzlocal                       4.0.2
ujson                         4.2.0
unicorn-binance-websocket-api 1.41.0
unicorn-fy                    0.11.0
urllib3                       1.26.7
wcwidth                       0.2.5
webencodings                  0.5.1
websocket-client              1.2.1
websockets                    10.3
Werkzeug                      2.0.2
widgetsnbextension            3.5.2
yarl                          1.7.2
zipp                          3.6.0
zope.interface                5.4.0

Logging output

~/g/binance-trade-bot > grep "REMOVE API_KEY" logs/* 
 ~/g/binance-trade-bot > grep "API_KEY" logs/*
 ~/g/binance-trade-bot > grep "API_SECRET" logs/*
 ~/g/binance-trade-bot > grep "LISTEN_KEY" logs/*
 ~/g/binance-trade-bot > grep "listenKeyExpired" logs/*
logs/crypto_trading.log:2022-05-27 21:11:32,282 - crypto_trading_logger - WARNING - WARN: Not handled 'e' event: {'e': 'listenKeyExpired', 'E': 1653657092253}
logs/crypto_trading.log:2022-05-27 21:11:32,282 - crypto_trading_logger - WARNING - WARN: Not handled 'e' event: {'e': 'listenKeyExpired', 'E': 1653657092253}
logs/crypto_trading.log:2022-05-29 00:20:58,989 - crypto_trading_logger - WARNING - WARN: Not handled 'e' event: {'e': 'listenKeyExpired', 'E': 1653754858963}
logs/crypto_trading.log:2022-05-29 00:20:58,990 - crypto_trading_logger - WARNING - WARN: Not handled 'e' event: {'e': 'listenKeyExpired', 'E': 1653754858964}
logs/crypto_trading.log:2022-05-30 00:42:24,114 - crypto_trading_logger - WARNING - Listen key expired: {'e': 'listenKeyExpired', 'E': 1653842544091}
logs/crypto_trading.log.1:2022-05-26 15:35:31,315 - crypto_trading_logger - WARNING - WARN: Not handled 'e' event: {'e': 'listenKeyExpired', 'E': 1653550531286}
logs/crypto_trading.log.1:2022-05-26 15:35:31,316 - crypto_trading_logger - WARNING - WARN: Not handled 'e' event: {'e': 'listenKeyExpired', 'E': 1653550531287}

Processing method?

process_stream_data

Used endpoint?

binance.com-coin_futures

Issue

I subscribe both !userData and !miniTicker stream, !userData stopped to get new update after got listenKeyExpired event. But last time(2022-05-30 00:42:24,114) both userData/miniTicker are stopped to send update.

There is no significant error/warning logs like "time out", "connection interrupted" etc. No related code change in recent days, except adding some new log specific for listenKeyExpired event. And the scripts never prompt such information in recent months.

I found API "PUT /fapi/v1/listenKey" not exposed, not sure if we can expose this API and then I can invoke it manually to prevent this event?

bobwng commented 2 years ago

Got another listenKeyExpired event just now, it lasts less than 5 hours this time.

oliver-zehentleitner commented 2 years ago

Can you provide a DEBUG log of ubwa please?

bobwng commented 2 years ago

Here it is:

2022-06-01 12:10:50,659 [DEBUG ] 23539 140046298318592 protocol: % sending keepalive ping 2022-06-01 12:10:50,659 [DEBUG ] 23539 140046298318592 protocol: > PING 83 f7 ab a0 [binary, 4 bytes] 2022-06-01 12:10:50,698 [DEBUG ] 23539 140046298318592 protocol: < PONG 83 f7 ab a0 [binary, 4 bytes] 2022-06-01 12:10:50,698 [DEBUG ] 23539 140046298318592 protocol: % received keepalive pong 2022-06-01 12:10:50,788 [DEBUG ] 23539 140046298318592 protocol: < TEXT '{"stream":"ethusdt@miniTicker","data":{"e":"24h...","q":"5074685853.30"}}' [187 bytes] 2022-06-01 12:10:50,788 [DEBUG ] 23539 140046298318592 manager: BinanceWebSocketApiManager.is_stop_request(8ace05a5aa94-82ba-5b56-e41d-6a6fa0ca) 2022-06-01 12:10:50,788 [DEBUG ] 23539 140046298318592 manager: BinanceWebSocketApiManager.is_stop_as_crash_request(8ace05a5aa94-82ba-5b56-e41d-6a6fa0ca) 2022-06-01 12:10:50,789 [DEBUG ] 23539 140046298318592 manager: BinanceWebSocketApiManager.set_heartbeat(8ace05a5aa94-82ba-5b56-e41d-6a6fa0ca) 2022-06-01 12:10:51,046 [DEBUG ] 23539 140045981832960 protocol: % sending keepalive ping 2022-06-01 12:10:51,046 [DEBUG ] 23539 140045981832960 protocol: > PING 39 9b a4 cf [binary, 4 bytes] 2022-06-01 12:10:51,057 [DEBUG ] 23539 140046298318592 protocol: < TEXT '{"stream":"adausdt@miniTicker","data":{"e":"24h...q":"1998507369.69000"}}' [189 bytes] 2022-06-01 12:10:51,057 [DEBUG ] 23539 140046298318592 manager: BinanceWebSocketApiManager.is_stop_request(8ace05a5aa94-82ba-5b56-e41d-6a6fa0ca) 2022-06-01 12:10:51,057 [DEBUG ] 23539 140046298318592 manager: BinanceWebSocketApiManager.is_stop_as_crash_request(8ace05a5aa94-82ba-5b56-e41d-6a6fa0ca) 2022-06-01 12:10:51,058 [DEBUG ] 23539 140046298318592 manager: BinanceWebSocketApiManager.set_heartbeat(8ace05a5aa94-82ba-5b56-e41d-6a6fa0ca) 2022-06-01 12:10:51,077 [DEBUG ] 23539 140046334162688 protocol: < TEXT '{"stream":"bnbusdt@markPrice","data":{"e":"mark...00","T":1654070400000}}' [185 bytes] 2022-06-01 12:10:51,078 [DEBUG ] 23539 140046334162688 manager: BinanceWebSocketApiManager.is_stop_request(5714146bb496-39e3-6ee7-b81c-04b57f70) 2022-06-01 12:10:51,078 [DEBUG ] 23539 140046334162688 manager: BinanceWebSocketApiManager.is_stop_as_crash_request(5714146bb496-39e3-6ee7-b81c-04b57f70) 2022-06-01 12:10:51,078 [DEBUG ] 23539 140046334162688 manager: BinanceWebSocketApiManager.set_heartbeat(5714146bb496-39e3-6ee7-b81c-04b57f70) 2022-06-01 12:10:51,081 [DEBUG ] 23539 140045981832960 protocol: < PONG 39 9b a4 cf [binary, 4 bytes] 2022-06-01 12:10:51,081 [DEBUG ] 23539 140045981832960 protocol: % received keepalive pong 2022-06-01 12:10:51,122 [DEBUG ] 23539 140046298318592 protocol: < TEXT '{"stream":"solusdt@miniTicker","data":{"e":"24h...,"q":"904046299.7000"}}' [185 bytes] 2022-06-01 12:10:51,122 [DEBUG ] 23539 140046298318592 manager: BinanceWebSocketApiManager.is_stop_request(8ace05a5aa94-82ba-5b56-e41d-6a6fa0ca) 2022-06-01 12:10:51,123 [DEBUG ] 23539 140046298318592 manager: BinanceWebSocketApiManager.is_stop_as_crash_request(8ace05a5aa94-82ba-5b56-e41d-6a6fa0ca) 2022-06-01 12:10:51,123 [DEBUG ] 23539 140046298318592 manager: BinanceWebSocketApiManager.set_heartbeat(8ace05a5aa94-82ba-5b56-e41d-6a6fa0ca) REMOVE LINES... 2022-06-01 12:10:51,622 [DEBUG ] 23539 140046298318592 protocol: < TEXT '{"stream":"solusdt@miniTicker","data":{"e":"24h...,"q":"904049721.7300"}}' [185 bytes] 2022-06-01 12:10:51,622 [DEBUG ] 23539 140046298318592 manager: BinanceWebSocketApiManager.is_stop_request(8ace05a5aa94-82ba-5b56-e41d-6a6fa0ca) 2022-06-01 12:10:51,622 [DEBUG ] 23539 140046298318592 manager: BinanceWebSocketApiManager.is_stop_as_crash_request(8ace05a5aa94-82ba-5b56-e41d-6a6fa0ca) 2022-06-01 12:10:51,622 [DEBUG ] 23539 140046298318592 manager: BinanceWebSocketApiManager.set_heartbeat(8ace05a5aa94-82ba-5b56-e41d-6a6fa0ca) 2022-06-01 12:10:51,641 [DEBUG ] 23539 140045981832960 sockets: BinanceWebSocketApiSocket.start_socket(7b228620c70d-6023-b639-9040-3fd6dfa6, ['arr'], ['!userData'] - Received inner asyncio.TimeoutError 2022-06-01 12:10:51,641 [DEBUG ] 23539 140045981832960 manager: BinanceWebSocketApiManager.is_stop_request(7b228620c70d-6023-b639-9040-3fd6dfa6) 2022-06-01 12:10:51,641 [DEBUG ] 23539 140045981832960 manager: BinanceWebSocketApiManager.is_stop_as_crash_request(7b228620c70d-6023-b639-9040-3fd6dfa6) 2022-06-01 12:10:51,641 [DEBUG ] 23539 140045981832960 manager: BinanceWebSocketApiManager.set_heartbeat(7b228620c70d-6023-b639-9040-3fd6dfa6) REMOVE LINES... 2022-06-01 12:10:52,122 [DEBUG ] 23539 140046298318592 protocol: < TEXT '{"stream":"solusdt@miniTicker","data":{"e":"24h...,"q":"904051677.5300"}}' [185 bytes] 2022-06-01 12:10:52,122 [DEBUG ] 23539 140046298318592 manager: BinanceWebSocketApiManager.is_stop_request(8ace05a5aa94-82ba-5b56-e41d-6a6fa0ca) 2022-06-01 12:10:52,122 [DEBUG ] 23539 140046298318592 manager: BinanceWebSocketApiManager.is_stop_as_crash_request(8ace05a5aa94-82ba-5b56-e41d-6a6fa0ca) 2022-06-01 12:10:52,122 [DEBUG ] 23539 140046298318592 manager: BinanceWebSocketApiManager.set_heartbeat(8ace05a5aa94-82ba-5b56-e41d-6a6fa0ca) 2022-06-01 12:10:52,144 [DEBUG ] 23539 140045981832960 protocol: < TEXT '{"e": "listenKeyExpired", "E": 1654056652127}' [45 bytes] 2022-06-01 12:10:52,145 [DEBUG ] 23539 140045981832960 protocol: < TEXT '{"e": "listenKeyExpired", "E": 1654056652128}' [45 bytes] 2022-06-01 12:10:52,145 [DEBUG ] 23539 140045981832960 manager: BinanceWebSocketApiManager.is_stop_request(7b228620c70d-6023-b639-9040-3fd6dfa6) 2022-06-01 12:10:52,145 [DEBUG ] 23539 140045981832960 manager: BinanceWebSocketApiManager.is_stop_as_crash_request(7b228620c70d-6023-b639-9040-3fd6dfa6) 2022-06-01 12:10:52,145 [DEBUG ] 23539 140045981832960 manager: BinanceWebSocketApiManager.set_heartbeat(7b228620c70d-6023-b639-9040-3fd6dfa6) 2022-06-01 12:10:52,145 [DEBUG ] 23539 140045981832960 manager: BinanceWebSocketApiManager.is_stop_request(7b228620c70d-6023-b639-9040-3fd6dfa6) 2022-06-01 12:10:52,145 [DEBUG ] 23539 140045981832960 manager: BinanceWebSocketApiManager.is_stop_as_crash_request(7b228620c70d-6023-b639-9040-3fd6dfa6) 2022-06-01 12:10:52,146 [DEBUG ] 23539 140045981832960 manager: BinanceWebSocketApiManager.set_heartbeat(7b228620c70d-6023-b639-9040-3fd6dfa6) 2022-06-01 12:10:52,146 [INFO ] 23539 140046412805888 asyncio: Notifying 1 service(s) asynchronously. 2022-06-01 12:10:52,146 [DEBUG ] 23539 140046412805888 selector_events: Using selector: EpollSelector 2022-06-01 12:10:52,147 [DEBUG ] 23539 140045940647680 NotifyJSON: JSON POST URL: 2022-06-01 12:10:52,147 [DEBUG ] 23539 140045940647680 NotifyJSON: JSON Payload: {'version': '1.0', 'title': '', 'message': "Listen key expired: {'e': 'listenKeyExpired', 'E': 1654056652127}", 'type': 'info'} 2022-06-01 12:10:52,153 [DEBUG ] 23539 140046298318592 protocol: < TEXT '{"stream":"btcusdt@miniTicker","data":{"e":"24h...,"q":"11953661745.49"}}' [191 bytes] 2022-06-01 12:10:52,153 [DEBUG ] 23539 140046298318592 manager: BinanceWebSocketApiManager.is_stop_request(8ace05a5aa94-82ba-5b56-e41d-6a6fa0ca) 2022-06-01 12:10:52,153 [DEBUG ] 23539 140046298318592 manager: BinanceWebSocketApiManager.is_stop_as_crash_request(8ace05a5aa94-82ba-5b56-e41d-6a6fa0ca) 2022-06-01 12:10:52,153 [DEBUG ] 23539 140046298318592 manager: BinanceWebSocketApiManager.set_heartbeat(8ace05a5aa94-82ba-5b56-e41d-6a6fa0ca)

This time it lives over 10+ hours...

Please pay attention to the line with timestamp: 2022-06-01 12:10:51,641, it received inner asyncio.TimeoutError, and then got listenKeyExpired event at 2022-06-01 12:10:52,144.

Please let me know if need more information.

bobwng commented 2 years ago

Checked the logs again, the "Received inner asyncio.TimeoutError" occurred not only right before listenKeyExpired event, it appears in lots of place even in several hours before got that event.

bobwng commented 2 years ago

Recently I'm still frequently got listenKeyExpired event, and I changed the code to call create_stream() again after got that event. Meanwhile, it might send two listenKeyExpired events at almost same time, you should avoid to call create_stream() twice in that time.

Looks good in last whole week.

dima-dmytruk23 commented 1 year ago

@oliver-zehentleitner Any ideas?

amdescombes commented 1 year ago

Hello Oliver, I am trying to replace Binance-Futures with your library and I am get quite a few ListenKeyExpired messages, how should I handle them ? Any suggestions ? Thanks in advance

Regards Andre

netsesame commented 1 year ago

https://github.com/LUCIT-Systems-and-Development/unicorn-fy/issues/41 Exactly the same。。。

bobwng commented 1 year ago

Hello Oliver, I am trying to replace Binance-Futures with your library and I am get quite a few ListenKeyExpired messages, how should I handle them ? Any suggestions ? Thanks in advance

Regards Andre

Just FYI, I added some code like below, it works well in last month, you can base it to get your own version:

  elif event_type == "listenKeyExpired":
      listen_key_expired_timestamp = datetime.fromtimestamp(stream_data['E'] / 1000)
      self.logger.warning(f"Listen key expired at {listen_key_expired_timestamp}: {stream_data}")

      if self.listen_key_expired_timestamp is None \
              or listen_key_expired_timestamp - self.listen_key_expired_timestamp > timedelta(seconds=10):
          # Never expired or last expired time is 10 seconds ago
          self.listen_key_expired_timestamp = listen_key_expired_timestamp

          self.bw_api_manager.create_stream(
          ["arr"], ["!userData"], api_key=self.config.BINANCE_API_KEY, api_secret=self.config.BINANCE_API_SECRET_KEY
          )
  else:
      self.logger.warning(f"WARN: Not handled 'e' event: {stream_data}")
dima-dmytruk23 commented 1 year ago

Hello Oliver, I am trying to replace Binance-Futures with your library and I am get quite a few ListenKeyExpired messages, how should I handle them ? Any suggestions ? Thanks in advance Regards Andre

Just FYI, I added some code like below, it works well in last month, you can base it to get your own version:

  elif event_type == "listenKeyExpired":
      listen_key_expired_timestamp = datetime.fromtimestamp(stream_data['E'] / 1000)
      self.logger.warning(f"Listen key expired at {listen_key_expired_timestamp}: {stream_data}")

      if self.listen_key_expired_timestamp is None \
              or listen_key_expired_timestamp - self.listen_key_expired_timestamp > timedelta(seconds=10):
          # Never expired or last expired time is 10 seconds ago
          self.listen_key_expired_timestamp = listen_key_expired_timestamp

          self.bw_api_manager.create_stream(
          ["arr"], ["!userData"], api_key=self.config.BINANCE_API_KEY, api_secret=self.config.BINANCE_API_SECRET_KEY
          )
  else:
      self.logger.warning(f"WARN: Not handled 'e' event: {stream_data}")

@bobwng what will happen if, for example, an order is filled on the exchange before the creation, or at the time of the stream creation. the message is lost?

amdescombes commented 1 year ago

Hello Oliver, I am trying to replace Binance-Futures with your library and I am get quite a few ListenKeyExpired messages, how should I handle them ? Any suggestions ? Thanks in advance Regards Andre

Just FYI, I added some code like below, it works well in last month, you can base it to get your own version:

  elif event_type == "listenKeyExpired":
      listen_key_expired_timestamp = datetime.fromtimestamp(stream_data['E'] / 1000)
      self.logger.warning(f"Listen key expired at {listen_key_expired_timestamp}: {stream_data}")

      if self.listen_key_expired_timestamp is None \
              or listen_key_expired_timestamp - self.listen_key_expired_timestamp > timedelta(seconds=10):
          # Never expired or last expired time is 10 seconds ago
          self.listen_key_expired_timestamp = listen_key_expired_timestamp

          self.bw_api_manager.create_stream(
          ["arr"], ["!userData"], api_key=self.config.BINANCE_API_KEY, api_secret=self.config.BINANCE_API_SECRET_KEY
          )
  else:
      self.logger.warning(f"WARN: Not handled 'e' event: {stream_data}")

@bobwng what will happen if, for example, an order is filled on the exchange before the creation, or at the time of the stream creation. the message is lost?

Hello diva,

in my experience the message is lost and all hell starts to break lose on your bots :( Cheers

Andre

amdescombes commented 1 year ago

Hello Oliver, I am trying to replace Binance-Futures with your library and I am get quite a few ListenKeyExpired messages, how should I handle them ? Any suggestions ? Thanks in advance Regards Andre

Just FYI, I added some code like below, it works well in last month, you can base it to get your own version:

  elif event_type == "listenKeyExpired":
      listen_key_expired_timestamp = datetime.fromtimestamp(stream_data['E'] / 1000)
      self.logger.warning(f"Listen key expired at {listen_key_expired_timestamp}: {stream_data}")

      if self.listen_key_expired_timestamp is None \
              or listen_key_expired_timestamp - self.listen_key_expired_timestamp > timedelta(seconds=10):
          # Never expired or last expired time is 10 seconds ago
          self.listen_key_expired_timestamp = listen_key_expired_timestamp

          self.bw_api_manager.create_stream(
          ["arr"], ["!userData"], api_key=self.config.BINANCE_API_KEY, api_secret=self.config.BINANCE_API_SECRET_KEY
          )
  else:
      self.logger.warning(f"WARN: Not handled 'e' event: {stream_data}")

Hi Bob, thanks I will try your code, on the other hand I managed to keep away from those listenkeyexpired messages by getting the listenkey every 60 seconds ! Cheers Andre

amdescombes commented 1 year ago

Hello Oliver, I am trying to replace Binance-Futures with your library and I am get quite a few ListenKeyExpired messages, how should I handle them ? Any suggestions ? Thanks in advance Regards Andre

Just FYI, I added some code like below, it works well in last month, you can base it to get your own version:

  elif event_type == "listenKeyExpired":
      listen_key_expired_timestamp = datetime.fromtimestamp(stream_data['E'] / 1000)
      self.logger.warning(f"Listen key expired at {listen_key_expired_timestamp}: {stream_data}")

      if self.listen_key_expired_timestamp is None \
              or listen_key_expired_timestamp - self.listen_key_expired_timestamp > timedelta(seconds=10):
          # Never expired or last expired time is 10 seconds ago
          self.listen_key_expired_timestamp = listen_key_expired_timestamp

          self.bw_api_manager.create_stream(
          ["arr"], ["!userData"], api_key=self.config.BINANCE_API_KEY, api_secret=self.config.BINANCE_API_SECRET_KEY
          )
  else:
      self.logger.warning(f"WARN: Not handled 'e' event: {stream_data}")

Hi Bob,

a question about your code:

If I had previously started a thread to wait for messages. If I use a replace_stream will I need to stop the old thread and start a new one ?

Thanks Andre

bobwng commented 1 year ago

If I had previously started a thread to wait for messages. If I use a replace_stream will I need to stop the old thread and start a new one ?

I have no experience on replace_stream, per comments mentioned in the sample code below, looks like no need to stop the old stream manually:

https://github.com/LUCIT-Systems-and-Development/unicorn-binance-websocket-api/blob/010cb9d33dbf157b4662b9745fe1615790a0d8c9/example_stream_management.py#L68-L69

bobwng commented 1 year ago

thanks I will try your code, on the other hand I managed to keep away from those listenkeyexpired messages by getting the listenkey every 60 seconds !

That's great!

Just FYI that the lib should already have the keep alive related code, but not sure why it not works:

https://github.com/LUCIT-Systems-and-Development/unicorn-binance-websocket-api/blob/010cb9d33dbf157b4662b9745fe1615790a0d8c9/unicorn_binance_websocket_api/manager.py#L691-L692

dima-dmytruk23 commented 1 year ago

@bobwng @oliver-zehentleitner

    self.restclient.keepalive_listen_key(stream_id)

    def keepalive_listen_key(self,
                             stream_id=False,
                             api_key=False,
                             api_secret=False,
                             listen_key=False,
                             last_static_ping_listen_key=False):
            with self.threading_lock:
            self._init_vars(stream_id, api_key, api_secret, listen_key, last_static_ping_listen_key)
            return self._do_request("keepalive")

    def _do_request(self, action=False):
        if action == "keepalive":
            logger.info(f"BinanceWebSocketApiRestclient.keepalive_listen_key({str(self.listen_key_output)})")
            method = "put"
            try:
                response = self._request(method, self.path_userdata, False, {'listenKey': str(self.listen_key)})
                self.last_static_ping_listen_key = time.time()
                return response

Very strange logic

amdescombes commented 1 year ago

@bobwng @oliver-zehentleitner

    self.restclient.keepalive_listen_key(stream_id)

    def keepalive_listen_key(self,
                             stream_id=False,
                             api_key=False,
                             api_secret=False,
                             listen_key=False,
                             last_static_ping_listen_key=False):
            with self.threading_lock:
            self._init_vars(stream_id, api_key, api_secret, listen_key, last_static_ping_listen_key)
            return self._do_request("keepalive")

    def _do_request(self, action=False):
        if action == "keepalive":
            logger.info(f"BinanceWebSocketApiRestclient.keepalive_listen_key({str(self.listen_key_output)})")
            method = "put"
            try:
                response = self._request(method, self.path_userdata, False, {'listenKey': str(self.listen_key)})
                self.last_static_ping_listen_key = time.time()
                return response

Very strange logic

Yes, and I don't think it works, sometimes when I launch the bot, the first message it receives is a listenKeyExpired !!!

netsesame commented 1 year ago

@oliver-zehentleitner @amdescombes @bobwng @dima-dmytruk23 I think I have fixed the this bug. 微信图片_20220724141624 微信图片_20220724141640

code

import logging
import time
import threading
import os
import json
from termcolor import colored, cprint
from unicorn_fy.unicorn_fy import UnicornFy
from unicorn_binance_websocket_api.manager import BinanceWebSocketApiManager

# create instances of BinanceWebSocketApiManager
#binance_websocket_api_manager = BinanceWebSocketApiManager(exchange="binance.com-futures", output_default="UnicornFy",throw_exception_if_unrepairable=True)
binance_websocket_api_manager = BinanceWebSocketApiManager(exchange="binance.com-futures", throw_exception_if_unrepairable=True)

# configure api key and secret for binance.com for Alice
apiKey = "apiKey"
secret = "secret"
# create the userData streams
alice_stream_id = binance_websocket_api_manager.create_stream('arr', '!userData', stream_label="Alice",stream_buffer_name=True,api_key=apiKey, api_secret=secret)

info_stream = binance_websocket_api_manager.get_stream_list()

print(alice_stream_id)
print('status',info_stream[alice_stream_id]['status'])
print('stop_request',info_stream[alice_stream_id]['stop_request'])#停止请求
print('crash_request',info_stream[alice_stream_id]['crash_request'])#崩溃请求
print('kill_request',info_stream[alice_stream_id]['kill_request'])#杀死请求
print('reconnects',info_stream[alice_stream_id]['reconnects'])#重连次数

# print(binance_websocket_api_manager.get_stream_statistic(alice_stream_id))

# 结果转成JSON
def str2json(result):
    return UnicornFy.binance_com_futures_websocket(result)

def getdate2(t):
    '''时间戳转换为时间'''
    t1 = float(t)/1000
    t2 = time.localtime(t1)
    t3 = time.strftime("%Y-%m-%d %H:%M:%S", t2)
    return t3

# # https://docs.python.org/3/library/logging.html#logging-levels
logging.basicConfig(level=logging.DEBUG,
                    filename=os.path.basename(__file__) + '.log',
                    format="{asctime} [{levelname:8}] {process} {thread} {module}: {message}",
                    style="{")

# Python线程退出条件有以下几种:
# 1、线程内的函数语句执行完毕,线程自动结束
# 2、线程内的函数抛出未处理的异常

def print_stream_buffer_data(binance_websocket_api_manager, stream_id):

    side_aways ={ 
        "BUYLONG":"买入开多",
        "BUYSHORT":"买入平空",
        "SELLSHORT":"卖出开空",
        "SELLLONG":"卖出平多",
    }

    order_status = {
        'NEWNEW':"挂单未成交",
        'CANCELEDCANCELED':"撤单",
        'TRADEFILLED':"挂单已成交",
        'EXPIREDEXPIRED':"订单已过期",
        'TRADEPARTIALLY_FILLED':'部分成交'
    }

    trad_types = {
        "LIMIT":"限价单",
        "TAKE_PROFIT":"止盈止损单",
        "MARKET":"市价单" 
    }

    while True:

        try :
            #有停止请求,则返回True ,否则返回 'False'。
            if binance_websocket_api_manager.is_manager_stopping():
                print("遇到错误了,正常运行程序并退出程序")
                exit(0)
            oldest_stream_data_from_stream_buffer = binance_websocket_api_manager.pop_stream_data_from_stream_buffer(stream_id)

            if oldest_stream_data_from_stream_buffer is False:
                time.sleep(0.01)
            else:
                oldest_stream_data_from_stream = json.loads(oldest_stream_data_from_stream_buffer)
                print(oldest_stream_data_from_stream['e'])
                if oldest_stream_data_from_stream['e'] == "listenKeyExpired":
                    binance_websocket_api_manager.kill_stream(stream_id)
                    binance_websocket_api_manager.set_restart_request(stream_id)
                    #binance_websocket_api_manager._restart_stream(stream_id)

                else:
                    data = UnicornFy.binance_com_futures_websocket(oldest_stream_data_from_stream_buffer)
                    event_type = data["event_type"]
                    if event_type == "ORDER_TRADE_UPDATE":
                        #币种
                        symbol = data['symbol']
                        #方向
                        side = data['side']
                        #持仓方向
                        position_side = data['position_side']
                        #挂单价格
                        order_price = data['order_price']
                        #实际成交价格
                        order_avg_price = data['order_avg_price']
                        #挂单数量
                        order_quantity = data['order_quantity']
                        current_order_status = data['current_order_status']
                        current_execution_type =  data['current_execution_type']
                        transaction_time = getdate2( data['transaction_time'])

                        last_executed_price = data['last_executed_price']
                        #交易编号 ex android_mJlmVJJhRdpoL2fnSAhB
                        client_order_id =  data['client_order_id']
                        #交易ID  ex 60952023909
                        order_id =  data['order_id']
                        #这个目前没用
                        trade_id = data['trade_id']
                        #下单为 LIMIT  挂单止盈为TAKE_PROFIT
                        order_type = data['order_type']

                        trad_type = trad_types[order_type] 
                        side_away = side_aways[side+position_side]
                        acction = order_status[current_execution_type + current_order_status]

                        cprint(f"订单状态:{acction}  信号状态:{event_type} 币种:{symbol} 下单动作:{side_away} 挂单价格:{order_price} 成交价格:{order_avg_price} 平仓价格:{last_executed_price} 挂单数量:{order_quantity} 时间:{transaction_time}",
                            'blue', 'on_white')

        except BaseException as e :
            print(e)

worker_thread = threading.Thread(target=print_stream_buffer_data, args=(binance_websocket_api_manager,alice_stream_id))
worker_thread.start()
dima-dmytruk23 commented 1 year ago

@netsesame what will happen if, for example, an order is filled on the exchange before the creation, or at the time of the stream creation. the message is lost?

I see 2 solutions to the problem:

  1. create 2 streams and periodically restart them at different timings
  2. update the key constantly.

The first option is more reliable, in my opinion.

hiliev commented 1 year ago

Hi, I'm fighting the same issue here with the user data stream stopping after listenKeyExpired is received. In my case, I have two clients connected to the same Binance account and when one of them calls stop_stream() (as part of its cleanup), the listen key gets deleted (there is a call to self.delete_listen_key_by_stream_id(stream_id) inside stop_stream()). If I understand the Binance docs correctly, there could only be a single listen key per account active at any given moment and its shared between all clients:

POST /fapi/v1/listenKey

Start a new user data stream. The stream will close after 60 minutes unless a keepalive is sent. If the account has an active listenKey, that listenKey will be returned and its validity will be extended for 60 minutes. [emphasis mine]

So, when the second client deletes the listen key before exiting, the first client will no longer receive messages on that listen key. Binance will not disconnect the websocket - it will simply stop sending data.

I tried calling replace_stream() when listenKeyExpired is received, but it does not solve the problem. For now, the only local remedy I see is to comment the delete call in the manager and let the key expire on its own if no other client is keeping it alive.

oliver-zehentleitner commented 1 year ago

Thanks for the good reports and analysis.

stop_stream() has from now on a new parameter called delete_listen_key. So it is possible to disable the deletion on stop_stream(). replace_stream() always calls stop_stream() with delete_listen_key=False from now on.

Thanks @hiliev

asyncio.TimeoutError is not a fail, its just a timeout if we wait to long to receive a message we get an timeout, so we can break the eventloop and close streams which are receiving no data. Without that userData streams were not closeable without a received data through websocket.

I set the interval from refreshing the listen_key to 10 min, before it was 30 which is equal to lifetime window.

If the problem persists, we can create a way to set the interval time manually. If necessary, the code for "keep alive" must be revised.

oliver-zehentleitner commented 1 year ago

lets continue here: https://github.com/LUCIT-Systems-and-Development/unicorn-binance-websocket-api/issues/301