crypto-ws-api 2.0.6__tar.gz → 2.0.7__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,7 @@
1
+ ## 2.0.7 - 2024-03-25
2
+ ### Update
3
+ * Refactoring and some minor fixes
4
+
1
5
  ## 2.0.6 - 2024-01-05
2
6
  ### Update
3
7
  * replacing json with ujson to improve performance
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: crypto-ws-api
3
- Version: 2.0.6
3
+ Version: 2.0.7
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.8
@@ -37,7 +37,7 @@ For :heavy_check_mark:Binance, :heavy_check_mark:OKX, :heavy_check_mark:Bitfinex
37
37
 
38
38
  ## Features
39
39
  Lightweight and efficient solution to utilize of all available methods** provided through the:
40
- * [Binance Websocket API v3](https://developers.binance.com/docs/binance-trading-api/websocket_api)
40
+ * [Binance Websocket API v3](https://binance-docs.github.io/apidocs/websocket_api/en)
41
41
  * [OKX Websocket API v5](https://www.okx.com/docs-v5/en/#overview-websocket)
42
42
  * [Bitfinex Websocket Inputs](https://docs.bitfinex.com/reference/ws-auth-input)
43
43
 
@@ -222,7 +222,5 @@ If you send a request in this state, the answer will be `None`
222
222
  *In any case, you are protected from exceeding limits and blocking for this reason*
223
223
 
224
224
  ## Donate
225
- *BNB*, *BUSD*, *USDT* (BEP20) 0x5b52c6ba862b11318616ee6cef64388618318b92
226
-
227
- *USDT* (TRC20) TP1Y43dpY7rrRyTSLaSKDZmFirqvRcpopC
225
+ *USDT* (TRC20) TU3kagV9kxbjuUmEi6bUym5MTXjeM7Tm8K
228
226
 
@@ -17,7 +17,7 @@ For :heavy_check_mark:Binance, :heavy_check_mark:OKX, :heavy_check_mark:Bitfinex
17
17
 
18
18
  ## Features
19
19
  Lightweight and efficient solution to utilize of all available methods** provided through the:
20
- * [Binance Websocket API v3](https://developers.binance.com/docs/binance-trading-api/websocket_api)
20
+ * [Binance Websocket API v3](https://binance-docs.github.io/apidocs/websocket_api/en)
21
21
  * [OKX Websocket API v5](https://www.okx.com/docs-v5/en/#overview-websocket)
22
22
  * [Bitfinex Websocket Inputs](https://docs.bitfinex.com/reference/ws-auth-input)
23
23
 
@@ -202,6 +202,4 @@ If you send a request in this state, the answer will be `None`
202
202
  *In any case, you are protected from exceeding limits and blocking for this reason*
203
203
 
204
204
  ## Donate
205
- *BNB*, *BUSD*, *USDT* (BEP20) 0x5b52c6ba862b11318616ee6cef64388618318b92
206
-
207
- *USDT* (TRC20) TP1Y43dpY7rrRyTSLaSKDZmFirqvRcpopC
205
+ *USDT* (TRC20) TU3kagV9kxbjuUmEi6bUym5MTXjeM7Tm8K
@@ -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.6"
16
+ __version__ = "2.0.7"
17
17
 
18
18
  from pathlib import Path
19
19
  import shutil
@@ -176,7 +176,6 @@ class UserWSS:
176
176
  except asyncio.TimeoutError:
177
177
  logger.warning(f"UserWSS: get response timeout error: {self.ws_id}")
178
178
  await self.stop()
179
- return None
180
179
  except asyncio.CancelledError:
181
180
  pass # Task cancellation should not be logged as an error
182
181
  else:
@@ -193,53 +192,59 @@ class UserWSS:
193
192
  return self._response_pool.pop(f"NoneResponse{self.ws_id}", None)
194
193
 
195
194
  def compose_request(self, _id, api_key, method, params, signed):
196
- req = None
197
195
  if self.exchange == "binance":
198
- req = {"id": _id, "method": method}
199
- if (api_key or signed) and not params:
200
- params = {}
201
- if api_key:
202
- params["apiKey"] = self._api_key
203
- if signed:
204
- params["timestamp"] = int(time.time() * 1000)
205
- payload = '&'.join(f"{key}={value}" for key, value in dict(sorted(params.items())).items())
206
- params["signature"] = generate_signature('binance_ws', self._api_secret, payload)
207
- if params:
208
- req["params"] = params
196
+ return self._compose_binance_request(_id, api_key, method, params, signed)
209
197
  elif self.exchange == "okx":
210
- if method == CONST_3:
211
- # https://www.okx.com/docs-v5/en/?python#overview-websocket-connect
212
- ts = int(time.time())
213
- signature_payload = f"{ts}GET/users/self/verify"
214
- signature = generate_signature(self.exchange, self._api_secret, signature_payload)
215
- # Login on account
216
- req = {"op": 'login',
217
- "args": [{"apiKey": self._api_key,
218
- "passphrase": self._passphrase,
219
- "timestamp": ts,
220
- "sign": signature}
221
- ]
222
- }
223
- else:
224
- req = {"id": _id, "op": method, "args": params if isinstance(params, list) else [params]}
198
+ return self._compose_okx_request(_id, method, params)
225
199
  elif self.exchange == 'bitfinex':
226
- if method == CONST_3:
227
- ts = int(time.time() * 1000)
228
- data = f"AUTH{ts}"
229
- req = {
230
- 'event': "auth",
231
- 'apiKey': self._api_key,
232
- 'authSig': generate_signature(self.exchange, self._api_secret, data),
233
- 'authPayload': data,
234
- 'authNonce': ts,
235
- 'filter': ['trading']
236
- }
237
- else:
238
- if method == 'on':
239
- params.update({"meta": {"aff_code": "v_4az2nCP"}})
240
- req = [0, method, _id, params]
200
+ return self._compose_bitfinex_request(_id, method, params)
201
+ else:
202
+ raise ValueError(f"Unsupported exchange: {self.exchange}")
203
+
204
+ def _compose_binance_request(self, _id, api_key, method, params, signed):
205
+ req = {"id": _id, "method": method}
206
+ params = params or {}
207
+ if api_key:
208
+ params["apiKey"] = self._api_key
209
+ if signed:
210
+ params["timestamp"] = int(time.time() * 1000)
211
+ payload = '&'.join(f"{key}={value}" for key, value in sorted(params.items()))
212
+ params["signature"] = generate_signature('binance_ws', self._api_secret, payload)
213
+ if params:
214
+ req["params"] = params
241
215
  return req
242
216
 
217
+ def _compose_okx_request(self, _id, method, params):
218
+ if method == CONST_3:
219
+ ts = int(time.time())
220
+ signature_payload = f"{ts}GET/users/self/verify"
221
+ signature = generate_signature(self.exchange, self._api_secret, signature_payload)
222
+ return {
223
+ "op": 'login',
224
+ "args": [
225
+ {"apiKey": self._api_key, "passphrase": self._passphrase, "timestamp": ts, "sign": signature}
226
+ ]
227
+ }
228
+ else:
229
+ return {"id": _id, "op": method, "args": params if isinstance(params, list) else [params]}
230
+
231
+ def _compose_bitfinex_request(self, _id, method, params):
232
+ if method == CONST_3:
233
+ ts = int(time.time() * 1000)
234
+ data = f"AUTH{ts}"
235
+ return {
236
+ 'event': "auth",
237
+ 'apiKey': self._api_key,
238
+ 'authSig': generate_signature(self.exchange, self._api_secret, data),
239
+ 'authPayload': data,
240
+ 'authNonce': ts,
241
+ 'filter': ['trading']
242
+ }
243
+ else:
244
+ if method == 'on':
245
+ params.update({"meta": {"aff_code": "v_4az2nCP"}})
246
+ return [0, method, _id, params]
247
+
243
248
  async def _keepalive(self, interval=10):
244
249
  while self.operational_status is not None:
245
250
  if self.request_limit_reached and (int(time.time() * 1000) - self._retry_after >= 0):
@@ -291,40 +296,60 @@ class UserWSS:
291
296
  elif self.exchange == 'bitfinex':
292
297
  return await self.bitfinex_error_handle(msg)
293
298
 
299
+ #region BitfinexErrorHandle
294
300
  async def bitfinex_error_handle(self, msg):
295
301
  if isinstance(msg, dict):
296
- if msg.get('event') == 'info' and not msg.get('platform', {}).get('status'):
297
- logger.warning(f"UserWSS Bitfinex platform in maintenance mode: {msg}")
298
- await self.stop()
299
- if msg.get('event') == 'auth' and msg.get('status') == "OK":
300
- return msg
301
- if msg.get('event') == 'info' and msg.get('version') != 2:
302
- logger.critical('Bitfinex WSS platform: version change detected')
303
- # sourcery skip: merge-nested-ifs
304
- if msg.get('code'):
305
- if msg.get('code') == 10305:
306
- logger.warning('UserWSS Bitfinex: Reached limit of open channels')
307
- self._retry_after = int((time.time() + TIMEOUT) * 1000)
308
- self.request_limit_reached = True
309
- logger.warning(f"Malformed request for {self.ws_id}: {msg}")
310
- return None
311
- return 'pass'
302
+ return await self._handle_dict_message(msg)
312
303
  elif isinstance(msg, list) and msg[1] == 'n' and msg[2][1] in ('on-req', 'oc-req', 'oc_multi-req'):
313
- msg = {"id": msg[2][2],
314
- "data": [msg[2][0],
315
- msg[2][1],
316
- None,
317
- None,
318
- [msg[2][4]] if msg[2][1] == 'on-req' else msg[2][4],
319
- None,
320
- msg[2][6],
321
- msg[2][7]
322
- ]
323
- }
324
- return msg
304
+ return self._transform_list_message(msg)
325
305
  else:
326
306
  return 'pass'
327
307
 
308
+ async def _handle_dict_message(self, msg):
309
+ event = msg.get('event')
310
+ if event == 'info':
311
+ return await self._handle_info_event(msg)
312
+ elif event == 'auth':
313
+ return msg if msg.get('status') == "OK" else None
314
+ elif msg.get('code'):
315
+ return await self._handle_error_code(msg)
316
+ return 'pass'
317
+
318
+ async def _handle_info_event(self, msg):
319
+ if not msg.get('platform', {}).get('status'):
320
+ logger.warning(f"UserWSS Bitfinex platform in maintenance mode: {msg}")
321
+ await self.stop()
322
+ elif msg.get('version') != 2:
323
+ logger.critical('Bitfinex WSS platform: version change detected')
324
+ return 'pass'
325
+
326
+ async def _handle_error_code(self, msg):
327
+ code = msg.get('code')
328
+ if code == 10305:
329
+ logger.warning('UserWSS Bitfinex: Reached limit of open channels')
330
+ self._retry_after = int((time.time() + TIMEOUT) * 1000)
331
+ self.request_limit_reached = True
332
+ else:
333
+ logger.warning(f"Malformed request for {self.ws_id}: {msg}")
334
+ return None
335
+
336
+ @staticmethod
337
+ def _transform_list_message(msg):
338
+ return {
339
+ "id": msg[2][2],
340
+ "data": [
341
+ msg[2][0],
342
+ msg[2][1],
343
+ None,
344
+ None,
345
+ [msg[2][4]] if msg[2][1] == 'on-req' else msg[2][4],
346
+ None,
347
+ msg[2][6],
348
+ msg[2][7]
349
+ ]
350
+ }
351
+ #endregion
352
+
328
353
  async def okx_error_handle(self, msg):
329
354
  if msg.get('code') == '1':
330
355
  logger.warning(f"Operation failed: {msg}")
File without changes