unicex 0.13.17__py3-none-any.whl → 0.16.5__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 +36 -2
- unicex/_abc/exchange_info.py +1 -1
- unicex/_abc/uni_client.py +31 -1
- unicex/_abc/uni_websocket_manager.py +1 -1
- unicex/_base/client.py +7 -0
- unicex/_base/websocket.py +31 -9
- unicex/binance/adapter.py +7 -16
- unicex/binance/client.py +25 -25
- unicex/binance/uni_websocket_manager.py +6 -2
- unicex/bingx/__init__.py +27 -0
- unicex/bingx/adapter.py +284 -0
- unicex/bingx/client.py +521 -0
- unicex/bingx/exchange_info.py +22 -0
- unicex/bingx/uni_client.py +191 -0
- unicex/bingx/uni_websocket_manager.py +283 -0
- unicex/bingx/user_websocket.py +7 -0
- unicex/bingx/websocket_manager.py +118 -0
- unicex/bitget/adapter.py +2 -2
- unicex/bitget/client.py +64 -64
- unicex/bitget/uni_websocket_manager.py +27 -6
- unicex/bitget/websocket_manager.py +2 -4
- unicex/bybit/adapter.py +1 -0
- unicex/bybit/client.py +4 -4
- unicex/bybit/exchange_info.py +1 -1
- unicex/bybit/uni_websocket_manager.py +33 -4
- unicex/bybit/websocket_manager.py +8 -24
- unicex/enums.py +19 -3
- unicex/extra.py +37 -35
- unicex/gate/adapter.py +113 -0
- unicex/gate/client.py +9 -9
- unicex/gate/uni_client.py +1 -3
- unicex/gate/uni_websocket_manager.py +47 -9
- unicex/hyperliquid/adapter.py +1 -0
- unicex/hyperliquid/client.py +12 -12
- unicex/hyperliquid/uni_client.py +4 -7
- unicex/hyperliquid/uni_websocket_manager.py +6 -2
- unicex/kucoin/__init__.py +27 -0
- unicex/kucoin/adapter.py +181 -0
- unicex/kucoin/client.py +135 -0
- unicex/kucoin/exchange_info.py +50 -0
- unicex/kucoin/uni_client.py +208 -0
- unicex/kucoin/uni_websocket_manager.py +273 -0
- unicex/kucoin/user_websocket.py +7 -0
- unicex/kucoin/websocket_manager.py +11 -0
- unicex/mapper.py +62 -21
- unicex/mexc/adapter.py +104 -0
- unicex/mexc/client.py +7 -7
- unicex/mexc/uni_client.py +1 -3
- unicex/mexc/uni_websocket_manager.py +31 -9
- unicex/mexc/websocket_manager.py +27 -6
- unicex/okx/adapter.py +51 -0
- unicex/okx/client.py +15 -15
- unicex/okx/exchange_info.py +2 -2
- unicex/okx/uni_websocket_manager.py +50 -9
- unicex/okx/websocket_manager.py +119 -166
- unicex/types.py +14 -10
- unicex/utils.py +44 -1
- {unicex-0.13.17.dist-info → unicex-0.16.5.dist-info}/METADATA +7 -5
- unicex-0.16.5.dist-info/RECORD +109 -0
- unicex-0.13.17.dist-info/RECORD +0 -93
- {unicex-0.13.17.dist-info → unicex-0.16.5.dist-info}/WHEEL +0 -0
- {unicex-0.13.17.dist-info → unicex-0.16.5.dist-info}/licenses/LICENSE +0 -0
- {unicex-0.13.17.dist-info → unicex-0.16.5.dist-info}/top_level.txt +0 -0
unicex/mexc/websocket_manager.py
CHANGED
|
@@ -8,6 +8,7 @@ import orjson
|
|
|
8
8
|
from google.protobuf.json_format import MessageToDict
|
|
9
9
|
|
|
10
10
|
from unicex._base import Websocket
|
|
11
|
+
from unicex.utils import validate_single_symbol_args
|
|
11
12
|
|
|
12
13
|
from ._spot_ws_proto import PushDataV3ApiWrapper
|
|
13
14
|
from .client import Client
|
|
@@ -27,7 +28,7 @@ class WebsocketManager:
|
|
|
27
28
|
class _MexcProtobufDecoder:
|
|
28
29
|
"""Класс для декодирования сообщений в формате Protobuf со спотового рынка Mexc."""
|
|
29
30
|
|
|
30
|
-
def decode(self, message: Any) -> dict:
|
|
31
|
+
def decode(self, message: Any) -> dict | Literal["ping"]:
|
|
31
32
|
if isinstance(message, bytes):
|
|
32
33
|
wrapper = PushDataV3ApiWrapper() # noqa
|
|
33
34
|
wrapper.ParseFromString(message)
|
|
@@ -55,10 +56,7 @@ class WebsocketManager:
|
|
|
55
56
|
**template_kwargs: Any,
|
|
56
57
|
) -> list[str]:
|
|
57
58
|
"""Сформировать сообщение для подписки на вебсокет."""
|
|
58
|
-
|
|
59
|
-
raise ValueError("Parameters symbol and symbols cannot be used together")
|
|
60
|
-
if not (symbol or symbols):
|
|
61
|
-
raise ValueError("Either symbol or symbols must be provided")
|
|
59
|
+
validate_single_symbol_args(symbol, symbols)
|
|
62
60
|
|
|
63
61
|
if symbol:
|
|
64
62
|
params = [channel_template.format(symbol=symbol, **template_kwargs)]
|
|
@@ -382,7 +380,30 @@ class WebsocketManager:
|
|
|
382
380
|
`Websocket`: Объект для управления вебсокет соединением.
|
|
383
381
|
"""
|
|
384
382
|
subscription_messages = self._generate_futures_subscription_message(
|
|
385
|
-
topic="sub.
|
|
383
|
+
topic="sub.kline", symbol=symbol, symbols=symbols, interval=interval
|
|
384
|
+
)
|
|
385
|
+
return self._create_futures_websocket(callback, subscription_messages)
|
|
386
|
+
|
|
387
|
+
def futures_trade(
|
|
388
|
+
self,
|
|
389
|
+
callback: CallbackType,
|
|
390
|
+
symbol: str | None = None,
|
|
391
|
+
symbols: Sequence[str] | None = None,
|
|
392
|
+
) -> Websocket:
|
|
393
|
+
"""Создает вебсокет для получения сделок по фьючерсным контрактам.
|
|
394
|
+
|
|
395
|
+
https://mexcdevelop.github.io/apidocs/contract_v1_en/#public-channels
|
|
396
|
+
|
|
397
|
+
Параметры:
|
|
398
|
+
callback (`CallbackType`): Асинхронная функция обратного вызова для обработки сообщений.
|
|
399
|
+
symbol (`str | None`): Символ фьючерсного контракта.
|
|
400
|
+
symbols (`Sequence[str] | None`): Последовательность символов фьючерсных контрактов.
|
|
401
|
+
|
|
402
|
+
Возвращает:
|
|
403
|
+
`Websocket`: Объект для управления вебсокет соединением.
|
|
404
|
+
"""
|
|
405
|
+
subscription_messages = self._generate_futures_subscription_message(
|
|
406
|
+
topic="sub.deal", symbol=symbol, symbols=symbols
|
|
386
407
|
)
|
|
387
408
|
return self._create_futures_websocket(callback, subscription_messages)
|
|
388
409
|
|
unicex/okx/adapter.py
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
__all__ = ["Adapter"]
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
4
6
|
from unicex.types import (
|
|
5
7
|
KlineDict,
|
|
6
8
|
OpenInterestDict,
|
|
7
9
|
OpenInterestItem,
|
|
8
10
|
TickerDailyDict,
|
|
9
11
|
TickerDailyItem,
|
|
12
|
+
TradeDict,
|
|
10
13
|
)
|
|
11
14
|
from unicex.utils import catch_adapter_errors, decorate_all_methods
|
|
12
15
|
|
|
@@ -137,10 +140,58 @@ class Adapter:
|
|
|
137
140
|
item["instId"]: OpenInterestItem(
|
|
138
141
|
t=int(item["ts"]),
|
|
139
142
|
v=float(item["oiCcy"]),
|
|
143
|
+
u="coins",
|
|
140
144
|
)
|
|
141
145
|
for item in raw_data["data"]
|
|
142
146
|
}
|
|
143
147
|
|
|
148
|
+
@staticmethod
|
|
149
|
+
def klines_message(raw_msg: Any) -> list[KlineDict]:
|
|
150
|
+
"""Преобразует вебсокет-сообщение со свечами в унифицированный формат.
|
|
151
|
+
|
|
152
|
+
Параметры:
|
|
153
|
+
raw_msg (Any): Сырое сообщение с вебсокета.
|
|
154
|
+
|
|
155
|
+
Возвращает:
|
|
156
|
+
list[KlineDict]: Список свечей в унифицированном формате.
|
|
157
|
+
"""
|
|
158
|
+
return [
|
|
159
|
+
KlineDict(
|
|
160
|
+
s=raw_msg["arg"]["instId"],
|
|
161
|
+
t=int(kline[0]),
|
|
162
|
+
o=float(kline[1]),
|
|
163
|
+
h=float(kline[2]),
|
|
164
|
+
l=float(kline[3]),
|
|
165
|
+
c=float(kline[4]),
|
|
166
|
+
v=float(kline[6]),
|
|
167
|
+
q=float(kline[7]),
|
|
168
|
+
T=None,
|
|
169
|
+
x=bool(int(kline[8])),
|
|
170
|
+
)
|
|
171
|
+
for kline in sorted(raw_msg["data"], key=lambda item: int(item[0]))
|
|
172
|
+
]
|
|
173
|
+
|
|
174
|
+
@staticmethod
|
|
175
|
+
def trades_message(raw_msg: Any) -> list[TradeDict]:
|
|
176
|
+
"""Преобразует вебсокет-сообщение со сделками в унифицированный формат.
|
|
177
|
+
|
|
178
|
+
Параметры:
|
|
179
|
+
raw_msg (Any): Сырое сообщение с вебсокета.
|
|
180
|
+
|
|
181
|
+
Возвращает:
|
|
182
|
+
list[TradeDict]: Список сделок в унифицированном формате.
|
|
183
|
+
"""
|
|
184
|
+
return [
|
|
185
|
+
TradeDict(
|
|
186
|
+
t=int(trade["ts"]),
|
|
187
|
+
s=trade["instId"],
|
|
188
|
+
S=trade["side"].upper(),
|
|
189
|
+
p=float(trade["px"]),
|
|
190
|
+
v=float(trade["sz"]) * Adapter._get_contract_size(trade["instId"]),
|
|
191
|
+
)
|
|
192
|
+
for trade in sorted(raw_msg["data"], key=lambda item: int(item["ts"]))
|
|
193
|
+
]
|
|
194
|
+
|
|
144
195
|
@staticmethod
|
|
145
196
|
def _get_contract_size(symbol: str) -> float:
|
|
146
197
|
"""Возвращает размер контракта для указанного символа тикера."""
|
unicex/okx/client.py
CHANGED
|
@@ -6,7 +6,7 @@ from typing import Any, Literal
|
|
|
6
6
|
|
|
7
7
|
from unicex._base import BaseClient
|
|
8
8
|
from unicex.exceptions import NotAuthorized
|
|
9
|
-
from unicex.types import RequestMethod
|
|
9
|
+
from unicex.types import NumberLike, RequestMethod
|
|
10
10
|
from unicex.utils import filter_params, generate_hmac_sha256_signature
|
|
11
11
|
|
|
12
12
|
|
|
@@ -510,7 +510,7 @@ class Client(BaseClient):
|
|
|
510
510
|
inst_id: str,
|
|
511
511
|
td_mode: Literal["cross", "isolated", "cash", "spot_isolated"],
|
|
512
512
|
ccy: str | None = None,
|
|
513
|
-
px:
|
|
513
|
+
px: NumberLike | None = None,
|
|
514
514
|
leverage: str | None = None,
|
|
515
515
|
trade_quote_ccy: str | None = None,
|
|
516
516
|
) -> dict:
|
|
@@ -540,7 +540,7 @@ class Client(BaseClient):
|
|
|
540
540
|
td_mode: Literal["cross", "isolated", "cash", "spot_isolated"],
|
|
541
541
|
ccy: str | None = None,
|
|
542
542
|
reduce_only: bool | None = None,
|
|
543
|
-
px:
|
|
543
|
+
px: NumberLike | None = None,
|
|
544
544
|
trade_quote_ccy: str | None = None,
|
|
545
545
|
) -> dict:
|
|
546
546
|
"""Получение максимального доступного баланса/эквити.
|
|
@@ -1313,14 +1313,14 @@ class Client(BaseClient):
|
|
|
1313
1313
|
"mmp_and_post_only",
|
|
1314
1314
|
"op_fok",
|
|
1315
1315
|
],
|
|
1316
|
-
sz:
|
|
1316
|
+
sz: NumberLike,
|
|
1317
1317
|
ccy: str | None = None,
|
|
1318
1318
|
cl_ord_id: str | None = None,
|
|
1319
1319
|
tag: str | None = None,
|
|
1320
1320
|
pos_side: Literal["net", "long", "short"] | None = None,
|
|
1321
|
-
px:
|
|
1322
|
-
px_usd:
|
|
1323
|
-
px_vol:
|
|
1321
|
+
px: NumberLike | None = None,
|
|
1322
|
+
px_usd: NumberLike | None = None,
|
|
1323
|
+
px_vol: NumberLike | None = None,
|
|
1324
1324
|
reduce_only: bool | None = None,
|
|
1325
1325
|
tgt_ccy: Literal["base_ccy", "quote_ccy"] | None = None,
|
|
1326
1326
|
ban_amend: bool | None = None,
|
|
@@ -1430,10 +1430,10 @@ class Client(BaseClient):
|
|
|
1430
1430
|
ord_id: str | None = None,
|
|
1431
1431
|
cl_ord_id: str | None = None,
|
|
1432
1432
|
*,
|
|
1433
|
-
new_sz:
|
|
1434
|
-
new_px:
|
|
1435
|
-
new_px_usd:
|
|
1436
|
-
new_px_vol:
|
|
1433
|
+
new_sz: NumberLike | None = None,
|
|
1434
|
+
new_px: NumberLike | None = None,
|
|
1435
|
+
new_px_usd: NumberLike | None = None,
|
|
1436
|
+
new_px_vol: NumberLike | None = None,
|
|
1437
1437
|
cxl_on_fail: bool | None = None,
|
|
1438
1438
|
req_id: str | None = None,
|
|
1439
1439
|
px_amend_type: Literal["0", "1"] | None = None,
|
|
@@ -1987,9 +1987,9 @@ class Client(BaseClient):
|
|
|
1987
1987
|
"ioc",
|
|
1988
1988
|
"optimal_limit_ioc",
|
|
1989
1989
|
],
|
|
1990
|
-
sz:
|
|
1990
|
+
sz: NumberLike,
|
|
1991
1991
|
pos_side: Literal["net", "long", "short"] | None = None,
|
|
1992
|
-
px:
|
|
1992
|
+
px: NumberLike | None = None,
|
|
1993
1993
|
reduce_only: bool | None = None,
|
|
1994
1994
|
tgt_ccy: Literal["base_ccy", "quote_ccy"] | None = None,
|
|
1995
1995
|
attach_algo_orders: list[dict[str, Any]] | None = None,
|
|
@@ -2592,9 +2592,9 @@ class Client(BaseClient):
|
|
|
2592
2592
|
async def convert_contract_coin(
|
|
2593
2593
|
self,
|
|
2594
2594
|
inst_id: str,
|
|
2595
|
-
sz:
|
|
2595
|
+
sz: NumberLike,
|
|
2596
2596
|
type_: Literal["1", "2"] | None = None,
|
|
2597
|
-
px:
|
|
2597
|
+
px: NumberLike | None = None,
|
|
2598
2598
|
unit: Literal["coin", "usds"] | None = None,
|
|
2599
2599
|
op_type: Literal["open", "close"] | None = None,
|
|
2600
2600
|
) -> dict:
|
unicex/okx/exchange_info.py
CHANGED
|
@@ -22,9 +22,9 @@ class ExchangeInfo(IExchangeInfo):
|
|
|
22
22
|
for el in exchange_info["data"]:
|
|
23
23
|
tickers_info[el["instId"]] = TickerInfoItem(
|
|
24
24
|
tick_precision=None,
|
|
25
|
-
tick_step=float(el["tickSz"]),
|
|
25
|
+
tick_step=float(el["tickSz"] or "0"),
|
|
26
26
|
size_precision=None,
|
|
27
|
-
size_step=float(el["lotSz"]),
|
|
27
|
+
size_step=float(el["lotSz"] or "0"),
|
|
28
28
|
contract_size=1,
|
|
29
29
|
)
|
|
30
30
|
|
|
@@ -5,7 +5,7 @@ from typing import Any, overload
|
|
|
5
5
|
|
|
6
6
|
from unicex._abc import IUniWebsocketManager
|
|
7
7
|
from unicex._base import Websocket
|
|
8
|
-
from unicex.enums import Timeframe
|
|
8
|
+
from unicex.enums import Exchange, Timeframe
|
|
9
9
|
from unicex.types import LoggerLike
|
|
10
10
|
|
|
11
11
|
from .adapter import Adapter
|
|
@@ -20,18 +20,39 @@ class UniWebsocketManager(IUniWebsocketManager):
|
|
|
20
20
|
"""Реализация менеджера асинхронных унифицированных вебсокетов."""
|
|
21
21
|
|
|
22
22
|
def __init__(
|
|
23
|
-
self,
|
|
23
|
+
self,
|
|
24
|
+
client: Client | UniClient | None = None,
|
|
25
|
+
logger: LoggerLike | None = None,
|
|
26
|
+
**ws_kwargs: Any,
|
|
24
27
|
) -> None:
|
|
25
28
|
"""Инициализирует унифицированный менеджер вебсокетов.
|
|
26
29
|
|
|
27
30
|
Параметры:
|
|
28
31
|
client (`Client | UniClient | None`): Клиент Okx или унифицированный клиент. Нужен для подключения к приватным топикам.
|
|
29
32
|
logger (`LoggerLike | None`): Логгер для записи логов.
|
|
33
|
+
ws_kwargs (`dict[str, Any]`): Дополнительные параметры инициализации, которые будут переданы WebsocketManager/Websocket.
|
|
30
34
|
"""
|
|
31
35
|
super().__init__(client=client, logger=logger)
|
|
32
|
-
self._websocket_manager = WebsocketManager(self._client) # type: ignore
|
|
36
|
+
self._websocket_manager = WebsocketManager(self._client, **ws_kwargs) # type: ignore
|
|
33
37
|
self._adapter = Adapter()
|
|
34
38
|
|
|
39
|
+
def _normalize_symbol(
|
|
40
|
+
self,
|
|
41
|
+
symbol: str | None,
|
|
42
|
+
symbols: Sequence[str] | None,
|
|
43
|
+
) -> str:
|
|
44
|
+
"""Преобразует параметры symbol/symbols в один тикер."""
|
|
45
|
+
if symbol and symbols:
|
|
46
|
+
raise ValueError("Parameters symbol and symbols cannot be used together")
|
|
47
|
+
if symbol:
|
|
48
|
+
return symbol
|
|
49
|
+
if symbols:
|
|
50
|
+
normalized = list(symbols)
|
|
51
|
+
if len(normalized) != 1:
|
|
52
|
+
raise ValueError("OKX websocket поддерживает только один тикер на соединение")
|
|
53
|
+
return normalized[0]
|
|
54
|
+
raise ValueError("Either symbol or symbols must be provided")
|
|
55
|
+
|
|
35
56
|
@overload
|
|
36
57
|
def klines(
|
|
37
58
|
self,
|
|
@@ -72,7 +93,13 @@ class UniWebsocketManager(IUniWebsocketManager):
|
|
|
72
93
|
Возвращает:
|
|
73
94
|
`Websocket`: Экземпляр вебсокета для управления соединением.
|
|
74
95
|
"""
|
|
75
|
-
|
|
96
|
+
inst_id = self._normalize_symbol(symbol, symbols)
|
|
97
|
+
wrapper = self._make_wrapper(self._adapter.klines_message, callback)
|
|
98
|
+
return self._websocket_manager.candlesticks(
|
|
99
|
+
callback=wrapper,
|
|
100
|
+
interval=timeframe.to_exchange_format(Exchange.OKX), # type: ignore
|
|
101
|
+
inst_id=inst_id,
|
|
102
|
+
)
|
|
76
103
|
|
|
77
104
|
@overload
|
|
78
105
|
def futures_klines(
|
|
@@ -114,7 +141,13 @@ class UniWebsocketManager(IUniWebsocketManager):
|
|
|
114
141
|
Возвращает:
|
|
115
142
|
`Websocket`: Экземпляр вебсокета.
|
|
116
143
|
"""
|
|
117
|
-
|
|
144
|
+
inst_id = self._normalize_symbol(symbol, symbols)
|
|
145
|
+
wrapper = self._make_wrapper(self._adapter.klines_message, callback)
|
|
146
|
+
return self._websocket_manager.candlesticks(
|
|
147
|
+
callback=wrapper,
|
|
148
|
+
interval=timeframe.to_exchange_format(Exchange.OKX), # type: ignore
|
|
149
|
+
inst_id=inst_id,
|
|
150
|
+
)
|
|
118
151
|
|
|
119
152
|
@overload
|
|
120
153
|
def trades(
|
|
@@ -152,7 +185,9 @@ class UniWebsocketManager(IUniWebsocketManager):
|
|
|
152
185
|
Возвращает:
|
|
153
186
|
`Websocket`: Экземпляр вебсокета.
|
|
154
187
|
"""
|
|
155
|
-
|
|
188
|
+
inst_id = self._normalize_symbol(symbol, symbols)
|
|
189
|
+
wrapper = self._make_wrapper(self._adapter.trades_message, callback)
|
|
190
|
+
return self._websocket_manager.all_trades(callback=wrapper, inst_id=inst_id)
|
|
156
191
|
|
|
157
192
|
@overload
|
|
158
193
|
def aggtrades(
|
|
@@ -190,7 +225,9 @@ class UniWebsocketManager(IUniWebsocketManager):
|
|
|
190
225
|
Возвращает:
|
|
191
226
|
`Websocket`: Экземпляр вебсокета.
|
|
192
227
|
"""
|
|
193
|
-
|
|
228
|
+
inst_id = self._normalize_symbol(symbol, symbols)
|
|
229
|
+
wrapper = self._make_wrapper(self._adapter.trades_message, callback)
|
|
230
|
+
return self._websocket_manager.trades(callback=wrapper, inst_id=inst_id)
|
|
194
231
|
|
|
195
232
|
@overload
|
|
196
233
|
def futures_trades(
|
|
@@ -228,7 +265,9 @@ class UniWebsocketManager(IUniWebsocketManager):
|
|
|
228
265
|
Возвращает:
|
|
229
266
|
`Websocket`: Экземпляр вебсокета.
|
|
230
267
|
"""
|
|
231
|
-
|
|
268
|
+
inst_id = self._normalize_symbol(symbol, symbols)
|
|
269
|
+
wrapper = self._make_wrapper(self._adapter.trades_message, callback)
|
|
270
|
+
return self._websocket_manager.all_trades(callback=wrapper, inst_id=inst_id)
|
|
232
271
|
|
|
233
272
|
@overload
|
|
234
273
|
def futures_aggtrades(
|
|
@@ -266,4 +305,6 @@ class UniWebsocketManager(IUniWebsocketManager):
|
|
|
266
305
|
Возвращает:
|
|
267
306
|
`Websocket`: Экземпляр вебсокета.
|
|
268
307
|
"""
|
|
269
|
-
|
|
308
|
+
inst_id = self._normalize_symbol(symbol, symbols)
|
|
309
|
+
wrapper = self._make_wrapper(self._adapter.trades_message, callback)
|
|
310
|
+
return self._websocket_manager.trades(callback=wrapper, inst_id=inst_id)
|