unicex 0.17.9__tar.gz → 0.17.11__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.
Files changed (123) hide show
  1. {unicex-0.17.9/unicex.egg-info → unicex-0.17.11}/PKG-INFO +1 -1
  2. {unicex-0.17.9 → unicex-0.17.11}/pyproject.toml +1 -1
  3. {unicex-0.17.9 → unicex-0.17.11}/unicex/_base/websocket.py +18 -3
  4. unicex-0.17.11/unicex/kucoin/websocket_manager.py +121 -0
  5. {unicex-0.17.9 → unicex-0.17.11/unicex.egg-info}/PKG-INFO +1 -1
  6. unicex-0.17.9/unicex/kucoin/websocket_manager.py +0 -11
  7. {unicex-0.17.9 → unicex-0.17.11}/LICENSE +0 -0
  8. {unicex-0.17.9 → unicex-0.17.11}/README.md +0 -0
  9. {unicex-0.17.9 → unicex-0.17.11}/setup.cfg +0 -0
  10. {unicex-0.17.9 → unicex-0.17.11}/unicex/__init__.py +0 -0
  11. {unicex-0.17.9 → unicex-0.17.11}/unicex/_abc/__init__.py +0 -0
  12. {unicex-0.17.9 → unicex-0.17.11}/unicex/_abc/exchange_info.py +0 -0
  13. {unicex-0.17.9 → unicex-0.17.11}/unicex/_abc/uni_client.py +0 -0
  14. {unicex-0.17.9 → unicex-0.17.11}/unicex/_abc/uni_websocket_manager.py +0 -0
  15. {unicex-0.17.9 → unicex-0.17.11}/unicex/_base/__init__.py +0 -0
  16. {unicex-0.17.9 → unicex-0.17.11}/unicex/_base/client.py +0 -0
  17. {unicex-0.17.9 → unicex-0.17.11}/unicex/aster/__init__.py +0 -0
  18. {unicex-0.17.9 → unicex-0.17.11}/unicex/aster/adapter.py +0 -0
  19. {unicex-0.17.9 → unicex-0.17.11}/unicex/aster/client.py +0 -0
  20. {unicex-0.17.9 → unicex-0.17.11}/unicex/aster/exchange_info.py +0 -0
  21. {unicex-0.17.9 → unicex-0.17.11}/unicex/aster/uni_client.py +0 -0
  22. {unicex-0.17.9 → unicex-0.17.11}/unicex/aster/uni_websocket_manager.py +0 -0
  23. {unicex-0.17.9 → unicex-0.17.11}/unicex/aster/user_websocket.py +0 -0
  24. {unicex-0.17.9 → unicex-0.17.11}/unicex/aster/websocket_manager.py +0 -0
  25. {unicex-0.17.9 → unicex-0.17.11}/unicex/binance/__init__.py +0 -0
  26. {unicex-0.17.9 → unicex-0.17.11}/unicex/binance/adapter.py +0 -0
  27. {unicex-0.17.9 → unicex-0.17.11}/unicex/binance/client.py +0 -0
  28. {unicex-0.17.9 → unicex-0.17.11}/unicex/binance/exchange_info.py +0 -0
  29. {unicex-0.17.9 → unicex-0.17.11}/unicex/binance/uni_client.py +0 -0
  30. {unicex-0.17.9 → unicex-0.17.11}/unicex/binance/uni_websocket_manager.py +0 -0
  31. {unicex-0.17.9 → unicex-0.17.11}/unicex/binance/user_websocket.py +0 -0
  32. {unicex-0.17.9 → unicex-0.17.11}/unicex/binance/websocket_manager.py +0 -0
  33. {unicex-0.17.9 → unicex-0.17.11}/unicex/bingx/__init__.py +0 -0
  34. {unicex-0.17.9 → unicex-0.17.11}/unicex/bingx/adapter.py +0 -0
  35. {unicex-0.17.9 → unicex-0.17.11}/unicex/bingx/client.py +0 -0
  36. {unicex-0.17.9 → unicex-0.17.11}/unicex/bingx/exchange_info.py +0 -0
  37. {unicex-0.17.9 → unicex-0.17.11}/unicex/bingx/uni_client.py +0 -0
  38. {unicex-0.17.9 → unicex-0.17.11}/unicex/bingx/uni_websocket_manager.py +0 -0
  39. {unicex-0.17.9 → unicex-0.17.11}/unicex/bingx/user_websocket.py +0 -0
  40. {unicex-0.17.9 → unicex-0.17.11}/unicex/bingx/websocket_manager.py +0 -0
  41. {unicex-0.17.9 → unicex-0.17.11}/unicex/bitget/__init__.py +0 -0
  42. {unicex-0.17.9 → unicex-0.17.11}/unicex/bitget/adapter.py +0 -0
  43. {unicex-0.17.9 → unicex-0.17.11}/unicex/bitget/client.py +0 -0
  44. {unicex-0.17.9 → unicex-0.17.11}/unicex/bitget/exchange_info.py +0 -0
  45. {unicex-0.17.9 → unicex-0.17.11}/unicex/bitget/uni_client.py +0 -0
  46. {unicex-0.17.9 → unicex-0.17.11}/unicex/bitget/uni_websocket_manager.py +0 -0
  47. {unicex-0.17.9 → unicex-0.17.11}/unicex/bitget/user_websocket.py +0 -0
  48. {unicex-0.17.9 → unicex-0.17.11}/unicex/bitget/websocket_manager.py +0 -0
  49. {unicex-0.17.9 → unicex-0.17.11}/unicex/bybit/__init__.py +0 -0
  50. {unicex-0.17.9 → unicex-0.17.11}/unicex/bybit/adapter.py +0 -0
  51. {unicex-0.17.9 → unicex-0.17.11}/unicex/bybit/client.py +0 -0
  52. {unicex-0.17.9 → unicex-0.17.11}/unicex/bybit/exchange_info.py +0 -0
  53. {unicex-0.17.9 → unicex-0.17.11}/unicex/bybit/uni_client.py +0 -0
  54. {unicex-0.17.9 → unicex-0.17.11}/unicex/bybit/uni_websocket_manager.py +0 -0
  55. {unicex-0.17.9 → unicex-0.17.11}/unicex/bybit/user_websocket.py +0 -0
  56. {unicex-0.17.9 → unicex-0.17.11}/unicex/bybit/websocket_manager.py +0 -0
  57. {unicex-0.17.9 → unicex-0.17.11}/unicex/enums.py +0 -0
  58. {unicex-0.17.9 → unicex-0.17.11}/unicex/exceptions.py +0 -0
  59. {unicex-0.17.9 → unicex-0.17.11}/unicex/extra.py +0 -0
  60. {unicex-0.17.9 → unicex-0.17.11}/unicex/gate/__init__.py +0 -0
  61. {unicex-0.17.9 → unicex-0.17.11}/unicex/gate/adapter.py +0 -0
  62. {unicex-0.17.9 → unicex-0.17.11}/unicex/gate/client.py +0 -0
  63. {unicex-0.17.9 → unicex-0.17.11}/unicex/gate/exchange_info.py +0 -0
  64. {unicex-0.17.9 → unicex-0.17.11}/unicex/gate/uni_client.py +0 -0
  65. {unicex-0.17.9 → unicex-0.17.11}/unicex/gate/uni_websocket_manager.py +0 -0
  66. {unicex-0.17.9 → unicex-0.17.11}/unicex/gate/user_websocket.py +0 -0
  67. {unicex-0.17.9 → unicex-0.17.11}/unicex/gate/websocket_manager.py +0 -0
  68. {unicex-0.17.9 → unicex-0.17.11}/unicex/hyperliquid/__init__.py +0 -0
  69. {unicex-0.17.9 → unicex-0.17.11}/unicex/hyperliquid/adapter.py +0 -0
  70. {unicex-0.17.9 → unicex-0.17.11}/unicex/hyperliquid/client.py +0 -0
  71. {unicex-0.17.9 → unicex-0.17.11}/unicex/hyperliquid/exchange_info.py +0 -0
  72. {unicex-0.17.9 → unicex-0.17.11}/unicex/hyperliquid/uni_client.py +0 -0
  73. {unicex-0.17.9 → unicex-0.17.11}/unicex/hyperliquid/uni_websocket_manager.py +0 -0
  74. {unicex-0.17.9 → unicex-0.17.11}/unicex/hyperliquid/user_websocket.py +0 -0
  75. {unicex-0.17.9 → unicex-0.17.11}/unicex/hyperliquid/websocket_manager.py +0 -0
  76. {unicex-0.17.9 → unicex-0.17.11}/unicex/kucoin/__init__.py +0 -0
  77. {unicex-0.17.9 → unicex-0.17.11}/unicex/kucoin/adapter.py +0 -0
  78. {unicex-0.17.9 → unicex-0.17.11}/unicex/kucoin/client.py +0 -0
  79. {unicex-0.17.9 → unicex-0.17.11}/unicex/kucoin/exchange_info.py +0 -0
  80. {unicex-0.17.9 → unicex-0.17.11}/unicex/kucoin/uni_client.py +0 -0
  81. {unicex-0.17.9 → unicex-0.17.11}/unicex/kucoin/uni_websocket_manager.py +0 -0
  82. {unicex-0.17.9 → unicex-0.17.11}/unicex/kucoin/user_websocket.py +0 -0
  83. {unicex-0.17.9 → unicex-0.17.11}/unicex/mapper.py +0 -0
  84. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/__init__.py +0 -0
  85. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/_spot_ws_proto/PrivateAccountV3Api_pb2.py +0 -0
  86. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/_spot_ws_proto/PrivateDealsV3Api_pb2.py +0 -0
  87. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/_spot_ws_proto/PrivateOrdersV3Api_pb2.py +0 -0
  88. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/_spot_ws_proto/PublicAggreBookTickerV3Api_pb2.py +0 -0
  89. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/_spot_ws_proto/PublicAggreDealsV3Api_pb2.py +0 -0
  90. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/_spot_ws_proto/PublicAggreDepthsV3Api_pb2.py +0 -0
  91. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/_spot_ws_proto/PublicBookTickerBatchV3Api_pb2.py +0 -0
  92. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/_spot_ws_proto/PublicBookTickerV3Api_pb2.py +0 -0
  93. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/_spot_ws_proto/PublicDealsV3Api_pb2.py +0 -0
  94. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/_spot_ws_proto/PublicFuture_pb2.py +0 -0
  95. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/_spot_ws_proto/PublicIncreaseDepthsBatchV3Api_pb2.py +0 -0
  96. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/_spot_ws_proto/PublicIncreaseDepthsV3Api_pb2.py +0 -0
  97. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/_spot_ws_proto/PublicLimitDepthsV3Api_pb2.py +0 -0
  98. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/_spot_ws_proto/PublicMiniTickerV3Api_pb2.py +0 -0
  99. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/_spot_ws_proto/PublicMiniTickersV3Api_pb2.py +0 -0
  100. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/_spot_ws_proto/PublicSpotKlineV3Api_pb2.py +0 -0
  101. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/_spot_ws_proto/PushDataV3ApiWrapper_pb2.py +0 -0
  102. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/_spot_ws_proto/__init__.py +0 -0
  103. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/adapter.py +0 -0
  104. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/client.py +0 -0
  105. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/exchange_info.py +0 -0
  106. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/uni_client.py +0 -0
  107. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/uni_websocket_manager.py +0 -0
  108. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/user_websocket.py +0 -0
  109. {unicex-0.17.9 → unicex-0.17.11}/unicex/mexc/websocket_manager.py +0 -0
  110. {unicex-0.17.9 → unicex-0.17.11}/unicex/okx/__init__.py +0 -0
  111. {unicex-0.17.9 → unicex-0.17.11}/unicex/okx/adapter.py +0 -0
  112. {unicex-0.17.9 → unicex-0.17.11}/unicex/okx/client.py +0 -0
  113. {unicex-0.17.9 → unicex-0.17.11}/unicex/okx/exchange_info.py +0 -0
  114. {unicex-0.17.9 → unicex-0.17.11}/unicex/okx/uni_client.py +0 -0
  115. {unicex-0.17.9 → unicex-0.17.11}/unicex/okx/uni_websocket_manager.py +0 -0
  116. {unicex-0.17.9 → unicex-0.17.11}/unicex/okx/user_websocket.py +0 -0
  117. {unicex-0.17.9 → unicex-0.17.11}/unicex/okx/websocket_manager.py +0 -0
  118. {unicex-0.17.9 → unicex-0.17.11}/unicex/types.py +0 -0
  119. {unicex-0.17.9 → unicex-0.17.11}/unicex/utils.py +0 -0
  120. {unicex-0.17.9 → unicex-0.17.11}/unicex.egg-info/SOURCES.txt +0 -0
  121. {unicex-0.17.9 → unicex-0.17.11}/unicex.egg-info/dependency_links.txt +0 -0
  122. {unicex-0.17.9 → unicex-0.17.11}/unicex.egg-info/requires.txt +0 -0
  123. {unicex-0.17.9 → unicex-0.17.11}/unicex.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: unicex
