unicex 0.8.0__tar.gz → 0.10.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.
Files changed (104) hide show
  1. {unicex-0.8.0/unicex.egg-info → unicex-0.10.0}/PKG-INFO +7 -6
  2. {unicex-0.8.0 → unicex-0.10.0}/README.md +5 -5
  3. {unicex-0.8.0 → unicex-0.10.0}/pyproject.toml +2 -1
  4. {unicex-0.8.0 → unicex-0.10.0}/unicex/_abc/__init__.py +2 -0
  5. {unicex-0.8.0 → unicex-0.10.0}/unicex/_abc/uni_client.py +1 -1
  6. unicex-0.10.0/unicex/_base/__init__.py +9 -0
  7. {unicex-0.8.0 → unicex-0.10.0}/unicex/_base/websocket.py +34 -14
  8. {unicex-0.8.0 → unicex-0.10.0}/unicex/binance/client.py +2 -2
  9. {unicex-0.8.0 → unicex-0.10.0}/unicex/bitget/client.py +25 -10
  10. {unicex-0.8.0 → unicex-0.10.0}/unicex/bitget/websocket_manager.py +6 -6
  11. {unicex-0.8.0 → unicex-0.10.0}/unicex/bybit/client.py +4 -4
  12. unicex-0.10.0/unicex/bybit/websocket_manager.py +339 -0
  13. {unicex-0.8.0 → unicex-0.10.0}/unicex/gateio/client.py +1 -1
  14. unicex-0.10.0/unicex/gateio/websocket_manager.py +513 -0
  15. unicex-0.10.0/unicex/hyperliquid/websocket_manager.py +363 -0
  16. unicex-0.10.0/unicex/mexc/_spot_ws_proto/PrivateAccountV3Api_pb2.py +38 -0
  17. unicex-0.10.0/unicex/mexc/_spot_ws_proto/PrivateDealsV3Api_pb2.py +38 -0
  18. unicex-0.10.0/unicex/mexc/_spot_ws_proto/PrivateOrdersV3Api_pb2.py +38 -0
  19. unicex-0.10.0/unicex/mexc/_spot_ws_proto/PublicAggreBookTickerV3Api_pb2.py +38 -0
  20. unicex-0.10.0/unicex/mexc/_spot_ws_proto/PublicAggreDealsV3Api_pb2.py +40 -0
  21. unicex-0.10.0/unicex/mexc/_spot_ws_proto/PublicAggreDepthsV3Api_pb2.py +40 -0
  22. unicex-0.10.0/unicex/mexc/_spot_ws_proto/PublicBookTickerBatchV3Api_pb2.py +38 -0
  23. unicex-0.10.0/unicex/mexc/_spot_ws_proto/PublicBookTickerV3Api_pb2.py +38 -0
  24. unicex-0.10.0/unicex/mexc/_spot_ws_proto/PublicDealsV3Api_pb2.py +40 -0
  25. unicex-0.10.0/unicex/mexc/_spot_ws_proto/PublicFuture_pb2.py +103 -0
  26. unicex-0.10.0/unicex/mexc/_spot_ws_proto/PublicIncreaseDepthsBatchV3Api_pb2.py +38 -0
  27. unicex-0.10.0/unicex/mexc/_spot_ws_proto/PublicIncreaseDepthsV3Api_pb2.py +40 -0
  28. unicex-0.10.0/unicex/mexc/_spot_ws_proto/PublicLimitDepthsV3Api_pb2.py +40 -0
  29. unicex-0.10.0/unicex/mexc/_spot_ws_proto/PublicMiniTickerV3Api_pb2.py +38 -0
  30. unicex-0.10.0/unicex/mexc/_spot_ws_proto/PublicMiniTickersV3Api_pb2.py +38 -0
  31. unicex-0.10.0/unicex/mexc/_spot_ws_proto/PublicSpotKlineV3Api_pb2.py +38 -0
  32. unicex-0.10.0/unicex/mexc/_spot_ws_proto/PushDataV3ApiWrapper_pb2.py +38 -0
  33. unicex-0.10.0/unicex/mexc/_spot_ws_proto/__init__.py +335 -0
  34. {unicex-0.8.0 → unicex-0.10.0}/unicex/mexc/client.py +2 -2
  35. unicex-0.10.0/unicex/mexc/websocket_manager.py +456 -0
  36. {unicex-0.8.0 → unicex-0.10.0}/unicex/okx/client.py +26 -15
  37. unicex-0.10.0/unicex/okx/websocket_manager.py +743 -0
  38. {unicex-0.8.0 → unicex-0.10.0/unicex.egg-info}/PKG-INFO +7 -6
  39. {unicex-0.8.0 → unicex-0.10.0}/unicex.egg-info/SOURCES.txt +18 -0
  40. {unicex-0.8.0 → unicex-0.10.0}/unicex.egg-info/requires.txt +1 -0
  41. unicex-0.8.0/unicex/_base/__init__.py +0 -7
  42. unicex-0.8.0/unicex/bybit/websocket_manager.py +0 -11
  43. unicex-0.8.0/unicex/gateio/websocket_manager.py +0 -11
  44. unicex-0.8.0/unicex/hyperliquid/websocket_manager.py +0 -11
  45. unicex-0.8.0/unicex/mexc/websocket_manager.py +0 -11
  46. unicex-0.8.0/unicex/okx/websocket_manager.py +0 -11
  47. {unicex-0.8.0 → unicex-0.10.0}/LICENSE +0 -0
  48. {unicex-0.8.0 → unicex-0.10.0}/setup.cfg +0 -0
  49. {unicex-0.8.0 → unicex-0.10.0}/unicex/__init__.py +0 -0
  50. {unicex-0.8.0 → unicex-0.10.0}/unicex/_abc/exchange_info.py +0 -0
  51. {unicex-0.8.0 → unicex-0.10.0}/unicex/_abc/uni_websocket_manager.py +0 -0
  52. {unicex-0.8.0 → unicex-0.10.0}/unicex/_base/client.py +0 -0
  53. {unicex-0.8.0 → unicex-0.10.0}/unicex/binance/__init__.py +0 -0
  54. {unicex-0.8.0 → unicex-0.10.0}/unicex/binance/adapter.py +0 -0
  55. {unicex-0.8.0 → unicex-0.10.0}/unicex/binance/exchange_info.py +0 -0
  56. {unicex-0.8.0 → unicex-0.10.0}/unicex/binance/uni_client.py +0 -0
  57. {unicex-0.8.0 → unicex-0.10.0}/unicex/binance/uni_websocket_manager.py +0 -0
  58. {unicex-0.8.0 → unicex-0.10.0}/unicex/binance/user_websocket.py +0 -0
  59. {unicex-0.8.0 → unicex-0.10.0}/unicex/binance/websocket_manager.py +0 -0
  60. {unicex-0.8.0 → unicex-0.10.0}/unicex/bitget/__init__.py +0 -0
  61. {unicex-0.8.0 → unicex-0.10.0}/unicex/bitget/adapter.py +0 -0
  62. {unicex-0.8.0 → unicex-0.10.0}/unicex/bitget/exchange_info.py +0 -0
  63. {unicex-0.8.0 → unicex-0.10.0}/unicex/bitget/uni_client.py +0 -0
  64. {unicex-0.8.0 → unicex-0.10.0}/unicex/bitget/uni_websocket_manager.py +0 -0
  65. {unicex-0.8.0 → unicex-0.10.0}/unicex/bitget/user_websocket.py +0 -0
  66. {unicex-0.8.0 → unicex-0.10.0}/unicex/bybit/__init__.py +0 -0
  67. {unicex-0.8.0 → unicex-0.10.0}/unicex/bybit/adapter.py +0 -0
  68. {unicex-0.8.0 → unicex-0.10.0}/unicex/bybit/exchange_info.py +0 -0
  69. {unicex-0.8.0 → unicex-0.10.0}/unicex/bybit/uni_client.py +0 -0
  70. {unicex-0.8.0 → unicex-0.10.0}/unicex/bybit/uni_websocket_manager.py +0 -0
  71. {unicex-0.8.0 → unicex-0.10.0}/unicex/bybit/user_websocket.py +0 -0
  72. {unicex-0.8.0 → unicex-0.10.0}/unicex/enums.py +0 -0
  73. {unicex-0.8.0 → unicex-0.10.0}/unicex/exceptions.py +0 -0
  74. {unicex-0.8.0 → unicex-0.10.0}/unicex/extra.py +0 -0
  75. {unicex-0.8.0 → unicex-0.10.0}/unicex/gateio/__init__.py +0 -0
  76. {unicex-0.8.0 → unicex-0.10.0}/unicex/gateio/adapter.py +0 -0
  77. {unicex-0.8.0 → unicex-0.10.0}/unicex/gateio/exchange_info.py +0 -0
  78. {unicex-0.8.0 → unicex-0.10.0}/unicex/gateio/uni_client.py +0 -0
  79. {unicex-0.8.0 → unicex-0.10.0}/unicex/gateio/uni_websocket_manager.py +0 -0
  80. {unicex-0.8.0 → unicex-0.10.0}/unicex/gateio/user_websocket.py +0 -0
  81. {unicex-0.8.0 → unicex-0.10.0}/unicex/hyperliquid/__init__.py +0 -0
  82. {unicex-0.8.0 → unicex-0.10.0}/unicex/hyperliquid/adapter.py +0 -0
  83. {unicex-0.8.0 → unicex-0.10.0}/unicex/hyperliquid/client.py +0 -0
  84. {unicex-0.8.0 → unicex-0.10.0}/unicex/hyperliquid/exchange_info.py +0 -0
  85. {unicex-0.8.0 → unicex-0.10.0}/unicex/hyperliquid/uni_client.py +0 -0
  86. {unicex-0.8.0 → unicex-0.10.0}/unicex/hyperliquid/uni_websocket_manager.py +0 -0
  87. {unicex-0.8.0 → unicex-0.10.0}/unicex/hyperliquid/user_websocket.py +0 -0
  88. {unicex-0.8.0 → unicex-0.10.0}/unicex/mapper.py +0 -0
  89. {unicex-0.8.0 → unicex-0.10.0}/unicex/mexc/__init__.py +0 -0
  90. {unicex-0.8.0 → unicex-0.10.0}/unicex/mexc/adapter.py +0 -0
  91. {unicex-0.8.0 → unicex-0.10.0}/unicex/mexc/exchange_info.py +0 -0
  92. {unicex-0.8.0 → unicex-0.10.0}/unicex/mexc/uni_client.py +0 -0
  93. {unicex-0.8.0 → unicex-0.10.0}/unicex/mexc/uni_websocket_manager.py +0 -0
  94. {unicex-0.8.0 → unicex-0.10.0}/unicex/mexc/user_websocket.py +0 -0
  95. {unicex-0.8.0 → unicex-0.10.0}/unicex/okx/__init__.py +0 -0
  96. {unicex-0.8.0 → unicex-0.10.0}/unicex/okx/adapter.py +0 -0
  97. {unicex-0.8.0 → unicex-0.10.0}/unicex/okx/exchange_info.py +0 -0
  98. {unicex-0.8.0 → unicex-0.10.0}/unicex/okx/uni_client.py +0 -0
  99. {unicex-0.8.0 → unicex-0.10.0}/unicex/okx/uni_websocket_manager.py +0 -0
  100. {unicex-0.8.0 → unicex-0.10.0}/unicex/okx/user_websocket.py +0 -0
  101. {unicex-0.8.0 → unicex-0.10.0}/unicex/types.py +0 -0
  102. {unicex-0.8.0 → unicex-0.10.0}/unicex/utils.py +0 -0
  103. {unicex-0.8.0 → unicex-0.10.0}/unicex.egg-info/dependency_links.txt +0 -0
  104. {unicex-0.8.0 → unicex-0.10.0}/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.8.0
3
+ Version: 0.10.0
4
4
  Summary: Unified Crypto Exchange API
5
5
  Author-email: LoveBloodAndDiamonds <ayazshakirzyanov27@gmail.com>
6
6
  License: BSD 3-Clause License
@@ -43,6 +43,7 @@ Requires-Dist: eth-account>=0.13.7
43
43
  Requires-Dist: loguru>=0.7.3
44
44
  Requires-Dist: msgpack>=1.1.1
45
45
  Requires-Dist: orjson>=3.11.3
46
+ Requires-Dist: protobuf>=6.32.1
46
47
  Requires-Dist: websockets>=15.0.1
47
48
  Dynamic: license-file
48
49
 
@@ -56,11 +57,11 @@ Dynamic: license-file
56
57
  |-----------------|--------|------|------------|---------|------------|----------------|--------------|
57
58
  | **Binance** | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
58
59
  | **Bitget** | ✓ | ✓ | ✓ | | ✓ | | |
59
- | **Bybit** | ✓ | ✓ | | | ✓ | | |
60
- | **Gateio** | ✓ | ✓ | | | ✓ | | |
61
- | **Hyperliquid** | ✓ | ✓ | | | ✓ | | |
62
- | **Mexc** | ✓ | ✓ | | | ✓ | | |
63
- | **Okx** | ✓ | ✓ | | | ✓ | | ✓ |
60
+ | **Bybit** | ✓ | ✓ || | ✓ | | |
61
+ | **Gateio** | ✓ | ✓ || | ✓ | | |
62
+ | **Hyperliquid** | ✓ | ✓ ||| ✓ | | |
63
+ | **Mexc** | ✓ | ✓ || | ✓ | | |
64
+ | **Okx** | ✓ | ✓ || | ✓ | | ✓ |
64
65
  ---
65
66
 
66
67
 
@@ -8,11 +8,11 @@
8
8
  |-----------------|--------|------|------------|---------|------------|----------------|--------------|
9
9
  | **Binance** | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
10
10
  | **Bitget** | ✓ | ✓ | ✓ | | ✓ | | |
11
- | **Bybit** | ✓ | ✓ | | | ✓ | | |
12
- | **Gateio** | ✓ | ✓ | | | ✓ | | |
13
- | **Hyperliquid** | ✓ | ✓ | | | ✓ | | |
14
- | **Mexc** | ✓ | ✓ | | | ✓ | | |
15
- | **Okx** | ✓ | ✓ | | | ✓ | | ✓ |
11
+ | **Bybit** | ✓ | ✓ || | ✓ | | |
12
+ | **Gateio** | ✓ | ✓ || | ✓ | | |
13
+ | **Hyperliquid** | ✓ | ✓ ||| ✓ | | |
14
+ | **Mexc** | ✓ | ✓ || | ✓ | | |
15
+ | **Okx** | ✓ | ✓ || | ✓ | | ✓ |
16
16
  ---
17
17
 
18
18
 
@@ -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.8.0"
7
+ version = "0.10.0"
8
8
 
9
9
  description = "Unified Crypto Exchange API "
10
10
  readme = "README.md"
@@ -19,6 +19,7 @@ dependencies = [
19
19
  "loguru>=0.7.3",
20
20
  "msgpack>=1.1.1",
21
21
  "orjson>=3.11.3",
22
+ "protobuf>=6.32.1",
22
23
  "websockets>=15.0.1",
23
24
  ]
24
25
 
@@ -1,3 +1,5 @@
1
+ """Пакет с абстракциями и интерфейсами."""
2
+
1
3
  __all__ = [
2
4
  "IUniClient",
3
5
  "IUniWebsocketManager",
@@ -115,7 +115,7 @@ class IUniClient(ABC, Generic[TClient]):
115
115
  Возвращает:
116
116
  `bool`: True, если апи ключи присутствуют, иначе False.
117
117
  """
118
- return self._client._api_key is not None and self._client._api_secret is not None
118
+ return self._client.is_authorized()
119
119
 
120
120
  async def close_connection(self) -> None:
121
121
  """Закрывает сессию клиента."""
@@ -0,0 +1,9 @@
1
+ """Пакет с базовым клиентом для HTTP запросов и базовым вебсокетом."""
2
+
3
+ __all__ = [
4
+ "BaseClient",
5
+ "Websocket",
6
+ ]
7
+
8
+ from .client import BaseClient
9
+ from .websocket import Websocket
@@ -3,7 +3,7 @@ __all__ = ["Websocket"]
3
3
  import asyncio
4
4
  import time
5
5
  from collections.abc import Awaitable, Callable
6
- from typing import Any
6
+ from typing import Any, Protocol
7
7
 
8
8
  import orjson
9
9
  import websockets
@@ -20,18 +20,30 @@ class Websocket:
20
20
  MAX_QUEUE_SIZE: int = 100
21
21
  """Максимальная длина очереди."""
22
22
 
23
+ class _DecoderProtocol(Protocol):
24
+ """Протокол декодирования сообщений."""
25
+
26
+ def decode(self, message: Any) -> dict: ...
27
+
28
+ class _JsonDecoder:
29
+ """Протокол декодирования сообщений в формате JSON."""
30
+
31
+ def decode(self, message: Any) -> dict:
32
+ return orjson.loads(message)
33
+
23
34
  def __init__(
24
35
  self,
25
36
  callback: Callable[[Any], Awaitable[None]],
26
37
  url: str,
27
38
  subscription_messages: list[dict] | list[str] | None = None,
28
39
  ping_interval: int | float = 10,
29
- ping_message: str | None = None,
30
- pong_message: str | None = None,
40
+ ping_message: str | Callable | None = None,
41
+ pong_message: str | Callable | None = None,
31
42
  no_message_reconnect_timeout: int | float | None = 60,
32
43
  reconnect_timeout: int | float | None = 5,
33
44
  worker_count: int = 2,
34
45
  logger: LoggerLike | None = None,
46
+ decoder: type[_DecoderProtocol] = _JsonDecoder,
35
47
  **kwargs: Any, # Не дадим сломаться, если юзер передал ненужные аргументы
36
48
  ) -> None:
37
49
  """Инициализация вебсокета.
@@ -41,12 +53,13 @@ class Websocket:
41
53
  url (`str`): URL вебсокета.
42
54
  subscription_messages (`list[dict] | list[str] | None`): Сообщения для подписки после подключения.
43
55
  ping_interval (`int | float`): Интервал отправки ping, сек.
44
- ping_message (`str | None`): Сообщение для ping (если не указано — используется ping‑frame).
45
- pong_message (`str | None`): Сообщение для pong (если не указано — используется pong‑frame).
56
+ ping_message (`str | Callable | None`): Сообщение для ping, или функция генерации ping (если не указано — используется ping‑frame).
57
+ pong_message (`str | Callable | None`): Сообщение для pong, или функция генерации pong (если не указано — используется pong‑frame).
46
58
  no_message_reconnect_timeout (`int | float | None`): Таймаут ожидания без сообщений до рестарта, сек.
47
59
  reconnect_timeout (`int | float | None`): Пауза перед переподключением, сек.
48
60
  worker_count (`int`): Количество рабочих задач для обработки сообщений.
49
61
  logger (`LoggerLike | None`): Логгер для записи логов.
62
+ decoder (`IDecoder | None`): Декодер для обработки входящих сообщений.
50
63
  """
51
64
  self._callback = callback
52
65
  self._url = url
@@ -59,6 +72,7 @@ class Websocket:
59
72
  self._last_message_time = time.monotonic()
60
73
  self._worker_count = worker_count
61
74
  self._logger = logger or _logger
75
+ self._decoder = decoder()
62
76
  self._tasks: list[asyncio.Task] = []
63
77
  self._queue = asyncio.Queue()
64
78
  self._running = False
@@ -104,24 +118,26 @@ class Websocket:
104
118
 
105
119
  # Цикл получения сообщений
106
120
  while self._running:
107
- message = await conn.recv(decode=True)
121
+ message = await conn.recv()
108
122
  await self._handle_message(message)
109
123
 
110
- except websockets.exceptions.ConnectionClosed:
111
- self._logger.error("Websocket connection was closed unexpectedly")
112
- continue
124
+ except websockets.exceptions.ConnectionClosed as e:
125
+ self._logger.error(f"Websocket connection was closed unexpectedly: {e}")
126
+ except Exception as e:
127
+ self._logger.error(f"Unexpected error in websosocket connection: {e}")
113
128
  finally:
114
129
  await asyncio.sleep(self._reconnect_timeout)
115
130
  await self._after_disconnect()
116
131
 
117
- async def _handle_message(self, message: str) -> None:
132
+ async def _handle_message(self, message: str | bytes) -> None:
118
133
  """Обрабатывает входящее сообщение вебсокета."""
119
134
  try:
120
135
  # Обновленяем время последнего сообщения
121
136
  self._last_message_time = time.monotonic()
122
137
 
123
138
  # Ложим сообщение в очередь, предварительно его сериализуя
124
- await self._queue.put(orjson.loads(message))
139
+ decoded_message = self._decoder.decode(message)
140
+ await self._queue.put(decoded_message)
125
141
 
126
142
  # Проверяем размер очереди сообщений и выбрасываем ошибку, если он превышает максимальный размер
127
143
  self._check_queue_size()
@@ -139,7 +155,7 @@ class Websocket:
139
155
  """Проверяет размер очереди и выбрасывает ошибку при переполнении."""
140
156
  qsize = self._queue.qsize()
141
157
  if qsize >= self.MAX_QUEUE_SIZE:
142
- raise QueueOverflowError("Message queue is overflow")
158
+ raise QueueOverflowError(f"Message queue is overflow: {qsize}")
143
159
 
144
160
  async def _after_connect(self, conn: ClientConnection) -> None:
145
161
  """Вызывается после установки соединения."""
@@ -201,8 +217,12 @@ class Websocket:
201
217
  """Периодически отправляет пользовательский ping."""
202
218
  while self._running and self._ping_message:
203
219
  try:
204
- await conn.send(self._ping_message)
205
- self._logger.debug(f"Sent ping message: {self._ping_message}")
220
+ if isinstance(self._ping_message, Callable):
221
+ ping_message = self._ping_message()
222
+ else:
223
+ ping_message = self._ping_message
224
+ await conn.send(ping_message)
225
+ self._logger.debug(f"Sent ping message: {ping_message}")
206
226
  except Exception as e:
207
227
  self._logger.error(f"Error sending ping: {e}")
208
228
  return
@@ -62,8 +62,8 @@ class Client(BaseClient):
62
62
  if not signed:
63
63
  return {"params": params, "data": data}, None
64
64
 
65
- if not self._api_key or not self._api_secret: # type: ignore[attr-defined]
66
- raise NotAuthorized("Api key is required to private endpoints")
65
+ if not self.is_authorized():
66
+ raise NotAuthorized("Api key and api secret is required to private endpoints")
67
67
 
68
68
  # Объединяем все параметры в payload
69
69
  payload = {**params, **data}
@@ -5,6 +5,7 @@ import time
5
5
  from typing import Any, Literal
6
6
 
7
7
  from unicex._base import BaseClient
8
+ from unicex.exceptions import NotAuthorized
8
9
  from unicex.types import RequestMethod
9
10
  from unicex.utils import (
10
11
  dict_to_query_string,
@@ -20,6 +21,18 @@ class Client(BaseClient):
20
21
  _BASE_URL: str = "https://api.bitget.com"
21
22
  """Базовый URL для REST API Bitget."""
22
23
 
24
+ def is_authorized(self) -> bool:
25
+ """Проверяет наличие API‑ключей у клиента.
26
+
27
+ Возвращает:
28
+ `bool`: Признак наличия ключей.
29
+ """
30
+ return (
31
+ self._api_key is not None
32
+ and self._api_secret is not None
33
+ and self._api_passphrase is not None
34
+ )
35
+
23
36
  def _sign_message(
24
37
  self,
25
38
  method: RequestMethod,
@@ -45,6 +58,9 @@ class Client(BaseClient):
45
58
  - `timestamp (str)`: Временная метка в миллисекундах.
46
59
  - `signature (str)`: Подпись в формате base64.
47
60
  """
61
+ if not self.is_authorized():
62
+ raise NotAuthorized("Api key and api secret is required to private endpoints")
63
+
48
64
  timestamp = str(int(time.time() * 1000))
49
65
 
50
66
  path = f"{endpoint}?{dict_to_query_string(params)}" if params else endpoint
@@ -68,16 +84,15 @@ class Client(BaseClient):
68
84
  `dict[str, str]`: Словарь заголовков запроса.
69
85
  """
70
86
  headers = {"Content-Type": "application/json", "Accept": "application/json"}
71
- if self._api_key: # type: ignore[attr-defined]
72
- headers.update(
73
- {
74
- "ACCESS-KEY": self._api_key, # type: ignore[attr-defined]
75
- "ACCESS-PASSPHRASE": self._api_passphrase, # type: ignore[attr-defined]
76
- "ACCESS-TIMESTAMP": timestamp,
77
- "ACCESS-SIGN": signature,
78
- "locale": "en-US",
79
- }
80
- )
87
+ headers.update(
88
+ {
89
+ "ACCESS-KEY": self._api_key, # type: ignore[attr-defined]
90
+ "ACCESS-PASSPHRASE": self._api_passphrase, # type: ignore[attr-defined]
91
+ "ACCESS-TIMESTAMP": timestamp,
92
+ "ACCESS-SIGN": signature,
93
+ "locale": "en-US",
94
+ }
95
+ )
81
96
  return headers
82
97
 
83
98
  def _prepare_request_params(
@@ -15,7 +15,7 @@ type CallbackType = Callable[[Any], Awaitable[None]]
15
15
  class WebsocketManager:
16
16
  """Менеджер асинхронных вебсокетов для Bitget."""
17
17
 
18
- _BASE_URL: str = "wss://ws.bitget.com/v2/ws/public"
18
+ _URL: str = "wss://ws.bitget.com/v2/ws/public"
19
19
  """Базовый URL для вебсокета."""
20
20
 
21
21
  def __init__(self, client: Client | None = None, **ws_kwargs: Any) -> None:
@@ -91,7 +91,7 @@ class WebsocketManager:
91
91
  )
92
92
  return Websocket(
93
93
  callback=callback,
94
- url=self._BASE_URL,
94
+ url=self._URL,
95
95
  subscription_messages=subsription_messages,
96
96
  **self._ws_kwargs,
97
97
  )
@@ -124,7 +124,7 @@ class WebsocketManager:
124
124
  )
125
125
  return Websocket(
126
126
  callback=callback,
127
- url=self._BASE_URL,
127
+ url=self._URL,
128
128
  subscription_messages=subscription_messages,
129
129
  **self._ws_kwargs,
130
130
  )
@@ -160,7 +160,7 @@ class WebsocketManager:
160
160
  )
161
161
  return Websocket(
162
162
  callback=callback,
163
- url=self._BASE_URL,
163
+ url=self._URL,
164
164
  subscription_messages=subscription_messages,
165
165
  **self._ws_kwargs,
166
166
  )
@@ -195,7 +195,7 @@ class WebsocketManager:
195
195
  )
196
196
  return Websocket(
197
197
  callback=callback,
198
- url=self._BASE_URL,
198
+ url=self._URL,
199
199
  subscription_messages=subscription_messages,
200
200
  **self._ws_kwargs,
201
201
  )
@@ -226,7 +226,7 @@ class WebsocketManager:
226
226
  )
227
227
  return Websocket(
228
228
  callback=callback,
229
- url=self._BASE_URL,
229
+ url=self._URL,
230
230
  subscription_messages=subscription_messages,
231
231
  **self._ws_kwargs,
232
232
  )
@@ -41,12 +41,12 @@ class Client(BaseClient):
41
41
  Источник: https://github.com/bybit-exchange/api-usage-examples/blob/master/V5_demo/api_demo/Encryption_HMAC.py
42
42
  """
43
43
  # Проверяем наличие апи ключей для подписи запроса
44
- if not self._api_key or not self._api_secret:
45
- raise NotAuthorized("API key and secret are required to private endpoints.")
44
+ if not self.is_authorized():
45
+ raise NotAuthorized("Api key and api secret is required to private endpoints")
46
46
 
47
47
  dumped_payload = json.dumps(payload)
48
- prepared_query_string = timestamp + self._api_key + self._RECV_WINDOW + dumped_payload
49
- return generate_hmac_sha256_signature(self._api_secret, prepared_query_string)
48
+ prepared_query_string = timestamp + self._api_key + self._RECV_WINDOW + dumped_payload # type: ignore[attrDefined]
49
+ return generate_hmac_sha256_signature(self._api_secret, prepared_query_string) # type: ignore[attrDefined]
50
50
 
51
51
  async def _make_request(
52
52
  self,