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.
- {crypto_ws_api-2.0.20 → crypto_ws_api-2.1.0}/CHANGELOG.md +10 -0
- {crypto_ws_api-2.0.20 → crypto_ws_api-2.1.0}/PKG-INFO +4 -3
- {crypto_ws_api-2.0.20 → crypto_ws_api-2.1.0}/README.md +3 -2
- {crypto_ws_api-2.0.20 → crypto_ws_api-2.1.0}/crypto_ws_api/__init__.py +1 -1
- {crypto_ws_api-2.0.20 → crypto_ws_api-2.1.0}/crypto_ws_api/demo.py +0 -6
- {crypto_ws_api-2.0.20 → crypto_ws_api-2.1.0}/crypto_ws_api/ws_api.toml.template +2 -2
- {crypto_ws_api-2.0.20 → crypto_ws_api-2.1.0}/crypto_ws_api/ws_session.py +32 -32
- {crypto_ws_api-2.0.20 → crypto_ws_api-2.1.0}/.deepsource.toml +0 -0
- {crypto_ws_api-2.0.20 → crypto_ws_api-2.1.0}/LICENSE.md +0 -0
- {crypto_ws_api-2.0.20 → crypto_ws_api-2.1.0}/pyproject.toml +0 -0
- {crypto_ws_api-2.0.20 → crypto_ws_api-2.1.0}/requirements.txt +0 -0
|
@@ -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
|
|
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
|
|
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.
|
|
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
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
403
|
+
self.htx_error_handle(msg)
|
|
404
|
+
return None
|
|
404
405
|
|
|
405
|
-
|
|
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,
|
|
570
|
-
except
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|