3
- Version: 0.17.9
3
+ Version: 0.17.11
4
4
  Summary: Unified Crypto Exchange API
5
5
  Author-email: LoveBloodAndDiamonds <ayazshakirzyanov27@gmail.com>
6
6
  License: BSD 3-Clause License
@@ -4,7 +4,7 @@ name = "unicex"
4
4
  # • PATCH (x.y.Z) → увеличивается при багфиксе, который не ломает совместимость.
5
5
  # • MINOR (x.Y.z) → увеличивается при добавлении новой функциональности, но без ломающих изменений (backward-compatible).
6
6
  # • MAJOR (X.y.z) → увеличивается при изменениях, которые ломают обратную совместимость.
7
- version = "0.17.9"
7
+ version = "0.17.11"
8
8
 
9
9
  description = "Unified Crypto Exchange API "
10
10
  readme = "README.md"
@@ -113,7 +113,7 @@ class Websocket:
113
113
  self._logger.debug(f"Establishing connection with {self._url}")
114
114
  async for conn in websockets.connect(uri=self._url, **self._generate_ws_kwargs()):
115
115
  try:
116
- self._logger.debug(f"Websocket connection was established to {self._url}")
116
+ self._logger.info(f"Websocket connection was established to {self._url}")
117
117
  await self._after_connect(conn)
