crypto-ws-api 2.0.20__tar.gz → 2.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,13 @@
1
+ ## 2.1.0 - 2025-06-22
2
+ ✨ refactor(ws_session.py): simplify `ws_login` and `request` methods by removing redundant `send_api_key` parameter.
3
+
4
+ ## 2.0.21 - 2025-06-22
5
+ 🔧 fix(README.md): Improve documentation layout for better readability
6
+ 🔧 fix(ws_session.py): Handle `asyncio.CancelledError` gracefully in `start_wss` method
7
+ 🔧 fix(ws_session.py): Replace `asyncio.CancelledError` with `KeyboardInterrupt` exception in `handle_request` method
8
+ 🔧 fix(demo.py): Remove unnecessary `asyncio.CancelledError` handling to clean up error logging
9
+ 🔧 fix(ws_api.toml.template): Update testnet URL for Binance websocket API
10
+
1
11
  ## 2.0.20 - 2025-04-24
2
12
  * On `Binance` now API key type [Ed25519](https://www.binance.com/en/support/faq/detail/6b9a63f1e3384cf48a2eedb82767a69a) is used instead of `HMAC`
3
13
  ✨ feat(ws_session): implement `compose_binance_ws_auth` for Binance WebSocket authentication
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: crypto-ws-api
3
- Version: 2.0.20
3
+ Version: 2.1.0
4
4
  Summary: Crypto WS API connector for ASYNC requests
5
5
  Author-email: Jerry Fedorenko <jerry.fedorenko@yahoo.com>
6
6
  Requires-Python: >=3.10
@@ -26,12 +26,13 @@ Project-URL: Source, https://github.com/DogsTailFarmer/crypto-ws-api
26
26
  <h3 align="center">Provides of connection management, keepalive and rate limits control</h3>
27
27
 
28
28
  ***
29
- <a href="https://pypi.org/project/crypto-ws-api/"><img src="https://img.shields.io/pypi/v/crypto-ws-api" alt="PyPI version"></a>
30
- <a href="https://codeclimate.com/github/DogsTailFarmer/crypto-ws-api/maintainability"><img src="https://api.codeclimate.com/v1/badges/2d2a654ba393eb88d911/maintainability" /></a>
29
+ <h1 align="center"><a href="https://pypi.org/project/crypto-ws-api/"><img src="https://img.shields.io/pypi/v/crypto-ws-api" alt="PyPI version"></a>
31
30
  <a href="https://app.deepsource.com/gh/DogsTailFarmer/crypto-ws-api/?ref=repository-badge}" target="_blank"><img alt="DeepSource" title="DeepSource" src="https://app.deepsource.com/gh/DogsTailFarmer/crypto-ws-api.svg/?label=resolved+issues&token=TXghPzbi0YWhkCLU8Q1tmDyQ"/></a>
32
31
  <a href="https://app.deepsource.com/gh/DogsTailFarmer/crypto-ws-api/?ref=repository-badge}" target="_blank"><img alt="DeepSource" title="DeepSource" src="https://app.deepsource.com/gh/DogsTailFarmer/crypto-ws-api.svg/?label=active+issues&token=TXghPzbi0YWhkCLU8Q1tmDyQ"/></a>
33
32
  <a href="https://sonarcloud.io/summary/new_code?id=DogsTailFarmer_crypto-ws-api" target="_blank"><img alt="sonarcloud" title="sonarcloud" src="https://sonarcloud.io/api/project_badges/measure?project=DogsTailFarmer_crypto-ws-api&metric=alert_status"/></a>
34
33
  <a href="https://pepy.tech/project/crypto-ws-api" target="_blank"><img alt="Downloads" title="Downloads" src="https://static.pepy.tech/badge/crypto-ws-api"/></a>
34
+ </h1>
35
+
35
36
  ***
36
37
  For :heavy_check_mark:[Binance](https://accounts.binance.com/en/register?ref=FXQ6HY5O), :heavy_check_mark:[OKX](https://okx.com/join/2607649), :heavy_check_mark:[Bitfinex](https://www.bitfinex.com/sign-up?refcode=v_4az2nCP), :heavy_check_mark:[HTX](https://www.htx.com/invite/en-us/1f?invite_code=9uaw3223)
37
38
  ***
@@ -5,12 +5,13 @@
5
5
  <h3 align="center">Provides of connection management, keepalive and rate limits control</h3>
6
6
 
7
7
  ***
8
- <a href="https://pypi.org/project/crypto-ws-api/"><img src="https://img.shields.io/pypi/v/crypto-ws-api" alt="PyPI version"></a>
9
- <a href="https://codeclimate.com/github/DogsTailFarmer/crypto-ws-api/maintainability"><img src="https://api.codeclimate.com/v1/badges/2d2a654ba393eb88d911/maintainability" /></a>
8
+ <h1 align="center"><a href="https://pypi.org/project/crypto-ws-api/"><img src="https://img.shields.io/pypi/v/crypto-ws-api" alt="PyPI version"></a>
10
9
  <a href="https://app.deepsource.com/gh/DogsTailFarmer/crypto-ws-api/?ref=repository-badge}" target="_blank"><img alt="DeepSource" title="DeepSource" src="https://app.deepsource.com/gh/DogsTailFarmer/crypto-ws-api.svg/?label=resolved+issues&token=TXghPzbi0YWhkCLU8Q1tmDyQ"/></a>
11
10
  <a href="https://app.deepsource.com/gh/DogsTailFarmer/crypto-ws-api/?ref=repository-badge}" target="_blank"><img alt="DeepSource" title="DeepSource" src="https://app.deepsource.com/gh/DogsTailFarmer/crypto-ws-api.svg/?label=active+issues&token=TXghPzbi0YWhkCLU8Q1tmDyQ"/></a>
12
11
  <a href="https://sonarcloud.io/summary/new_code?id=DogsTailFarmer_crypto-ws-api" target="_blank"><img alt="sonarcloud" title="sonarcloud" src="https://sonarcloud.io/api/project_badges/measure?project=DogsTailFarmer_crypto-ws-api&metric=alert_status"/></a>
13
12
  <a href="https://pepy.tech/project/crypto-ws-api" target="_blank"><img alt="Downloads" title="Downloads" src="https://static.pepy.tech/badge/crypto-ws-api"/></a>
13
+ </h1>
14
+
14
15
  ***
15
16
  For :heavy_check_mark:[Binance](https://accounts.binance.com/en/register?ref=FXQ6HY5O), :heavy_check_mark:[OKX](https://okx.com/join/2607649), :heavy_check_mark:[Bitfinex](https://www.bitfinex.com/sign-up?refcode=v_4az2nCP), :heavy_check_mark:[HTX](https://www.htx.com/invite/en-us/1f?invite_code=9uaw3223)
16
17
  ***
@@ -13,7 +13,7 @@ __maintainer__ = "Jerry Fedorenko"
13
13
  __contact__ = "https://github.com/DogsTailFarmer"
14
14
  __email__ = "jerry.fedorenko@yahoo.com"
15
15
  __credits__ = ["https://github.com/DanyaSWorlD"]
16
- __version__ = "2.0.20"
16
+ __version__ = "2.1.0"
17
17
 
18
18
  from pathlib import Path
19
19
  import shutil
@@ -66,8 +66,6 @@ async def get_time(user_session: UserWSSession, _trade_id):
66
66
  )
67
67
  if res is None:
68
68
  logger.warning(CONST_1)
69
- except asyncio.CancelledError:
70
- pass # Task cancellation should not be logged as an error
71
69
  except Exception as _ex:
72
70
  logger.error(CONST_2, _ex)
73
71
  else:
@@ -87,8 +85,6 @@ async def current_average_price(user_session: UserWSSession, _trade_id):
87
85
  )
88
86
  if res is None:
89
87
  logger.warning(CONST_1)
90
- except asyncio.CancelledError:
91
- pass # Task cancellation should not be logged as an error
92
88
  except Exception as _ex:
93
89
  logger.error(CONST_2, _ex)
94
90
  else:
@@ -105,8 +101,6 @@ async def account_information(user_session: UserWSSession, _trade_id):
105
101
  )
106
102
  if res is None:
107
103
  logger.warning(CONST_1)
108
- except asyncio.CancelledError:
109
- pass # Task cancellation should not be logged as an error
110
104
  except Exception as _ex:
111
105
  logger.error(CONST_2, _ex)
112
106
  else:
@@ -1,12 +1,12 @@
1
1
  # Parameters for crypto-ws-api connector
2
2
  # Copyright © 2023-2025 Jerry Fedorenko aka VM
3
- # __version__ = "2.0.20"
3
+ # __version__ = "2.0.21"
4
4
 
5
5
  # region endpoint
6
6
  [endpoint]
7
7
  [endpoint.binance]
8
8
  ws_api = 'wss://ws-api.binance.com:443/ws-api/v3'
9
- ws_api_test = 'wss://testnet.binance.vision/ws-api/v3'
9
+ ws_api_test = 'wss://ws-api.testnet.binance.vision:9443/ws-api/v3'
10
10
  # endregion
11
11
 
12
12
  # region Binance accounts
@@ -191,32 +191,34 @@ class UserWSS:
191
191
  else:
192
192
  logger.warning(f"UserWSS: {self.ws_id}: {msg}")
193
193
  await self.stop()
194
- logger.warning(f"UserWSS: {self.ws_id}: _ws_listener stopped")
195
- await self.stop()
196
194
 
197
195
  async def start_wss(self):
