unicex 0.15.1__py3-none-any.whl → 0.15.4__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/_abc/exchange_info.py +1 -1
- unicex/_abc/uni_client.py +1 -1
- unicex/_abc/uni_websocket_manager.py +1 -1
- unicex/_base/client.py +7 -0
- unicex/binance/adapter.py +5 -1
- unicex/bingx/adapter.py +1 -1
- unicex/bingx/websocket_manager.py +2 -4
- unicex/bitget/adapter.py +1 -0
- unicex/bitget/websocket_manager.py +2 -4
- unicex/bybit/adapter.py +1 -0
- unicex/bybit/websocket_manager.py +7 -24
- unicex/extra.py +24 -24
- unicex/gate/adapter.py +1 -0
- unicex/hyperliquid/adapter.py +1 -0
- unicex/kucoin/adapter.py +4 -9
- unicex/kucoin/client.py +13 -0
- unicex/kucoin/uni_client.py +2 -14
- unicex/mexc/_spot_ws_proto/__init__.py +335 -335
- unicex/mexc/adapter.py +1 -0
- unicex/mexc/websocket_manager.py +2 -4
- unicex/okx/adapter.py +1 -0
- unicex/types.py +4 -1
- unicex/utils.py +22 -1
- {unicex-0.15.1.dist-info → unicex-0.15.4.dist-info}/METADATA +1 -1
- {unicex-0.15.1.dist-info → unicex-0.15.4.dist-info}/RECORD +28 -28
- {unicex-0.15.1.dist-info → unicex-0.15.4.dist-info}/WHEEL +0 -0
- {unicex-0.15.1.dist-info → unicex-0.15.4.dist-info}/licenses/LICENSE +0 -0
- {unicex-0.15.1.dist-info → unicex-0.15.4.dist-info}/top_level.txt +0 -0
unicex/_abc/exchange_info.py
CHANGED
|
@@ -17,7 +17,7 @@ if TYPE_CHECKING:
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
class IExchangeInfo(ABC):
|
|
20
|
-
"""Интерфейс
|
|
20
|
+
"""Интерфейс класса, который обновляет информацию о правилах торговли на бирже."""
|
|
21
21
|
|
|
22
22
|
_loaded: bool
|
|
23
23
|
"""Флаг, указывающий, была ли информация о бирже загружена."""
|
unicex/_abc/uni_client.py
CHANGED
|
@@ -16,7 +16,7 @@ type CallbackType = Callable[[Any], Awaitable[None]]
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
class IUniWebsocketManager(ABC):
|
|
19
|
-
"""Интерфейс менеджера
|
|
19
|
+
"""Интерфейс менеджера унифицированных вебсокетов."""
|
|
20
20
|
|
|
21
21
|
def __init__(
|
|
22
22
|
self, client: BaseClient | IUniClient | None = None, logger: LoggerLike | None = None
|
unicex/_base/client.py
CHANGED
|
@@ -203,6 +203,9 @@ class BaseClient:
|
|
|
203
203
|
response_json=response_json,
|
|
204
204
|
) from None
|
|
205
205
|
|
|
206
|
+
# Валидирование ответа в конерктной реализации клиента
|
|
207
|
+
self._validate_response(response_json)
|
|
208
|
+
|
|
206
209
|
# Логирование ответа
|
|
207
210
|
try:
|
|
208
211
|
self._logger.debug(
|
|
@@ -212,3 +215,7 @@ class BaseClient:
|
|
|
212
215
|
self._logger.error(f"Error while logging response: {e}")
|
|
213
216
|
|
|
214
217
|
return response_json
|
|
218
|
+
|
|
219
|
+
def _validate_response(self, response_json: dict[str, Any]) -> None:
|
|
220
|
+
"""Проверка ответа API на ошибки биржи. Переопределяется в клиентах конкретных бирж."""
|
|
221
|
+
return None
|
unicex/binance/adapter.py
CHANGED
|
@@ -115,7 +115,11 @@ class Adapter:
|
|
|
115
115
|
Возвращает:
|
|
116
116
|
OpenInterestItem: Словарь со временем и объемом открытого интереса в монетах.
|
|
117
117
|
"""
|
|
118
|
-
return OpenInterestItem(
|
|
118
|
+
return OpenInterestItem(
|
|
119
|
+
t=raw_data["time"],
|
|
120
|
+
v=float(raw_data["openInterest"]),
|
|
121
|
+
u="coins",
|
|
122
|
+
)
|
|
119
123
|
|
|
120
124
|
@staticmethod
|
|
121
125
|
def klines_message(raw_msg: dict) -> list[KlineDict]:
|
unicex/bingx/adapter.py
CHANGED
|
@@ -68,7 +68,7 @@ class Adapter:
|
|
|
68
68
|
OpenInterestItem: Словарь со временем и объемом открытого интереса в монетах.
|
|
69
69
|
"""
|
|
70
70
|
item = raw_data["data"]
|
|
71
|
-
return OpenInterestItem(t=int(item["time"]), v=float(item["openInterest"]))
|
|
71
|
+
return OpenInterestItem(t=int(item["time"]), v=float(item["openInterest"]), u="usd")
|
|
72
72
|
|
|
73
73
|
@staticmethod
|
|
74
74
|
def funding_rate(raw_data: dict) -> dict[str, float]:
|
|
@@ -9,6 +9,7 @@ from typing import Any, Literal
|
|
|
9
9
|
import orjson
|
|
10
10
|
|
|
11
11
|
from unicex._base import Websocket
|
|
12
|
+
from unicex.utils import validate_single_symbol_args
|
|
12
13
|
|
|
13
14
|
from .client import Client
|
|
14
15
|
|
|
@@ -101,10 +102,7 @@ class WebsocketManager:
|
|
|
101
102
|
Возвращает:
|
|
102
103
|
`Websocket`: Объект для управления вебсокет соединением.
|
|
103
104
|
"""
|
|
104
|
-
|
|
105
|
-
raise ValueError("Parameters symbol and symbols cannot be used together")
|
|
106
|
-
if not (symbol or symbols):
|
|
107
|
-
raise ValueError("Either symbol or symbols must be provided")
|
|
105
|
+
validate_single_symbol_args(symbol, symbols)
|
|
108
106
|
|
|
109
107
|
tickers = [symbol] if symbol else symbols
|
|
110
108
|
data_types = [f"{ticker.upper()}@trade" for ticker in tickers] # type: ignore[arg-type]
|
unicex/bitget/adapter.py
CHANGED
|
@@ -6,6 +6,7 @@ from collections.abc import Awaitable, Callable, Sequence
|
|
|
6
6
|
from typing import Any, Literal
|
|
7
7
|
|
|
8
8
|
from unicex._base import Websocket
|
|
9
|
+
from unicex.utils import validate_single_symbol_args
|
|
9
10
|
|
|
10
11
|
from .client import Client
|
|
11
12
|
|
|
@@ -46,10 +47,7 @@ class WebsocketManager:
|
|
|
46
47
|
Возвращает:
|
|
47
48
|
`str`: JSON-строка с сообщением для подписки на вебсокет.
|
|
48
49
|
"""
|
|
49
|
-
|
|
50
|
-
raise ValueError("Parameters symbol and symbols cannot be used together")
|
|
51
|
-
if not (symbol or symbols):
|
|
52
|
-
raise ValueError("Either symbol or symbols must be provided")
|
|
50
|
+
validate_single_symbol_args(symbol, symbols)
|
|
53
51
|
|
|
54
52
|
tickers = [symbol] if symbol else symbols
|
|
55
53
|
streams: list[dict] = [
|
unicex/bybit/adapter.py
CHANGED
|
@@ -6,6 +6,7 @@ from collections.abc import Awaitable, Callable, Sequence
|
|
|
6
6
|
from typing import Any, Literal
|
|
7
7
|
|
|
8
8
|
from unicex._base import Websocket
|
|
9
|
+
from unicex.utils import validate_single_symbol_args
|
|
9
10
|
|
|
10
11
|
from .client import Client
|
|
11
12
|
|
|
@@ -108,10 +109,7 @@ class WebsocketManager:
|
|
|
108
109
|
Возвращает:
|
|
109
110
|
`Websocket`: Объект для управления вебсокет соединением.
|
|
110
111
|
"""
|
|
111
|
-
|
|
112
|
-
raise ValueError("Parameters symbol and symbols cannot be used together")
|
|
113
|
-
if not (symbol or symbols):
|
|
114
|
-
raise ValueError("Either symbol or symbols must be provided")
|
|
112
|
+
validate_single_symbol_args(symbol, symbols)
|
|
115
113
|
|
|
116
114
|
tickers = [symbol] if symbol else symbols
|
|
117
115
|
topics = [f"orderbook.{depth}.{ticker.upper()}" for ticker in tickers] # type: ignore
|
|
@@ -152,10 +150,7 @@ class WebsocketManager:
|
|
|
152
150
|
Возвращает:
|
|
153
151
|
`Websocket`: Объект для управления вебсокет соединением.
|
|
154
152
|
"""
|
|
155
|
-
|
|
156
|
-
raise ValueError("Parameters symbol and symbols cannot be used together")
|
|
157
|
-
if not (symbol or symbols):
|
|
158
|
-
raise ValueError("Either symbol or symbols must be provided")
|
|
153
|
+
validate_single_symbol_args(symbol, symbols)
|
|
159
154
|
|
|
160
155
|
tickers = [symbol] if symbol else symbols
|
|
161
156
|
topics = [f"kline.{interval}.{ticker.upper()}" for ticker in tickers] # type: ignore
|
|
@@ -192,10 +187,7 @@ class WebsocketManager:
|
|
|
192
187
|
Возвращает:
|
|
193
188
|
`Websocket`: Объект для управления вебсокет соединением.
|
|
194
189
|
"""
|
|
195
|
-
|
|
196
|
-
raise ValueError("Parameters symbol and symbols cannot be used together")
|
|
197
|
-
if not (symbol or symbols):
|
|
198
|
-
raise ValueError("Either symbol or symbols must be provided")
|
|
190
|
+
validate_single_symbol_args(symbol, symbols)
|
|
199
191
|
|
|
200
192
|
tickers = [symbol] if symbol else symbols
|
|
201
193
|
topics = [f"publicTrade.{ticker.upper()}" for ticker in tickers] # type: ignore
|
|
@@ -232,10 +224,7 @@ class WebsocketManager:
|
|
|
232
224
|
Возвращает:
|
|
233
225
|
`Websocket`: Объект для управления вебсокет соединением.
|
|
234
226
|
"""
|
|
235
|
-
|
|
236
|
-
raise ValueError("Parameters symbol and symbols cannot be used together")
|
|
237
|
-
if not (symbol or symbols):
|
|
238
|
-
raise ValueError("Either symbol or symbols must be provided")
|
|
227
|
+
validate_single_symbol_args(symbol, symbols)
|
|
239
228
|
|
|
240
229
|
tickers = [symbol] if symbol else symbols
|
|
241
230
|
topics = [f"tickers.{ticker.upper()}" for ticker in tickers] # type: ignore
|
|
@@ -280,10 +269,7 @@ class WebsocketManager:
|
|
|
280
269
|
stacklevel=2,
|
|
281
270
|
)
|
|
282
271
|
|
|
283
|
-
|
|
284
|
-
raise ValueError("Parameters symbol and symbols cannot be used together")
|
|
285
|
-
if not (symbol or symbols):
|
|
286
|
-
raise ValueError("Either symbol or symbols must be provided")
|
|
272
|
+
validate_single_symbol_args(symbol, symbols)
|
|
287
273
|
|
|
288
274
|
tickers = [symbol] if symbol else symbols
|
|
289
275
|
topics = [f"liquidation.{ticker.upper()}" for ticker in tickers] # type: ignore
|
|
@@ -320,10 +306,7 @@ class WebsocketManager:
|
|
|
320
306
|
Возвращает:
|
|
321
307
|
`Websocket`: Объект для управления вебсокет соединением.
|
|
322
308
|
"""
|
|
323
|
-
|
|
324
|
-
raise ValueError("Parameters symbol and symbols cannot be used together")
|
|
325
|
-
if not (symbol or symbols):
|
|
326
|
-
raise ValueError("Either symbol or symbols must be provided")
|
|
309
|
+
validate_single_symbol_args(symbol, symbols)
|
|
327
310
|
|
|
328
311
|
tickers = [symbol] if symbol else symbols
|
|
329
312
|
topics = [f"allLiquidation.{ticker.upper()}" for ticker in tickers] # type: ignore
|
unicex/extra.py
CHANGED
|
@@ -179,23 +179,22 @@ def generate_ex_link(exchange: Exchange, market_type: MarketType, symbol: str):
|
|
|
179
179
|
Возвращает:
|
|
180
180
|
`str`: Ссылка на биржу.
|
|
181
181
|
"""
|
|
182
|
-
symbol = normalize_symbol(symbol)
|
|
183
182
|
ticker = normalize_ticker(symbol)
|
|
184
183
|
if exchange == Exchange.BINANCE:
|
|
185
184
|
if market_type == MarketType.FUTURES:
|
|
186
|
-
return f"https://www.binance.com/en/futures/{
|
|
185
|
+
return f"https://www.binance.com/en/futures/{ticker}USDT"
|
|
187
186
|
else:
|
|
188
187
|
return f"https://www.binance.com/en/trade/{ticker}_USDT?type=spot"
|
|
189
188
|
elif exchange == Exchange.BYBIT:
|
|
190
189
|
if market_type == MarketType.FUTURES:
|
|
191
|
-
return f"https://www.bybit.com/trade/usdt/{
|
|
190
|
+
return f"https://www.bybit.com/trade/usdt/{ticker}USDT"
|
|
192
191
|
else:
|
|
193
192
|
return f"https://www.bybit.com/en/trade/spot/{ticker}/USDT"
|
|
194
193
|
elif exchange == Exchange.BITGET:
|
|
195
194
|
if market_type == MarketType.FUTURES:
|
|
196
|
-
return f"https://www.bitget.com/ru/futures/usdt/{
|
|
195
|
+
return f"https://www.bitget.com/ru/futures/usdt/{ticker}USDT"
|
|
197
196
|
else:
|
|
198
|
-
return f"https://www.bitget.com/ru/spot/{
|
|
197
|
+
return f"https://www.bitget.com/ru/spot/{ticker}USDT"
|
|
199
198
|
elif exchange == Exchange.OKX:
|
|
200
199
|
if market_type == MarketType.FUTURES:
|
|
201
200
|
return f"https://www.okx.com/ru/trade-swap/{ticker.lower()}-usdt-swap"
|
|
@@ -218,14 +217,14 @@ def generate_ex_link(exchange: Exchange, market_type: MarketType, symbol: str):
|
|
|
218
217
|
return f"https://app.hyperliquid.xyz/trade/{ticker}/USDC"
|
|
219
218
|
elif exchange == Exchange.KUCOIN:
|
|
220
219
|
if market_type == MarketType.FUTURES:
|
|
221
|
-
return f"https://www.kucoin.com/trade/futures/{
|
|
220
|
+
return f"https://www.kucoin.com/trade/futures/{ticker}USDTM"
|
|
222
221
|
else:
|
|
223
222
|
return f"https://www.kucoin.com/trade/{ticker}-USDT"
|
|
224
223
|
elif exchange == Exchange.BINGX:
|
|
225
224
|
if market_type == MarketType.FUTURES:
|
|
226
|
-
return f"https://bingx.com/en/spot/{symbol}"
|
|
227
|
-
else:
|
|
228
225
|
return f"https://bingx.com/en/perpetual/{ticker}-USDT"
|
|
226
|
+
else:
|
|
227
|
+
return f"https://bingx.com/en/spot/{ticker}USDT"
|
|
229
228
|
else:
|
|
230
229
|
raise NotSupported(f"Exchange {exchange} is not supported")
|
|
231
230
|
|
|
@@ -260,34 +259,35 @@ def generate_cg_link(exchange: Exchange, market_type: MarketType, symbol: str) -
|
|
|
260
259
|
Возвращает:
|
|
261
260
|
`str`: Ссылка для CoinGlass.
|
|
262
261
|
"""
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
symbol = normalize_symbol(symbol)
|
|
262
|
+
ticker = normalize_ticker(symbol)
|
|
266
263
|
|
|
264
|
+
base_url = "https://www.coinglass.com/tv/ru"
|
|
267
265
|
if market_type == MarketType.FUTURES:
|
|
268
266
|
match exchange:
|
|
269
267
|
case Exchange.OKX:
|
|
270
|
-
return f"{base_url}/OKX_{
|
|
268
|
+
return f"{base_url}/OKX_{ticker}-USDT-SWAP"
|
|
271
269
|
case Exchange.MEXC:
|
|
272
|
-
return f"{base_url}/MEXC_{
|
|
270
|
+
return f"{base_url}/MEXC_{ticker}_USDT"
|
|
273
271
|
case Exchange.BITGET:
|
|
274
|
-
return f"{base_url}/Bitget_{
|
|
272
|
+
return f"{base_url}/Bitget_{ticker}USDT_UMCBL"
|
|
275
273
|
case Exchange.GATE:
|
|
276
|
-
return f"{base_url}/Gate_{
|
|
274
|
+
return f"{base_url}/Gate_{ticker}_USDT"
|
|
277
275
|
case Exchange.HYPERLIQUID:
|
|
278
|
-
return f"{base_url}/Hyperliquid_{
|
|
276
|
+
return f"{base_url}/Hyperliquid_{ticker}-USD"
|
|
279
277
|
case Exchange.KUCOIN:
|
|
280
|
-
return f"https://www.coinglass.com/tv/ru/KuCoin_{
|
|
278
|
+
return f"https://www.coinglass.com/tv/ru/KuCoin_{ticker}USDTM"
|
|
281
279
|
case Exchange.BINGX:
|
|
282
|
-
return f"https://www.coinglass.com/tv/ru/BingX_{
|
|
280
|
+
return f"https://www.coinglass.com/tv/ru/BingX_{ticker}-USDT"
|
|
283
281
|
case _:
|
|
284
|
-
return f"{base_url}/{exchange.capitalize()}_{
|
|
282
|
+
return f"{base_url}/{exchange.capitalize()}_{ticker}USDT"
|
|
285
283
|
else:
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
284
|
+
match exchange:
|
|
285
|
+
case Exchange.OKX:
|
|
286
|
+
return f"{base_url}/SPOT_{exchange.upper()}_{ticker}-USDT"
|
|
287
|
+
case Exchange.GATE:
|
|
288
|
+
return f"{base_url}/SPOT_{exchange.capitalize()}_{ticker}_USDT"
|
|
289
|
+
case _:
|
|
290
|
+
return f"{base_url}/SPOT_{exchange.capitalize()}_{ticker}USDT"
|
|
291
291
|
|
|
292
292
|
|
|
293
293
|
def make_humanreadable(value: float, locale: Literal["ru", "en"] = "ru") -> str:
|
unicex/gate/adapter.py
CHANGED
unicex/hyperliquid/adapter.py
CHANGED
unicex/kucoin/adapter.py
CHANGED
|
@@ -126,27 +126,22 @@ class Adapter:
|
|
|
126
126
|
item["symbol"]: OpenInterestItem(
|
|
127
127
|
t=item["ts"],
|
|
128
128
|
v=float(item["openInterest"]) * Adapter._get_contract_size(item["symbol"]),
|
|
129
|
+
u="coins",
|
|
129
130
|
)
|
|
130
131
|
for item in raw_data["data"]
|
|
131
132
|
}
|
|
132
133
|
|
|
133
134
|
@staticmethod
|
|
134
|
-
def funding_rate(raw_data: dict) ->
|
|
135
|
+
def funding_rate(raw_data: dict) -> float:
|
|
135
136
|
"""Преобразует историю ставок финансирования в унифицированный формат.
|
|
136
137
|
|
|
137
138
|
Параметры:
|
|
138
139
|
raw_data (dict): Сырой ответ с биржи.
|
|
139
140
|
|
|
140
141
|
Возвращает:
|
|
141
|
-
|
|
142
|
+
float: Актуальная ставка финансирования.
|
|
142
143
|
"""
|
|
143
|
-
|
|
144
|
-
history = raw_data["data"]["list"]
|
|
145
|
-
if not history:
|
|
146
|
-
return {}
|
|
147
|
-
|
|
148
|
-
last_point = max(history, key=lambda item: int(item["ts"]))
|
|
149
|
-
return {symbol: float(last_point["fundingRate"]) * 100}
|
|
144
|
+
return round(raw_data["data"]["nextFundingRate"] * 100, 6)
|
|
150
145
|
|
|
151
146
|
@staticmethod
|
|
152
147
|
def _get_contract_size(symbol: str) -> float:
|
unicex/kucoin/client.py
CHANGED
|
@@ -120,3 +120,16 @@ class Client(BaseClient):
|
|
|
120
120
|
"/api/ua/v1/market/funding-rate-history",
|
|
121
121
|
params=params,
|
|
122
122
|
)
|
|
123
|
+
|
|
124
|
+
async def funding_rate(self, symbol: str) -> dict[str, Any]:
|
|
125
|
+
"""Получение текущей ставки финансирования.
|
|
126
|
+
|
|
127
|
+
https://www.kucoin.com/docs-new/rest/ua/get-current-funding-rate
|
|
128
|
+
"""
|
|
129
|
+
params = {"symbol": symbol}
|
|
130
|
+
|
|
131
|
+
return await self._make_request(
|
|
132
|
+
"GET",
|
|
133
|
+
"/api/ua/v1/market/funding-rate",
|
|
134
|
+
params=params,
|
|
135
|
+
)
|
unicex/kucoin/uni_client.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
__all__ = ["UniClient"]
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
import time
|
|
5
4
|
from typing import overload
|
|
6
5
|
|
|
7
6
|
from unicex._abc import IUniClient
|
|
@@ -181,19 +180,8 @@ class UniClient(IUniClient[Client]):
|
|
|
181
180
|
"""
|
|
182
181
|
if not symbol:
|
|
183
182
|
raise ValueError("Symbol is required to fetch Kucoin funding rate")
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
# Kucoin публикует ставку каждые 8 часов, берем окно в 24 часа для гарантии наличия записи.
|
|
187
|
-
start_time = end_time - 24 * 60 * 60 * 1000
|
|
188
|
-
raw_data = await self._client.funding_rate_history(
|
|
189
|
-
symbol=symbol,
|
|
190
|
-
start_at=start_time,
|
|
191
|
-
end_at=end_time,
|
|
192
|
-
)
|
|
193
|
-
adapted_data = Adapter.funding_rate(raw_data)
|
|
194
|
-
if symbol not in adapted_data:
|
|
195
|
-
raise ValueError(f"Kucoin funding rate history is empty for {symbol}")
|
|
196
|
-
return adapted_data[symbol]
|
|
183
|
+
raw_data = await self._client.funding_rate(symbol=symbol)
|
|
184
|
+
return Adapter.funding_rate(raw_data)
|
|
197
185
|
|
|
198
186
|
@overload
|
|
199
187
|
async def open_interest(self, symbol: str) -> OpenInterestItem: ...
|