unicex 0.4.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.
- unicex/__init__.py +56 -124
- unicex/_abc/__init__.py +2 -0
- unicex/_abc/exchange_info.py +176 -0
- unicex/_abc/uni_client.py +2 -2
- unicex/_base/client.py +2 -2
- unicex/binance/__init__.py +12 -0
- unicex/binance/adapter.py +1 -1
- unicex/binance/exchange_info.py +12 -0
- unicex/bitget/__init__.py +14 -4
- unicex/bitget/adapter.py +1 -1
- unicex/bitget/exchange_info.py +12 -0
- unicex/bitget/uni_websocket_manager.py +1 -1
- unicex/bybit/__init__.py +12 -0
- unicex/bybit/adapter.py +1 -1
- unicex/bybit/exchange_info.py +12 -0
- unicex/enums.py +16 -5
- unicex/extra.py +49 -0
- unicex/gateio/__init__.py +12 -0
- unicex/gateio/adapter.py +2 -2
- unicex/gateio/exchange_info.py +12 -0
- unicex/hyperliquid/__init__.py +12 -0
- unicex/hyperliquid/adapter.py +140 -30
- unicex/hyperliquid/client.py +2208 -125
- unicex/hyperliquid/exchange_info.py +100 -0
- unicex/hyperliquid/uni_client.py +176 -22
- unicex/mapper.py +35 -33
- unicex/mexc/__init__.py +12 -0
- unicex/mexc/adapter.py +28 -11
- unicex/mexc/exchange_info.py +32 -0
- unicex/mexc/uni_client.py +6 -0
- unicex/okx/__init__.py +12 -0
- unicex/okx/adapter.py +23 -7
- unicex/okx/exchange_info.py +50 -0
- unicex/okx/uni_client.py +2 -2
- unicex/types.py +31 -0
- unicex-0.7.0.dist-info/METADATA +192 -0
- unicex-0.7.0.dist-info/RECORD +75 -0
- unicex/bitrue/__init__.py +0 -15
- unicex/bitrue/adapter.py +0 -8
- unicex/bitrue/client.py +0 -128
- unicex/bitrue/uni_client.py +0 -151
- unicex/bitrue/uni_websocket_manager.py +0 -269
- unicex/bitrue/user_websocket.py +0 -7
- unicex/bitrue/websocket_manager.py +0 -11
- unicex/bitunix/__init__.py +0 -15
- unicex/bitunix/adapter.py +0 -8
- unicex/bitunix/client.py +0 -8
- unicex/bitunix/uni_client.py +0 -151
- unicex/bitunix/uni_websocket_manager.py +0 -269
- unicex/bitunix/user_websocket.py +0 -7
- unicex/bitunix/websocket_manager.py +0 -11
- unicex/btse/__init__.py +0 -15
- unicex/btse/adapter.py +0 -8
- unicex/btse/client.py +0 -123
- unicex/btse/uni_client.py +0 -151
- unicex/btse/uni_websocket_manager.py +0 -269
- unicex/btse/user_websocket.py +0 -7
- unicex/btse/websocket_manager.py +0 -11
- unicex/kcex/__init__.py +0 -15
- unicex/kcex/adapter.py +0 -8
- unicex/kcex/client.py +0 -8
- unicex/kcex/uni_client.py +0 -151
- unicex/kcex/uni_websocket_manager.py +0 -269
- unicex/kcex/user_websocket.py +0 -7
- unicex/kcex/websocket_manager.py +0 -11
- unicex/kraken/__init__.py +0 -15
- unicex/kraken/adapter.py +0 -8
- unicex/kraken/client.py +0 -165
- unicex/kraken/uni_client.py +0 -151
- unicex/kraken/uni_websocket_manager.py +0 -269
- unicex/kraken/user_websocket.py +0 -7
- unicex/kraken/websocket_manager.py +0 -11
- unicex/kucoin/__init__.py +0 -15
- unicex/kucoin/adapter.py +0 -8
- unicex/kucoin/client.py +0 -120
- unicex/kucoin/uni_client.py +0 -151
- unicex/kucoin/uni_websocket_manager.py +0 -269
- unicex/kucoin/user_websocket.py +0 -7
- unicex/kucoin/websocket_manager.py +0 -11
- unicex/weex/__init__.py +0 -15
- unicex/weex/adapter.py +0 -8
- unicex/weex/client.py +0 -8
- unicex/weex/uni_client.py +0 -151
- unicex/weex/uni_websocket_manager.py +0 -269
- unicex/weex/user_websocket.py +0 -7
- unicex/weex/websocket_manager.py +0 -11
- unicex/xt/__init__.py +0 -15
- unicex/xt/adapter.py +0 -8
- unicex/xt/client.py +0 -8
- unicex/xt/uni_client.py +0 -151
- unicex/xt/uni_websocket_manager.py +0 -269
- unicex/xt/user_websocket.py +0 -7
- unicex/xt/websocket_manager.py +0 -11
- unicex-0.4.0.dist-info/METADATA +0 -170
- unicex-0.4.0.dist-info/RECORD +0 -123
- {unicex-0.4.0.dist-info → unicex-0.7.0.dist-info}/WHEEL +0 -0
- {unicex-0.4.0.dist-info → unicex-0.7.0.dist-info}/licenses/LICENSE +0 -0
- {unicex-0.4.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
|
-
"
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
)
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
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
|
@@ -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
|
|
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
|
|
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`): Максимум повторов при ошибках запроса.
|
unicex/binance/__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
|
+
"""Загружает информацию о бирже 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
|
|
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
|
@@ -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
|
-
|
|
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
|
@@ -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
|
+
...
|