198
- async for self._ws in connect(
199
- self.endpoint,
200
- logger=self.logger,
201
- ping_interval=None if self.exchange in ('binance', 'huobi') else 20
202
- ):
203
- try:
204
- await self._ws_listener()
205
- except ConnectionClosed as ex:
206
- if ex.rcvd and ex.rcvd.code == 4000:
207
- logger.info(f"WSS closed for {self.ws_id}")
208
- break
209
- else:
210
- self.operational_status = False
211
- [task.cancel() for task in self.tasks if not task.done()]
212
- self.tasks.clear()
213
- logger.warning(f"Restart UserWSS for {self.ws_id}")
214
- continue
215
- except Exception as ex:
216
- logger.error(f"UserWSS start other exception: {ex}")
196
+ try:
197
+ async for self._ws in connect(
198
+ self.endpoint,
199
+ logger=self.logger,
200
+ ping_interval=None if self.exchange in ('binance', 'huobi') else 20
201
+ ):
202
+ try:
203
+ await self._ws_listener()
204
+ except ConnectionClosed as ex:
205
+ if ex.rcvd and ex.rcvd.code == 4000:
206
+ logger.info(f"WSS closed for {self.ws_id}")
207
+ break
208
+ else:
209
+ self.operational_status = False
210
+ [task.cancel() for task in self.tasks if not task.done()]
211
+ self.tasks.clear()
212
+ logger.warning(f"Restart UserWSS for {self.ws_id}")
213
+ continue
214
+ except Exception as ex:
215
+ logger.error(f"UserWSS start other exception: {ex}")
216
+ except asyncio.CancelledError:
217
+ await self.stop()
218
+ raise
217
219
 
218
220
  async def ws_login(self):
219
- res = await self.request(CONST_WS_START, send_api_key=True)
221
+ res = await self.request(CONST_WS_START)
220
222
  if res is None:
221
223
  logger.warning(f"UserWSS: Not 'logged in' for {self.ws_id}")
222
224
  await self.stop()
@@ -229,7 +231,7 @@ class UserWSS:
229
231
  self.tasks_manage(self._keepalive(), f"keepalive-{self.ws_id}")
230
232
  logger.info(f"UserWSS: 'logged in' for {self.ws_id}")
231
233
 
232
- async def request(self, method, _params=None, send_api_key=False, _signed=False):
234
+ async def request(self, method, _params=None, _signed=False):
233
235
  """
234
236
  Construct and handling request/response to WS API endpoint, use a description of the methods on
235
237
  https://developers.binance.com/docs/binance-spot-api-docs/websocket-api
@@ -251,7 +253,7 @@ class UserWSS:
251
253
  else:
252
254
  _id = ''.join(e for e in r_id if e.isalnum())[-ID_LEN_LIMIT.get(self.exchange, 64):]
253
255
  await self._ws.send(
254
- json.dumps(self.compose_request(_id, send_api_key, method, params, _signed))
256
+ json.dumps(self.compose_request(_id, method, params, _signed))
255
257
  )
256
258
  await asyncio.sleep(0)
257
259
  try:
@@ -260,8 +262,6 @@ class UserWSS:
260
262
  logger.warning(f"UserWSS: get response timeout error: {self.ws_id}")
261
263
  await self.stop()
262
264
  return None
263
- except asyncio.CancelledError:
264
- return None
265
265
  else:
266
266
  return res
267
267
 
@@ -275,7 +275,7 @@ class UserWSS:
275
275
  return self._response_pool.pop(f"NoneResponse{self.ws_id}", None)
276
276
  return None
277
277
 
278
- def compose_request(self, _id, send_api_key, method, params, signed):
278
+ def compose_request(self, _id, method, params, signed):
279
279
  if self.exchange == "binance":
280
280
  return self._compose_binance_request(_id, method, params, signed)
281
281
  elif self.exchange == "okx":
@@ -400,9 +400,10 @@ class UserWSS:
400
400
  if msg.get('code') == 200 or msg.get('status') == 'ok':
401
401
  return msg
402
402
 
403
- await self.htx_error_handle(msg)
403
+ self.htx_error_handle(msg)
404
+ return None
404
405
 
405
- async def htx_error_handle(self, msg):
406
+ def htx_error_handle(self, msg):
406
407
  if msg.get('code') == 500:
407
408
  logger.warning(f"An issue occurred on exchange's side: {msg}")
408
409
  elif msg.get('code') in {429, 4000}:
@@ -526,7 +527,6 @@ class UserWSSession:
526
527
  trade_id: str,
527
528
  method: str,
528
529
  _params=None,
529
- send_api_key=False,
530
530
  _signed=False,
531
531
  ):
532
532
 
@@ -566,8 +566,8 @@ class UserWSSession:
566
566
  duration += DELAY
567
567
 
568
568
  try:
569
- return await user_wss.request(method=method, _params=_params, send_api_key=send_api_key, _signed=_signed)
570
- except asyncio.CancelledError:
569
+ return await user_wss.request(method=method, _params=_params, _signed=_signed)
570
+ except KeyboardInterrupt:
571
571
  pass # Task cancellation should not be logged as an error
572
572
  except Exception as ex:
573
573
  logger.error(f"crypto_ws_api.ws_session.handle_request(): {ex}")
File without changes