unicex 0.5.0__py3-none-any.whl → 0.7.0__py3-none-any.whl

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 (97) hide show
  1. unicex/__init__.py +56 -124
  2. unicex/_abc/__init__.py +2 -0
  3. unicex/_abc/exchange_info.py +176 -0
  4. unicex/_abc/uni_client.py +2 -2
  5. unicex/_base/client.py +2 -2
  6. unicex/binance/__init__.py +12 -0
  7. unicex/binance/adapter.py +1 -1
  8. unicex/binance/exchange_info.py +12 -0
  9. unicex/bitget/__init__.py +14 -4
  10. unicex/bitget/adapter.py +1 -1
  11. unicex/bitget/exchange_info.py +12 -0
  12. unicex/bitget/uni_websocket_manager.py +1 -1
  13. unicex/bybit/__init__.py +12 -0
  14. unicex/bybit/adapter.py +1 -1
  15. unicex/bybit/exchange_info.py +12 -0
  16. unicex/enums.py +16 -5
  17. unicex/gateio/__init__.py +12 -0
  18. unicex/gateio/adapter.py +2 -2
  19. unicex/gateio/exchange_info.py +12 -0
  20. unicex/hyperliquid/__init__.py +12 -0
  21. unicex/hyperliquid/adapter.py +140 -30
  22. unicex/hyperliquid/client.py +2208 -125
  23. unicex/hyperliquid/exchange_info.py +100 -0
  24. unicex/hyperliquid/uni_client.py +176 -22
  25. unicex/mapper.py +35 -33
  26. unicex/mexc/__init__.py +12 -0
  27. unicex/mexc/adapter.py +28 -11
  28. unicex/mexc/exchange_info.py +32 -0
  29. unicex/mexc/uni_client.py +6 -0
  30. unicex/okx/__init__.py +12 -0
  31. unicex/okx/adapter.py +23 -7
  32. unicex/okx/exchange_info.py +50 -0
  33. unicex/okx/uni_client.py +2 -2
  34. unicex/types.py +31 -0
  35. unicex-0.7.0.dist-info/METADATA +192 -0
  36. unicex-0.7.0.dist-info/RECORD +75 -0
  37. unicex/bitrue/__init__.py +0 -15
  38. unicex/bitrue/adapter.py +0 -8
  39. unicex/bitrue/client.py +0 -128
  40. unicex/bitrue/uni_client.py +0 -151
  41. unicex/bitrue/uni_websocket_manager.py +0 -269
  42. unicex/bitrue/user_websocket.py +0 -7
  43. unicex/bitrue/websocket_manager.py +0 -11
  44. unicex/bitunix/__init__.py +0 -15
  45. unicex/bitunix/adapter.py +0 -8
  46. unicex/bitunix/client.py +0 -8
  47. unicex/bitunix/uni_client.py +0 -151
  48. unicex/bitunix/uni_websocket_manager.py +0 -269
  49. unicex/bitunix/user_websocket.py +0 -7
  50. unicex/bitunix/websocket_manager.py +0 -11
  51. unicex/btse/__init__.py +0 -15
  52. unicex/btse/adapter.py +0 -8
  53. unicex/btse/client.py +0 -123
  54. unicex/btse/uni_client.py +0 -151
  55. unicex/btse/uni_websocket_manager.py +0 -269
  56. unicex/btse/user_websocket.py +0 -7
  57. unicex/btse/websocket_manager.py +0 -11
  58. unicex/kcex/__init__.py +0 -15
  59. unicex/kcex/adapter.py +0 -8
  60. unicex/kcex/client.py +0 -8
  61. unicex/kcex/uni_client.py +0 -151
  62. unicex/kcex/uni_websocket_manager.py +0 -269
  63. unicex/kcex/user_websocket.py +0 -7
  64. unicex/kcex/websocket_manager.py +0 -11
  65. unicex/kraken/__init__.py +0 -15
  66. unicex/kraken/adapter.py +0 -8
  67. unicex/kraken/client.py +0 -165
  68. unicex/kraken/uni_client.py +0 -151
  69. unicex/kraken/uni_websocket_manager.py +0 -269
  70. unicex/kraken/user_websocket.py +0 -7
  71. unicex/kraken/websocket_manager.py +0 -11
  72. unicex/kucoin/__init__.py +0 -15
  73. unicex/kucoin/adapter.py +0 -8
  74. unicex/kucoin/client.py +0 -120
  75. unicex/kucoin/uni_client.py +0 -151
  76. unicex/kucoin/uni_websocket_manager.py +0 -269
  77. unicex/kucoin/user_websocket.py +0 -7
  78. unicex/kucoin/websocket_manager.py +0 -11
  79. unicex/weex/__init__.py +0 -15
  80. unicex/weex/adapter.py +0 -8
  81. unicex/weex/client.py +0 -8
  82. unicex/weex/uni_client.py +0 -151
  83. unicex/weex/uni_websocket_manager.py +0 -269
  84. unicex/weex/user_websocket.py +0 -7
  85. unicex/weex/websocket_manager.py +0 -11
  86. unicex/xt/__init__.py +0 -15
  87. unicex/xt/adapter.py +0 -8
  88. unicex/xt/client.py +0 -8
  89. unicex/xt/uni_client.py +0 -151
  90. unicex/xt/uni_websocket_manager.py +0 -269
  91. unicex/xt/user_websocket.py +0 -7
  92. unicex/xt/websocket_manager.py +0 -11
  93. unicex-0.5.0.dist-info/METADATA +0 -170
  94. unicex-0.5.0.dist-info/RECORD +0 -123
  95. {unicex-0.5.0.dist-info → unicex-0.7.0.dist-info}/WHEEL +0 -0
  96. {unicex-0.5.0.dist-info → unicex-0.7.0.dist-info}/licenses/LICENSE +0 -0
  97. {unicex-0.5.0.dist-info → unicex-0.7.0.dist-info}/top_level.txt +0 -0