118
118
 
119
119
  # Цикл получения сообщений
@@ -151,7 +151,8 @@ class Websocket:
151
151
  # Проверяем размер очереди сообщений и выбрасываем ошибку, если он превышает максимальный размер
152
152
  self._check_queue_size()
153
153
  except QueueOverflowError:
154
- self._logger.error("Message queue is overflow")
154
+ cleaned_messages = self._clear_queue()
155
+ self._logger.error(f"Message queue is overflow, cleaned {cleaned_messages} messages")
155
156
  except orjson.JSONDecodeError as e:
156
157
  if message in ["ping", "pong"]:
157
158
  self._logger.debug(f"Received ping message: {message}")
@@ -166,6 +167,18 @@ class Websocket:
166
167
  if qsize >= self.MAX_QUEUE_SIZE:
167
168
  raise QueueOverflowError(f"Message queue is overflow: {qsize}")
168
169
 
170
+ def _clear_queue(self) -> int:
171
+ """Очищает очередь сообщений."""
172
+ cleared = 0
173
+ while True:
174
+ try:
175
+ self._queue.get_nowait()
176
+ self._queue.task_done()
177
+ cleared += 1
178
+ except asyncio.QueueEmpty:
179
+ break
180
+ return cleared
181
+
169
182
  async def _after_connect(self, conn: ClientConnection) -> None:
170
183
  """Вызывается после установки соединения."""
171
184
  # Подписываемся на топики
@@ -261,7 +274,9 @@ class Websocket:
261
274
 
262
275
  while self._running:
263
276
  if time.monotonic() - self._last_message_time > self._no_message_reconnect_timeout:
264
- self._logger.error("Websocket is not responding, restarting...")
277
+ self._logger.error(
278
+ f"No messages in {self._no_message_reconnect_timeout} seconds, restarting..."
279
+ )
265
280
  await self.restart()
266
281
  return
267
282
  await asyncio.sleep(1)
@@ -0,0 +1,121 @@
1
+ __all__ = ["WebsocketManager"]
2
+
3
+ import json
4
+ import time
5
+ from collections.abc import Awaitable, Callable, Sequence
6
+ from typing import Any, Literal
7
+
8
+ from unicex._base import Websocket
9
+ from unicex.utils import validate_single_symbol_args
10
+
11
+ from .client import Client
12
+
13
+ type CallbackType = Callable[[Any], Awaitable[None]]
14
+
15
+
16
+ class WebsocketManager:
17
+ """Менеджер асинхронных вебсокетов для Kucoin."""
18
+
19
+ _SPOT_URL: str = "wss://x-push-spot.kucoin.com"
20
+ """Базовый URL для вебсокета на спот."""
21
+
22
+ _FUTURES_URL: str = "wss://x-push-futures.kucoin.com"
23
+ """Базовый URL для вебсокета на фьючерсы."""
24
+
25
+ def __init__(self, client: Client | None = None, **ws_kwargs: Any) -> None:
26
+ """Инициализирует менеджер вебсокетов для Kucoin.
27
+
28
+ Параметры:
29
+ client (`Client | None`): Клиент для выполнения запросов. Нужен, чтобы открыть приватные вебсокеты.
30
+ ws_kwargs (`dict[str, Any]`): Дополнительные аргументы, которые прокидываются в `Websocket`.
31
+ """
32
+ self.client = client
33
+ self._ws_kwargs = ws_kwargs
34
+
35
+ def _get_url(self, trade_type: Literal["SPOT", "FUTURES"]) -> str:
36
+ """Возвращает URL для указанного типа рынка."""
37
+ if trade_type == "SPOT":
38
+ return self._SPOT_URL
39
+ if trade_type == "FUTURES":
40
+ return self._FUTURES_URL
41
+ raise ValueError(f"Unsupported trade type: {trade_type}")
42
+
43
+ def _normalize_depth(self, depth: str | int) -> str:
44
+ """Нормализует значение глубины стакана."""
45
+ depth_value = str(depth)
46
+ if depth_value not in {"1", "5", "50", "increment"}:
47
+ raise ValueError("depth must be one of: 1, 5, 50, increment")
48
+ return depth_value
49
+
50
+ def _build_subscription_messages(
51
+ self,
52
+ trade_type: Literal["SPOT", "FUTURES"],
53
+ depth: str,
54
+ symbols: Sequence[str],
55
+ rpi_filter: Literal[0, 1],
56
+ request_id: str | None = None,
57
+ ) -> list[str]:
58
+ """Формирует сообщения для подписки."""
59
+ base_id = int(time.time() * 1000)
60
+ messages: list[str] = []
61
+ for index, symbol in enumerate(symbols):
62
+ payload = {
63
+ "id": request_id or str(base_id + index),
64
+ "action": "SUBSCRIBE",
65
+ "channel": "obu",
66
+ "tradeType": trade_type,
67
+ "symbol": symbol.upper(),
68
+ "depth": depth,
69
+ "rpiFilter": rpi_filter,
70
+ }
71
+ messages.append(json.dumps(payload))
72
+ return messages
73
+
74
+ def orderbook(
75
+ self,
76
+ callback: CallbackType,
77
+ trade_type: Literal["SPOT", "FUTURES"],
78
+ depth: Literal["1", "5", "50", "increment"] | int = "1",
79
+ symbol: str | None = None,
80
+ symbols: Sequence[str] | None = None,
81
+ rpi_filter: Literal[0, 1] = 0,
82
+ request_id: str | None = None,
83
+ ) -> Websocket:
84
+ """Создает вебсокет для получения order book.
85
+
86
+ Параметры:
87
+ callback (`CallbackType`): Асинхронная функция обратного вызова для обработки сообщений.
88
+ trade_type (`Literal["SPOT", "FUTURES"]`): Тип рынка.
89
+ depth (`Literal["1", "5", "50", "increment"] | int`): Глубина стакана.
90
+ symbol (`str | None`): Один символ для подписки.
91
+ symbols (`Sequence[str] | None`): Список символов для мультиплекс‑подключения.
92
+ rpi_filter (`Literal[0, 1]`): Фильтр RPI. Доступен только для фьючерсов (depth=5/50).
93
+ request_id (`str | None`): Опциональный идентификатор запроса.
94
+
95
+ Возвращает:
96
+ `Websocket`: Объект для управления вебсокет соединением.
97
+ """
98
+ validate_single_symbol_args(symbol, symbols)
99
+
100
+ depth_value = self._normalize_depth(depth)
101
+ if rpi_filter not in (0, 1):
102
+ raise ValueError("rpi_filter must be 0 or 1")
103
+ if trade_type == "SPOT" and rpi_filter == 1:
104
+ raise ValueError("rpi_filter=1 is supported only for FUTURES")
105
+ if rpi_filter == 1 and depth_value not in {"5", "50"}:
106
+ raise ValueError("rpi_filter=1 supports only depth=5 or depth=50")
107
+
108
+ tickers = [symbol] if symbol else symbols
109
+ subscription_messages = self._build_subscription_messages(
110
+ trade_type=trade_type,
111
+ depth=depth_value,
112
+ symbols=tickers, # type: ignore[arg-type]
113
+ rpi_filter=rpi_filter,
114
+ request_id=request_id,
115
+ )
116
+ return Websocket(
117
+ callback=callback,
118
+ url=self._get_url(trade_type),
119
+ subscription_messages=subscription_messages,
120
+ **self._ws_kwargs,
121
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: unicex
3
- Version: 0.17.9
3
+ Version: 0.17.11
4
4
  Summary: Unified Crypto Exchange API
5
5
  Author-email: LoveBloodAndDiamonds <ayazshakirzyanov27@gmail.com>
6
6
  License: BSD 3-Clause License
@@ -1,11 +0,0 @@
1
- __all__ = ["WebsocketManager"]
2
-
3
-
4
- from collections.abc import Awaitable, Callable
5
- from typing import Any
6
-
7
- type CallbackType = Callable[[Any], Awaitable[None]]
8
-
9
-
10
- class WebsocketManager:
11
- """Менеджер асинхронных вебсокетов для Kucoin."""
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes