unicex 0.7.0__tar.gz → 0.8.1__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.
- {unicex-0.7.0/unicex.egg-info → unicex-0.8.1}/PKG-INFO +4 -3
- {unicex-0.7.0 → unicex-0.8.1}/README.md +2 -2
- {unicex-0.7.0 → unicex-0.8.1}/pyproject.toml +2 -1
- {unicex-0.7.0 → unicex-0.8.1}/unicex/_abc/__init__.py +4 -0
- unicex-0.8.1/unicex/_abc/decoder.py +18 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/_abc/uni_client.py +1 -1
- unicex-0.8.1/unicex/_base/__init__.py +9 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/_base/websocket.py +16 -4
- {unicex-0.7.0 → unicex-0.8.1}/unicex/binance/adapter.py +1 -1
- {unicex-0.7.0 → unicex-0.8.1}/unicex/binance/client.py +2 -2
- {unicex-0.7.0 → unicex-0.8.1}/unicex/bitget/client.py +25 -10
- {unicex-0.7.0 → unicex-0.8.1}/unicex/bybit/adapter.py +1 -1
- {unicex-0.7.0 → unicex-0.8.1}/unicex/bybit/client.py +4 -4
- {unicex-0.7.0 → unicex-0.8.1}/unicex/bybit/uni_client.py +2 -2
- unicex-0.8.1/unicex/bybit/websocket_manager.py +339 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/extra.py +84 -6
- {unicex-0.7.0 → unicex-0.8.1}/unicex/gateio/adapter.py +2 -2
- {unicex-0.7.0 → unicex-0.8.1}/unicex/gateio/client.py +1 -1
- {unicex-0.7.0 → unicex-0.8.1}/unicex/hyperliquid/adapter.py +12 -1
- unicex-0.8.1/unicex/mexc/_spot_ws_proto/PrivateAccountV3Api_pb2.py +40 -0
- unicex-0.8.1/unicex/mexc/_spot_ws_proto/PrivateDealsV3Api_pb2.py +40 -0
- unicex-0.8.1/unicex/mexc/_spot_ws_proto/PrivateOrdersV3Api_pb2.py +40 -0
- unicex-0.8.1/unicex/mexc/_spot_ws_proto/PublicAggreBookTickerV3Api_pb2.py +40 -0
- unicex-0.8.1/unicex/mexc/_spot_ws_proto/PublicAggreDealsV3Api_pb2.py +42 -0
- unicex-0.8.1/unicex/mexc/_spot_ws_proto/PublicAggreDepthsV3Api_pb2.py +42 -0
- unicex-0.8.1/unicex/mexc/_spot_ws_proto/PublicBookTickerBatchV3Api_pb2.py +40 -0
- unicex-0.8.1/unicex/mexc/_spot_ws_proto/PublicBookTickerV3Api_pb2.py +40 -0
- unicex-0.8.1/unicex/mexc/_spot_ws_proto/PublicDealsV3Api_pb2.py +42 -0
- unicex-0.8.1/unicex/mexc/_spot_ws_proto/PublicFuture_pb2.py +105 -0
- unicex-0.8.1/unicex/mexc/_spot_ws_proto/PublicIncreaseDepthsBatchV3Api_pb2.py +40 -0
- unicex-0.8.1/unicex/mexc/_spot_ws_proto/PublicIncreaseDepthsV3Api_pb2.py +42 -0
- unicex-0.8.1/unicex/mexc/_spot_ws_proto/PublicLimitDepthsV3Api_pb2.py +42 -0
- unicex-0.8.1/unicex/mexc/_spot_ws_proto/PublicMiniTickerV3Api_pb2.py +40 -0
- unicex-0.8.1/unicex/mexc/_spot_ws_proto/PublicMiniTickersV3Api_pb2.py +40 -0
- unicex-0.8.1/unicex/mexc/_spot_ws_proto/PublicSpotKlineV3Api_pb2.py +40 -0
- unicex-0.8.1/unicex/mexc/_spot_ws_proto/PushDataV3ApiWrapper_pb2.py +40 -0
- unicex-0.8.1/unicex/mexc/_spot_ws_proto/__init__.py +332 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/mexc/adapter.py +2 -2
- {unicex-0.7.0 → unicex-0.8.1}/unicex/mexc/client.py +2 -2
- {unicex-0.7.0 → unicex-0.8.1}/unicex/okx/adapter.py +2 -2
- unicex-0.8.1/unicex/okx/client.py +2864 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/okx/uni_client.py +8 -8
- {unicex-0.7.0 → unicex-0.8.1/unicex.egg-info}/PKG-INFO +4 -3
- {unicex-0.7.0 → unicex-0.8.1}/unicex.egg-info/SOURCES.txt +19 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex.egg-info/requires.txt +1 -0
- unicex-0.7.0/unicex/_base/__init__.py +0 -7
- unicex-0.7.0/unicex/bybit/websocket_manager.py +0 -11
- unicex-0.7.0/unicex/okx/client.py +0 -280
- {unicex-0.7.0 → unicex-0.8.1}/LICENSE +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/setup.cfg +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/__init__.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/_abc/exchange_info.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/_abc/uni_websocket_manager.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/_base/client.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/binance/__init__.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/binance/exchange_info.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/binance/uni_client.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/binance/uni_websocket_manager.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/binance/user_websocket.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/binance/websocket_manager.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/bitget/__init__.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/bitget/adapter.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/bitget/exchange_info.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/bitget/uni_client.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/bitget/uni_websocket_manager.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/bitget/user_websocket.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/bitget/websocket_manager.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/bybit/__init__.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/bybit/exchange_info.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/bybit/uni_websocket_manager.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/bybit/user_websocket.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/enums.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/exceptions.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/gateio/__init__.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/gateio/exchange_info.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/gateio/uni_client.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/gateio/uni_websocket_manager.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/gateio/user_websocket.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/gateio/websocket_manager.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/hyperliquid/__init__.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/hyperliquid/client.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/hyperliquid/exchange_info.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/hyperliquid/uni_client.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/hyperliquid/uni_websocket_manager.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/hyperliquid/user_websocket.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/hyperliquid/websocket_manager.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/mapper.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/mexc/__init__.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/mexc/exchange_info.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/mexc/uni_client.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/mexc/uni_websocket_manager.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/mexc/user_websocket.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/mexc/websocket_manager.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/okx/__init__.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/okx/exchange_info.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/okx/uni_websocket_manager.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/okx/user_websocket.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/okx/websocket_manager.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/types.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex/utils.py +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/unicex.egg-info/dependency_links.txt +0 -0
- {unicex-0.7.0 → unicex-0.8.1}/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.
|
|
3
|
+
Version: 0.8.1
|
|
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
|
+
| **Bybit** | ✓ | ✓ | ✓ | | ✓ | | |
|
|
60
61
|
| **Gateio** | ✓ | ✓ | | | ✓ | | |
|
|
61
62
|
| **Hyperliquid** | ✓ | ✓ | | | ✓ | | |
|
|
62
63
|
| **Mexc** | ✓ | ✓ | | | ✓ | | |
|
|
63
|
-
| **Okx** |
|
|
64
|
+
| **Okx** | ✓ | ✓ | | | ✓ | | ✓ |
|
|
64
65
|
---
|
|
65
66
|
|
|
66
67
|
|
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
|-----------------|--------|------|------------|---------|------------|----------------|--------------|
|
|
9
9
|
| **Binance** | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
|
|
10
10
|
| **Bitget** | ✓ | ✓ | ✓ | | ✓ | | |
|
|
11
|
-
| **Bybit** | ✓ | ✓ |
|
|
11
|
+
| **Bybit** | ✓ | ✓ | ✓ | | ✓ | | |
|
|
12
12
|
| **Gateio** | ✓ | ✓ | | | ✓ | | |
|
|
13
13
|
| **Hyperliquid** | ✓ | ✓ | | | ✓ | | |
|
|
14
14
|
| **Mexc** | ✓ | ✓ | | | ✓ | | |
|
|
15
|
-
| **Okx** |
|
|
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.
|
|
7
|
+
version = "0.8.1"
|
|
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,9 +1,13 @@
|
|
|
1
|
+
"""Пакет с абстракциями и интерфейсами."""
|
|
2
|
+
|
|
1
3
|
__all__ = [
|
|
2
4
|
"IUniClient",
|
|
3
5
|
"IUniWebsocketManager",
|
|
4
6
|
"IExchangeInfo",
|
|
7
|
+
"IDecoder",
|
|
5
8
|
]
|
|
6
9
|
|
|
10
|
+
from .decoder import IDecoder
|
|
7
11
|
from .exchange_info import IExchangeInfo
|
|
8
12
|
from .uni_client import IUniClient
|
|
9
13
|
from .uni_websocket_manager import IUniWebsocketManager
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
__all__ = ["IDecoder"]
|
|
2
|
+
|
|
3
|
+
from typing import Protocol
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class IDecoder(Protocol):
|
|
7
|
+
"""Протокол для декодеров сообщений c вебсокета."""
|
|
8
|
+
|
|
9
|
+
def decode(self, message: bytes | str) -> dict:
|
|
10
|
+
"""Декодирует сообщение.
|
|
11
|
+
|
|
12
|
+
Параметры:
|
|
13
|
+
message (`Any`): Сообщение для декодирования.
|
|
14
|
+
|
|
15
|
+
Возвращает:
|
|
16
|
+
`Any`: Декодированное сообщение.
|
|
17
|
+
"""
|
|
18
|
+
...
|
|
@@ -115,7 +115,7 @@ class IUniClient(ABC, Generic[TClient]):
|
|
|
115
115
|
Возвращает:
|
|
116
116
|
`bool`: True, если апи ключи присутствуют, иначе False.
|
|
117
117
|
"""
|
|
118
|
-
return self._client.
|
|
118
|
+
return self._client.is_authorized()
|
|
119
119
|
|
|
120
120
|
async def close_connection(self) -> None:
|
|
121
121
|
"""Закрывает сессию клиента."""
|
|
@@ -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 TYPE_CHECKING, Any
|
|
7
7
|
|
|
8
8
|
import orjson
|
|
9
9
|
import websockets
|
|
@@ -13,6 +13,9 @@ from websockets.asyncio.client import ClientConnection
|
|
|
13
13
|
from unicex.exceptions import QueueOverflowError
|
|
14
14
|
from unicex.types import LoggerLike
|
|
15
15
|
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from unicex._abc import IDecoder
|
|
18
|
+
|
|
16
19
|
|
|
17
20
|
class Websocket:
|
|
18
21
|
"""Базовый класс асинхронного вебсокета."""
|
|
@@ -20,6 +23,12 @@ class Websocket:
|
|
|
20
23
|
MAX_QUEUE_SIZE: int = 100
|
|
21
24
|
"""Максимальная длина очереди."""
|
|
22
25
|
|
|
26
|
+
class _JsonDecoder:
|
|
27
|
+
"""Базовый JSON декодер для WebSocket сообщений."""
|
|
28
|
+
|
|
29
|
+
def decode(self, message: bytes | str) -> dict:
|
|
30
|
+
return orjson.loads(message)
|
|
31
|
+
|
|
23
32
|
def __init__(
|
|
24
33
|
self,
|
|
25
34
|
callback: Callable[[Any], Awaitable[None]],
|
|
@@ -32,6 +41,7 @@ class Websocket:
|
|
|
32
41
|
reconnect_timeout: int | float | None = 5,
|
|
33
42
|
worker_count: int = 2,
|
|
34
43
|
logger: LoggerLike | None = None,
|
|
44
|
+
decoder: type["IDecoder"] = _JsonDecoder,
|
|
35
45
|
**kwargs: Any, # Не дадим сломаться, если юзер передал ненужные аргументы
|
|
36
46
|
) -> None:
|
|
37
47
|
"""Инициализация вебсокета.
|
|
@@ -47,6 +57,7 @@ class Websocket:
|
|
|
47
57
|
reconnect_timeout (`int | float | None`): Пауза перед переподключением, сек.
|
|
48
58
|
worker_count (`int`): Количество рабочих задач для обработки сообщений.
|
|
49
59
|
logger (`LoggerLike | None`): Логгер для записи логов.
|
|
60
|
+
decoder (`IDecoder | None`): Декодер для обработки входящих сообщений.
|
|
50
61
|
"""
|
|
51
62
|
self._callback = callback
|
|
52
63
|
self._url = url
|
|
@@ -59,6 +70,7 @@ class Websocket:
|
|
|
59
70
|
self._last_message_time = time.monotonic()
|
|
60
71
|
self._worker_count = worker_count
|
|
61
72
|
self._logger = logger or _logger
|
|
73
|
+
self._decoder = decoder()
|
|
62
74
|
self._tasks: list[asyncio.Task] = []
|
|
63
75
|
self._queue = asyncio.Queue()
|
|
64
76
|
self._running = False
|
|
@@ -114,14 +126,14 @@ class Websocket:
|
|
|
114
126
|
await asyncio.sleep(self._reconnect_timeout)
|
|
115
127
|
await self._after_disconnect()
|
|
116
128
|
|
|
117
|
-
async def _handle_message(self, message: str) -> None:
|
|
129
|
+
async def _handle_message(self, message: str | bytes) -> None:
|
|
118
130
|
"""Обрабатывает входящее сообщение вебсокета."""
|
|
119
131
|
try:
|
|
120
132
|
# Обновленяем время последнего сообщения
|
|
121
133
|
self._last_message_time = time.monotonic()
|
|
122
134
|
|
|
123
135
|
# Ложим сообщение в очередь, предварительно его сериализуя
|
|
124
|
-
await self._queue.put(
|
|
136
|
+
await self._queue.put(self._decoder.decode(message))
|
|
125
137
|
|
|
126
138
|
# Проверяем размер очереди сообщений и выбрасываем ошибку, если он превышает максимальный размер
|
|
127
139
|
self._check_queue_size()
|
|
@@ -139,7 +151,7 @@ class Websocket:
|
|
|
139
151
|
"""Проверяет размер очереди и выбрасывает ошибку при переполнении."""
|
|
140
152
|
qsize = self._queue.qsize()
|
|
141
153
|
if qsize >= self.MAX_QUEUE_SIZE:
|
|
142
|
-
raise QueueOverflowError("Message queue is overflow")
|
|
154
|
+
raise QueueOverflowError(f"Message queue is overflow: {qsize}")
|
|
143
155
|
|
|
144
156
|
async def _after_connect(self, conn: ClientConnection) -> None:
|
|
145
157
|
"""Вызывается после установки соединения."""
|
|
@@ -17,7 +17,7 @@ class Adapter:
|
|
|
17
17
|
"""Адаптер для унификации данных с Binance API."""
|
|
18
18
|
|
|
19
19
|
@staticmethod
|
|
20
|
-
def tickers(raw_data: list[dict], only_usdt: bool
|
|
20
|
+
def tickers(raw_data: list[dict], only_usdt: bool) -> list[str]:
|
|
21
21
|
"""Преобразует сырой ответ, в котором содержатся данные о тикерах в список тикеров.
|
|
22
22
|
|
|
23
23
|
Параметры:
|
|
@@ -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.
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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(
|
|
@@ -16,7 +16,7 @@ class Adapter:
|
|
|
16
16
|
"""Адаптер для унификации данных с Bybit API."""
|
|
17
17
|
|
|
18
18
|
@staticmethod
|
|
19
|
-
def tickers(raw_data: dict, only_usdt: bool
|
|
19
|
+
def tickers(raw_data: dict, only_usdt: bool) -> list[str]:
|
|
20
20
|
"""Преобразует сырой ответ, в котором содержатся данные о тикерах в список тикеров.
|
|
21
21
|
|
|
22
22
|
Параметры:
|
|
@@ -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.
|
|
45
|
-
raise NotAuthorized("
|
|
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,
|
|
@@ -33,7 +33,7 @@ class UniClient(IUniClient[Client]):
|
|
|
33
33
|
list[str]: Список тикеров.
|
|
34
34
|
"""
|
|
35
35
|
raw_data = await self._client.tickers("spot")
|
|
36
|
-
return Adapter.tickers(raw_data)
|
|
36
|
+
return Adapter.tickers(raw_data, only_usdt)
|
|
37
37
|
|
|
38
38
|
async def futures_tickers(self, only_usdt: bool = True) -> list[str]:
|
|
39
39
|
"""Возвращает список тикеров.
|
|
@@ -45,7 +45,7 @@ class UniClient(IUniClient[Client]):
|
|
|
45
45
|
list[str]: Список тикеров.
|
|
46
46
|
"""
|
|
47
47
|
raw_data = await self._client.tickers("linear")
|
|
48
|
-
return Adapter.tickers(raw_data)
|
|
48
|
+
return Adapter.tickers(raw_data, only_usdt)
|
|
49
49
|
|
|
50
50
|
async def last_price(self) -> dict[str, float]:
|
|
51
51
|
"""Возвращает последнюю цену для каждого тикера.
|