unicex/__init__.py CHANGED
@@ -4,18 +4,28 @@ __all__ = [
4
4
  # Mappers
5
5
  "get_uni_client",
6
6
  "get_uni_websocket_manager",
7
+ "get_exchange_info",
8
+ # Exchanges info
9
+ "load_exchanges_info",
10
+ "start_exchanges_info",
7
11
  # Enums
8
12
  "MarketType",
9
13
  "Exchange",
10
14
  "Timeframe",
11
15
  "Side",
12
16
  # Types
17
+ "TickerDailyDict",
18
+ "TickerDailyItem",
13
19
  "KlineDict",
14
- "AggTradeDict",
15
20
  "TradeDict",
16
- "TickerDailyDict",
21
+ "AggTradeDict",
17
22
  "RequestMethod",
18
23
  "LoggerLike",
24
+ "AccountType",
25
+ "OpenInterestDict",
26
+ "OpenInterestItem",
27
+ "TickerInfoItem",
28
+ "TickersInfoDict",
19
29
  # Interfaces
20
30
  "IUniClient",
21
31
  "IUniWebsocketManager",
@@ -28,109 +38,62 @@ __all__ = [
28
38
  "BinanceWebsocketManager",
29
39
  "BinanceUniWebsocketManager",
30
40
  "BinanceUserWebsocket",
41
+ "BinanceExchangeInfo",
31
42
  # Bitget
32
43
  "BitgetClient",
33
44
  "BitgetUniClient",
34
45
  "BitgetUniWebsocketManager",
35
46
  "BitgetWebsocketManager",
36
47
  "BitgetUserWebsocket",
37
- # Bitrue
38
- "BitrueClient",
39
- "BitrueUniClient",
40
- "BitrueUniWebsocketManager",
41
- "BitrueWebsocketManager",
42
- "BitrueUserWebsocket",
48
+ "BitgetExchangeInfo",
43
49
  # Mexc
44
50
  "MexcClient",
45
51
  "MexcUniClient",
46
52
  "MexcUniWebsocketManager",
47
53
  "MexcWebsocketManager",
48
54
  "MexcUserWebsocket",
55
+ "MexcExchangeInfo",
49
56
  # Bybit
50
57
  "BybitClient",
51
58
  "BybitUniClient",
52
59
  "BybitUniWebsocketManager",
53
60
  "BybitWebsocketManager",
54
61
  "BybitUserWebsocket",
62
+ "BybitExchangeInfo",
55
63
  # Okx
56
64
  "OkxClient",
57
65
  "OkxUniClient",
58
66
  "OkxUniWebsocketManager",
59
67
  "OkxWebsocketManager",
60
68
  "OkxUserWebsocket",
69
+ "OkxExchangeInfo",
61
70
  # Hyperliquid
62
71
  "HyperliquidClient",
63
72
  "HyperliquidUniClient",
64
73
  "HyperliquidUniWebsocketManager",
65
74
  "HyperliquidWebsocketManager",
66
75
  "HyperliquidUserWebsocket",
76
+ "HyperliquidExchangeInfo",
67
77
  # Gateio
68
78
  "GateioClient",
69
79
  "GateioUniClient",
70
80
  "GateioUniWebsocketManager",
71
81
  "GateioWebsocketManager",
72
82
  "GateioUserWebsocket",
73
- # Bitunix
74
- "BitunixClient",
75
- "BitunixUniClient",
76
- "BitunixUniWebsocketManager",
77
- "BitunixWebsocketManager",
78
- "BitunixUserWebsocket",
79
- # Btse
80
- "BtseClient",
81
- "BtseUniClient",
82
- "BtseUniWebsocketManager",
83
- "BtseWebsocketManager",
84
- "BtseUserWebsocket",
85
- # Kcex
86
- "KcexClient",
87
- "KcexUniClient",
88
- "KcexUniWebsocketManager",
89
- "KcexWebsocketManager",
90
- "KcexUserWebsocket",
91
- # Kraken
92
- "KrakenClient",
93
- "KrakenUniClient",
94
- "KrakenUniWebsocketManager",
95
- "KrakenWebsocketManager",
96
- "KrakenUserWebsocket",
97
- # Kucoin
98
- "KucoinClient",
99
- "KucoinUniClient",
100
- "KucoinUniWebsocketManager",
101
- "KucoinWebsocketManager",
102
- "KucoinUserWebsocket",
103
- # Weex
104
- "WeexClient",
105
- "WeexUniClient",
106
- "WeexUniWebsocketManager",
107
- "WeexWebsocketManager",
108
- "WeexUserWebsocket",
109
- # Xt
110
- "XtClient",
111
- "XtUniClient",
112
- "XtUniWebsocketManager",
113
- "XtWebsocketManager",
114
- "XtUserWebsocket",
83
+ "GateioExchangeInfo",
115
84
  ]
116
85
 
117
86
  # ruff: noqa
118
87
 
119
88
  # abstract & base
89
+ import asyncio
120
90
  from ._abc import IUniClient, IUniWebsocketManager
121
91
  from ._base import BaseClient, Websocket
122
92
 
123
93
  # enums, mappers, types
124
94
  from .enums import Exchange, MarketType, Side, Timeframe
125
- from .mapper import get_uni_client, get_uni_websocket_manager
126
- from .types import (
127
- AggTradeDict,
128
- KlineDict,
129
- LoggerLike,
130
- RequestMethod,
131
- TickerDailyDict,
132
- TradeDict,
133
- )
95
+ from .mapper import get_uni_client, get_uni_websocket_manager, get_exchange_info
96
+ from .types import *
134
97
 
135
98
  # exchanges
136
99
 
@@ -140,6 +103,7 @@ from .binance import (
140
103
  UniWebsocketManager as BinanceUniWebsocketManager,
141
104
  UserWebsocket as BinanceUserWebsocket,
142
105
  WebsocketManager as BinanceWebsocketManager,
106
+ ExchangeInfo as BinanceExchangeInfo,
143
107
  )
144
108
 
145
109
  from .bitget import (
@@ -148,30 +112,7 @@ from .bitget import (
148
112
  UniWebsocketManager as BitgetUniWebsocketManager,
149
113
  UserWebsocket as BitgetUserWebsocket,
150
114
  WebsocketManager as BitgetWebsocketManager,
151
- )
152
-
153
- from .bitrue import (
154
- Client as BitrueClient,
155
- UniClient as BitrueUniClient,
156
- UniWebsocketManager as BitrueUniWebsocketManager,
157
- UserWebsocket as BitrueUserWebsocket,
158
- WebsocketManager as BitrueWebsocketManager,
159
- )
160
-
161
- from .bitunix import (
162
- Client as BitunixClient,
163
- UniClient as BitunixUniClient,
164
- UniWebsocketManager as BitunixUniWebsocketManager,
165
- UserWebsocket as BitunixUserWebsocket,
166
- WebsocketManager as BitunixWebsocketManager,
167
- )
168
-
169
- from .btse import (
170
- Client as BtseClient,
171
- UniClient as BtseUniClient,
172
- UniWebsocketManager as BtseUniWebsocketManager,
173
- UserWebsocket as BtseUserWebsocket,
174
- WebsocketManager as BtseWebsocketManager,
115
+ ExchangeInfo as BitgetExchangeInfo,
175
116
  )
176
117
 
177
118
  from .bybit import (
@@ -180,6 +121,7 @@ from .bybit import (
180
121
  UniWebsocketManager as BybitUniWebsocketManager,
181
122
  UserWebsocket as BybitUserWebsocket,
182
123
  WebsocketManager as BybitWebsocketManager,
124
+ ExchangeInfo as BybitExchangeInfo,
183
125
  )
184
126
 
185
127
  from .gateio import (
@@ -188,6 +130,7 @@ from .gateio import (
188
130
  UniWebsocketManager as GateioUniWebsocketManager,
189
131
  UserWebsocket as GateioUserWebsocket,
190
132
  WebsocketManager as GateioWebsocketManager,
133
+ ExchangeInfo as GateioExchangeInfo,
191
134
  )
192
135
 
193
136
  from .hyperliquid import (
@@ -196,30 +139,7 @@ from .hyperliquid import (
196
139
  UniWebsocketManager as HyperliquidUniWebsocketManager,
197
140
  UserWebsocket as HyperliquidUserWebsocket,
198
141
  WebsocketManager as HyperliquidWebsocketManager,
199
- )
200
-
201
- from .kcex import (
202
- Client as KcexClient,
203
- UniClient as KcexUniClient,
204
- UniWebsocketManager as KcexUniWebsocketManager,
205
- UserWebsocket as KcexUserWebsocket,
206
- WebsocketManager as KcexWebsocketManager,
207
- )
208
-
209
- from .kraken import (
210
- Client as KrakenClient,
211
- UniClient as KrakenUniClient,
212
- UniWebsocketManager as KrakenUniWebsocketManager,
213
- UserWebsocket as KrakenUserWebsocket,
214
- WebsocketManager as KrakenWebsocketManager,
215
- )
216
-
217
- from .kucoin import (
218
- Client as KucoinClient,
219
- UniClient as KucoinUniClient,
220
- UniWebsocketManager as KucoinUniWebsocketManager,
221
- UserWebsocket as KucoinUserWebsocket,
222
- WebsocketManager as KucoinWebsocketManager,
142
+ ExchangeInfo as HyperliquidExchangeInfo,
223
143
  )
224
144
 
225
145
  from .mexc import (
@@ -228,6 +148,7 @@ from .mexc import (
228
148
  UniWebsocketManager as MexcUniWebsocketManager,
229
149
  UserWebsocket as MexcUserWebsocket,
230
150
  WebsocketManager as MexcWebsocketManager,
151
+ ExchangeInfo as MexcExchangeInfo,
231
152
  )
232
153
 
233
154
  from .okx import (
@@ -236,20 +157,31 @@ from .okx import (
236
157
  UniWebsocketManager as OkxUniWebsocketManager,
237
158
  UserWebsocket as OkxUserWebsocket,
238
159
  WebsocketManager as OkxWebsocketManager,
239
- )
240
-
241
- from .weex import (
242
- Client as WeexClient,
243
- UniClient as WeexUniClient,
244
- UniWebsocketManager as WeexUniWebsocketManager,
245
- UserWebsocket as WeexUserWebsocket,
246
- WebsocketManager as WeexWebsocketManager,
247
- )
248
-
249
- from .xt import (
250
- Client as XtClient,
251
- UniClient as XtUniClient,
252
- UniWebsocketManager as XtUniWebsocketManager,
253
- UserWebsocket as XtUserWebsocket,
254
- WebsocketManager as XtWebsocketManager,
255
- )
160
+ ExchangeInfo as OkxExchangeInfo,
161
+ )
162
+
163
+
164
+ async def load_exchanges_info() -> None:
165
+ """Единожды загружает информацию о тикерах на всех биржах."""
166
+ await asyncio.gather(
167
+ BinanceExchangeInfo.load_exchange_info(),
168
+ BitgetExchangeInfo.load_exchange_info(),
169
+ BybitExchangeInfo.load_exchange_info(),
170
+ GateioExchangeInfo.load_exchange_info(),
171
+ HyperliquidExchangeInfo.load_exchange_info(),
172
+ MexcExchangeInfo.load_exchange_info(),
173
+ OkxExchangeInfo.load_exchange_info(),
174
+ )
175
+
176
+
177
+ async def start_exchanges_info(parse_interval_seconds: int = 60 * 60) -> None:
178
+ """Запускает цикл обновления информации о тикерах на всех биржах."""
179
+ asyncio.gather(
180
+ BinanceExchangeInfo.start(parse_interval_seconds),
181
+ BitgetExchangeInfo.start(parse_interval_seconds),
182
+ BybitExchangeInfo.start(parse_interval_seconds),
183
+ GateioExchangeInfo.start(parse_interval_seconds),
184
+ HyperliquidExchangeInfo.start(parse_interval_seconds),
185
+ MexcExchangeInfo.start(parse_interval_seconds),
186
+ OkxExchangeInfo.start(parse_interval_seconds),
187
+ )
unicex/_abc/__init__.py CHANGED
@@ -1,7 +1,9 @@
1
1
  __all__ = [
2
2
  "IUniClient",
3
3
  "IUniWebsocketManager",
4
+ "IExchangeInfo",
4
5
  ]
5
6
 
7
+ from .exchange_info import IExchangeInfo
6
8
  from .uni_client import IUniClient
7
9
  from .uni_websocket_manager import IUniWebsocketManager
@@ -0,0 +1,176 @@
1
+ __all__ = ["IExchangeInfo"]
2
+
3
+ import asyncio
4
+ from abc import ABC, abstractmethod
5
+ from decimal import Decimal
6
+ from typing import TYPE_CHECKING
7
+
8
+ from loguru import logger
9
+
10
+ from unicex.enums import MarketType
11
+ from unicex.types import TickerInfoItem, TickersInfoDict
12
+
13
+ if TYPE_CHECKING:
14
+ import loguru
15
+
16
+
17
+ class IExchangeInfo(ABC):
18
+ """Интерфейс для наследников, которые предзагружают и обновляют информацию о бирже."""
19
+
20
+ _loaded: bool
21
+ """Флаг, указывающий, была ли информация о бирже загружена."""
22
+
23
+ _running: bool
24
+ """Флаг, указывающий, запущена ли фоновая задача для обновления информации о бирже."""
25
+
26
+ _tickers_info: TickersInfoDict
27
+ """Словарь с информацией о округлении для каждого тикера."""
28
+
29
+ _futures_tickers_info: TickersInfoDict
30
+ """Словарь с информацией о округлении и размере контракта (если есть) для каждого тикера."""
31
+
32
+ _logger: "loguru.Logger"
33
+ """Логгер для записи сообщений о работе с биржей."""
34
+
35
+ def __init_subclass__(cls, **kwargs):
36
+ """Инициализация подкласса. Функция нужна, чтобы у каждого наследника была своя копия атрибутов."""
37
+ super().__init_subclass__(**kwargs)
38
+ cls._tickers_info = {}
39
+ cls._loaded = False
40
+ cls._running = False
41
+ cls._logger = logger
42
+
43
+ @classmethod
44
+ async def start(cls, update_interval_seconds: int = 60 * 60) -> None:
45
+ """Запускает фоновую задачу с бесконечным циклом для загрузки данных."""
46
+ cls._running = True
47
+ asyncio.create_task(cls._load_exchange_info_loop(update_interval_seconds))
48
+
49
+ @classmethod
50
+ async def stop(cls) -> None:
51
+ """Останавливает фоновую задачу для обновления информации о бирже."""
52
+ cls._running = False
53
+
54
+ @classmethod
55
+ async def set_logger(cls, logger: "loguru.Logger") -> None:
56
+ """Устанавливает логгер для записи сообщений о работе с биржей."""
57
+ cls._logger = logger
58
+
59
+ @classmethod
60
+ async def _load_exchange_info_loop(cls, update_interval_seconds: int) -> None:
61
+ """Запускает бесконечный цикл для загрузки данных о бирже."""
62
+ while cls._running:
63
+ try:
64
+ await cls.load_exchange_info()
65
+ except Exception as e:
66
+ cls._logger.error(f"Error loading exchange data: {e}")
67
+ for _ in range(update_interval_seconds):
68
+ if not cls._running:
69
+ break
70
+ await asyncio.sleep(1)
71
+
72
+ @classmethod
73
+ async def load_exchange_info(cls) -> None:
74
+ """Принудительно вызывает загрузку информации о бирже."""
75
+ await cls._load_exchange_info()
76
+ cls._loaded = True
77
+
78
+ @classmethod
79
+ def get_ticker_info(
80
+ cls, symbol: str, market_type: MarketType = MarketType.SPOT
81
+ ) -> TickerInfoItem: # type: ignore[reportReturnType]
82
+ """Возвращает информацию о тикере по его символу."""
83
+ try:
84
+ if market_type == MarketType.SPOT:
85
+ return cls._tickers_info[symbol]
86
+ return cls._futures_tickers_info[symbol]
87
+ except KeyError as e:
88
+ cls._handle_key_error(e, symbol)
89
+
90
+ @classmethod
91
+ def get_futures_ticker_info(cls, symbol: str) -> TickerInfoItem:
92
+ """Возвращает информацию о тикере фьючерсов по его символу."""
93
+ return cls.get_ticker_info(symbol, MarketType.FUTURES)
94
+
95
+ @classmethod
96
+ @abstractmethod
97
+ async def _load_exchange_info(cls) -> None:
98
+ """Загружает информацию о бирже."""
99
+ ...
100
+
101
+ @classmethod
102
+ def round_price(
103
+ cls, symbol: str, price: float, market_type: MarketType = MarketType.SPOT
104
+ ) -> float:
105
+ """Округляет цену до ближайшего возможного значения."""
106
+ try:
107
+ if market_type == MarketType.SPOT:
108
+ precision = cls._tickers_info[symbol]["tick_precision"]
109
+ else:
110
+ precision = cls._futures_tickers_info[symbol]["tick_precision"]
111
+ except KeyError as e:
112
+ cls._handle_key_error(e, symbol)
113
+ return round(price, precision)
114
+
115
+ @classmethod
116
+ def round_quantity(
117
+ cls, symbol: str, quantity: float, market_type: MarketType = MarketType.SPOT
118
+ ) -> float:
119
+ """Округляет объем до ближайшего возможного значения."""
120
+ try:
121
+ if market_type == MarketType.SPOT:
122
+ precision = cls._tickers_info[symbol]["size_precision"]
123
+ else:
124
+ precision = cls._futures_tickers_info[symbol]["size_precision"]
125
+ except KeyError as e:
126
+ cls._handle_key_error(e, symbol)
127
+ return round(quantity, precision)
128
+
129
+ @classmethod
130
+ def round_futures_price(cls, symbol: str, price: float) -> float:
131
+ """Округляет цену до ближайшего возможного значения на фьючерсах."""
132
+ return cls.round_price(symbol, price, MarketType.FUTURES)
133
+
134
+ @classmethod
135
+ def round_futures_quantity(cls, symbol: str, quantity: float) -> float:
136
+ """Округляет объем до ближайшего возможного значения на фьючерсах."""
137
+ return cls.round_quantity(symbol, quantity, MarketType.FUTURES)
138
+
139
+ @staticmethod
140
+ def _step_size_to_precision(tick_size: str | int | float) -> int:
141
+ """Возвращает precision для round(x, precision) по шагу цены/объёма.
142
+
143
+ Работает только для шагов — степеней 10.
144
+ Примеры:
145
+ "0.0001" -> 4
146
+ "0.01" -> 2
147
+ "0.1" -> 1
148
+ "1" -> 0
149
+ "10" -> -1
150
+ "100" -> -2
151
+ """
152
+ d = Decimal(str(tick_size)).normalize()
153
+ if d <= 0:
154
+ raise ValueError("tick_size must be > 0")
155
+
156
+ t = d.as_tuple()
157
+ # Степень десяти даёт один значащий разряд = 1 (1eN)
158
+ if t.digits == (1,):
159
+ return -t.exponent # type: ignore
160
+
161
+ # Иначе это не степень 10 (например, 0.5, 5 и т.п.)
162
+ raise ValueError(
163
+ f"tick_size={tick_size} is not a power of 10; cannot map to round() precision."
164
+ )
165
+
166
+ @classmethod
167
+ def _handle_key_error(cls, exception: KeyError, symbol: str) -> None:
168
+ """Обрабатывает KeyError при получении информации о тикере."""
169
+ cls._check_loaded()
170
+ raise KeyError(f"Symbol {symbol} not found") from exception
171
+
172
+ @classmethod
173
+ def _check_loaded(cls) -> None:
174
+ """Проверяет, загружены ли данные об обмене."""
175
+ if not cls._loaded:
176
+ raise ValueError("Exchange data not loaded") from None
unicex/_abc/uni_client.py CHANGED
@@ -172,7 +172,7 @@ class IUniClient(ABC, Generic[TClient]):
172
172
  Возвращает:
173
173
  `list[list[str]]`: Список тикеров в чанках.
174
174
  """
175
- tickers = await self.tickers(only_usdt=only_usdt)
175
+ tickers = await self.tickers(only_usdt)
176
176
  return batched_list(tickers, batch_size)
177
177
 
178
178
  @abstractmethod
@@ -199,7 +199,7 @@ class IUniClient(ABC, Generic[TClient]):
199
199
  Возвращает:
200
200
  `list[list[str]]`: Список тикеров в чанках.
201
201
  """
202
- tickers = await self.futures_tickers(only_usdt=only_usdt)
202
+ tickers = await self.futures_tickers(only_usdt)
203
203
  return batched_list(tickers, batch_size)
204
204
 
205
205
  @abstractmethod
unicex/_base/client.py CHANGED
@@ -33,7 +33,7 @@ class BaseClient:
33
33
  session (`aiohttp.ClientSession`): Сессия для выполнения HTTP‑запросов.
34
34
  api_key (`str | None`): Ключ API для аутентификации.
35
35
  api_secret (`str | None`): Секретный ключ API для аутентификации.
36
- api_passphrase (`str | None`): Пароль API для аутентификации (Bitget).
36
+ api_passphrase (`str | None`): Пароль API для аутентификации (Bitget, OKX).
37
37
  logger (`LoggerLike | None`): Логгер для вывода информации.
38
38
  max_retries (`int`): Максимальное количество повторных попыток запроса.
39
39
  retry_delay (`int | float`): Задержка между повторными попытками, сек.
@@ -68,7 +68,7 @@ class BaseClient:
68
68
  Параметры:
69
69
  api_key (`str | None`): Ключ API для аутентификации.
70
70
  api_secret (`str | None`): Секретный ключ API для аутентификации.
71
- api_passphrase (`str | None`): Пароль API для аутентификации (Bitget).
71
+ api_passphrase (`str | None`): Пароль API для аутентификации (Bitget, OKX).
72
72
  session (`aiohttp.ClientSession | None`): Сессия для HTTP‑запросов (если не передана, будет создана).
73
73
  logger (`LoggerLike | None`): Логгер для вывода информации.
74
74
  max_retries (`int`): Максимум повторов при ошибках запроса.
@@ -6,10 +6,22 @@ __all__ = [
6
6
  "UserWebsocket",
7
7
  "WebsocketManager",
8
8
  "UniWebsocketManager",
9
+ "ExchangeInfo",
9
10
  ]
10
11
 
11
12
  from .client import Client
13
+ from .exchange_info import ExchangeInfo
12
14
  from .uni_client import UniClient
13
15
  from .uni_websocket_manager import UniWebsocketManager
14
16
  from .user_websocket import UserWebsocket
15
17
  from .websocket_manager import WebsocketManager
18
+
19
+
20
+ async def load_exchange_info() -> None:
21
+ """Загружает информацию о бирже Binance."""
22
+ await ExchangeInfo.load_exchange_info()
23
+
24
+
25
+ async def start_exchange_info(parse_interval_seconds: int = 60 * 60) -> None:
26
+ """Запускает процесс обновления информации о бирже Binance."""
27
+ await ExchangeInfo.start(parse_interval_seconds)
unicex/binance/adapter.py CHANGED
@@ -28,7 +28,7 @@ class Adapter:
28
28
  list[str]: Список тикеров.
29
29
  """
30
30
  return [
31
- item["symbol"] for item in raw_data if not only_usdt or item["symbol"].endswith("USDT")
31
+ item["symbol"] for item in raw_data if item["symbol"].endswith("USDT") or not only_usdt
32
32
  ]
33
33
 
34
34
  @staticmethod
@@ -0,0 +1,12 @@
1
+ __all__ = ["ExchangeInfo"]
2
+
3
+ from unicex._abc import IExchangeInfo
4
+
5
+
6
+ class ExchangeInfo(IExchangeInfo):
7
+ """Предзагружает информацию о тикерах для биржи Binance."""
8
+
9
+ @classmethod
10
+ async def _load_exchange_info(cls) -> None:
11
+ """Загружает информацию о бирже."""
12
+ ...
unicex/bitget/__init__.py CHANGED
@@ -2,16 +2,26 @@
2
2
 
3
3
  __all__ = [
4
4
  "Client",
5
- "WebsocketManager",
6
- "UniWebsocketManager",
7
5
  "UniClient",
8
- "Adapter",
9
6
  "UserWebsocket",
7
+ "WebsocketManager",
8
+ "UniWebsocketManager",
9
+ "ExchangeInfo",
10
10
  ]
11
11
 
12
- from .adapter import Adapter
13
12
  from .client import Client
13
+ from .exchange_info import ExchangeInfo
14
14
  from .uni_client import UniClient
15
15
  from .uni_websocket_manager import UniWebsocketManager
16
16
  from .user_websocket import UserWebsocket
17
17
  from .websocket_manager import WebsocketManager
18
+
19
+
20
+ async def load_exchange_info() -> None:
21
+ """Загружает информацию о бирже Bitget."""
22
+ await ExchangeInfo.load_exchange_info()
23
+
24
+
25
+ async def start_exchange_info(parse_interval_seconds: int = 60 * 60) -> None:
26
+ """Запускает процесс обновления информации о бирже Bitget."""
27
+ await ExchangeInfo.start(parse_interval_seconds)
unicex/bitget/adapter.py CHANGED
@@ -30,7 +30,7 @@ class Adapter:
30
30
  return [
31
31
  item["symbol"]
32
32
  for item in raw_data["data"]
33
- if not only_usdt or item["symbol"].endswith("USDT")
33
+ if item["symbol"].endswith("USDT") or not only_usdt
34
34
  ]
35
35
 
36
36
  @staticmethod
@@ -0,0 +1,12 @@
1
+ __all__ = ["ExchangeInfo"]
2
+
3
+ from unicex._abc import IExchangeInfo
4
+
5
+
6
+ class ExchangeInfo(IExchangeInfo):
7
+ """Предзагружает информацию о тикерах для биржи Bitget."""
8
+
9
+ @classmethod
10
+ async def _load_exchange_info(cls) -> None:
11
+ """Загружает информацию о бирже."""
12
+ ...
@@ -193,7 +193,7 @@ class UniWebsocketManager(IUniWebsocketManager):
193
193
  Возвращает:
194
194
  `Websocket`: Экземпляр вебсокета.
195
195
  """
196
- raise NotImplementedError()
196
+ return self.trades(callback=callback, symbol=symbol, symbols=symbols) # type: ignore[reportCallIssue]
197
197
 
198
198
  @overload
199
199
  def futures_trades(
unicex/bybit/__init__.py CHANGED
@@ -6,10 +6,22 @@ __all__ = [
6
6
  "UserWebsocket",
7
7
  "WebsocketManager",
8
8
  "UniWebsocketManager",
9
+ "ExchangeInfo",
9
10
  ]
10
11
 
11
12
  from .client import Client
13
+ from .exchange_info import ExchangeInfo
12
14
  from .uni_client import UniClient
13
15
  from .uni_websocket_manager import UniWebsocketManager
14
16
  from .user_websocket import UserWebsocket
15
17
  from .websocket_manager import WebsocketManager
18
+
19
+
20
+ async def load_exchange_info() -> None:
21
+ """Загружает информацию о бирже Bybit."""
22
+ await ExchangeInfo.load_exchange_info()
23
+
24
+
25
+ async def start_exchange_info(parse_interval_seconds: int = 60 * 60) -> None:
26
+ """Запускает процесс обновления информации о бирже Bybit."""
27
+ await ExchangeInfo.start(parse_interval_seconds)
unicex/bybit/adapter.py CHANGED
@@ -29,7 +29,7 @@ class Adapter:
29
29
  return [
30
30
  item["symbol"]
31
31
  for item in raw_data["result"]["list"]
32
- if only_usdt or item["symbol"].endswith("USDT")
32
+ if item["symbol"].endswith("USDT") or not only_usdt
33
33
  ]
34
34
 
35
35
  @staticmethod
@@ -0,0 +1,12 @@
1
+ __all__ = ["ExchangeInfo"]
2
+
3
+ from unicex._abc import IExchangeInfo
4
+
5
+
6
+ class ExchangeInfo(IExchangeInfo):
7
+ """Предзагружает информацию о тикерах для биржи Bybit."""
8
+
9
+ @classmethod
10
+ async def _load_exchange_info(cls) -> None:
11
+ """Загружает информацию о бирже."""
12
+ ...