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/okx/websocket_manager.py
CHANGED
|
@@ -15,13 +15,13 @@ type CallbackType = Callable[[Any], Awaitable[None]]
|
|
|
15
15
|
class WebsocketManager:
|
|
16
16
|
"""Менеджер асинхронных вебсокетов для Okx."""
|
|
17
17
|
|
|
18
|
-
_BASE_URL = "wss://ws.okx.com:8443/ws"
|
|
18
|
+
_BASE_URL: str = "wss://ws.okx.com:8443/ws"
|
|
19
19
|
"""Базовый URL вебсокетов на Okx."""
|
|
20
20
|
|
|
21
|
-
_PUBLIC_URL = _BASE_URL + "/v5/public"
|
|
21
|
+
_PUBLIC_URL: str = _BASE_URL + "/v5/public"
|
|
22
22
|
"""Публичный URL вебсокетов на Okx."""
|
|
23
23
|
|
|
24
|
-
_BUSINESS_URL = _BASE_URL + "/v5/business"
|
|
24
|
+
_BUSINESS_URL: str = _BASE_URL + "/v5/business"
|
|
25
25
|
"""Бизнес-URL вебсокетов на Okx. (для топиков trades-all и candle)"""
|
|
26
26
|
|
|
27
27
|
def __init__(self, client: Client | None = None, **ws_kwargs: Any) -> None:
|
|
@@ -34,6 +34,15 @@ class WebsocketManager:
|
|
|
34
34
|
self.client = client
|
|
35
35
|
self._ws_kwargs = {"ping_message": "ping", **ws_kwargs}
|
|
36
36
|
|
|
37
|
+
def _build_subscription_message(self, args: list[dict[str, Any]]) -> str:
|
|
38
|
+
"""Формирует JSON-сообщение подписки."""
|
|
39
|
+
return json.dumps(
|
|
40
|
+
{
|
|
41
|
+
"op": "subscribe",
|
|
42
|
+
"args": args,
|
|
43
|
+
}
|
|
44
|
+
)
|
|
45
|
+
|
|
37
46
|
def instruments(
|
|
38
47
|
self,
|
|
39
48
|
callback: CallbackType,
|
|
@@ -50,16 +59,13 @@ class WebsocketManager:
|
|
|
50
59
|
Возвращает:
|
|
51
60
|
`Websocket`: Объект для управления вебсокет соединением.
|
|
52
61
|
"""
|
|
53
|
-
subscription_message =
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
],
|
|
62
|
-
}
|
|
62
|
+
subscription_message = self._build_subscription_message(
|
|
63
|
+
[
|
|
64
|
+
{
|
|
65
|
+
"channel": "instruments",
|
|
66
|
+
"instType": inst_type,
|
|
67
|
+
}
|
|
68
|
+
]
|
|
63
69
|
)
|
|
64
70
|
|
|
65
71
|
return Websocket(
|
|
@@ -85,16 +91,13 @@ class WebsocketManager:
|
|
|
85
91
|
Возвращает:
|
|
86
92
|
`Websocket`: Объект для управления вебсокет соединением.
|
|
87
93
|
"""
|
|
88
|
-
subscription_message =
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
],
|
|
97
|
-
}
|
|
94
|
+
subscription_message = self._build_subscription_message(
|
|
95
|
+
[
|
|
96
|
+
{
|
|
97
|
+
"channel": "open-interest",
|
|
98
|
+
"instId": inst_id,
|
|
99
|
+
}
|
|
100
|
+
]
|
|
98
101
|
)
|
|
99
102
|
|
|
100
103
|
return Websocket(
|
|
@@ -120,16 +123,13 @@ class WebsocketManager:
|
|
|
120
123
|
Возвращает:
|
|
121
124
|
`Websocket`: Объект для управления вебсокет соединением.
|
|
122
125
|
"""
|
|
123
|
-
subscription_message =
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
131
|
-
],
|
|
132
|
-
}
|
|
126
|
+
subscription_message = self._build_subscription_message(
|
|
127
|
+
[
|
|
128
|
+
{
|
|
129
|
+
"channel": "funding-rate",
|
|
130
|
+
"instId": inst_id,
|
|
131
|
+
}
|
|
132
|
+
]
|
|
133
133
|
)
|
|
134
134
|
|
|
135
135
|
return Websocket(
|
|
@@ -155,16 +155,13 @@ class WebsocketManager:
|
|
|
155
155
|
Возвращает:
|
|
156
156
|
`Websocket`: Объект для управления вебсокет соединением.
|
|
157
157
|
"""
|
|
158
|
-
subscription_message =
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}
|
|
166
|
-
],
|
|
167
|
-
}
|
|
158
|
+
subscription_message = self._build_subscription_message(
|
|
159
|
+
[
|
|
160
|
+
{
|
|
161
|
+
"channel": "price-limit",
|
|
162
|
+
"instId": inst_id,
|
|
163
|
+
}
|
|
164
|
+
]
|
|
168
165
|
)
|
|
169
166
|
|
|
170
167
|
return Websocket(
|
|
@@ -190,16 +187,13 @@ class WebsocketManager:
|
|
|
190
187
|
Возвращает:
|
|
191
188
|
`Websocket`: Объект для управления вебсокет соединением.
|
|
192
189
|
"""
|
|
193
|
-
subscription_message =
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
201
|
-
],
|
|
202
|
-
}
|
|
190
|
+
subscription_message = self._build_subscription_message(
|
|
191
|
+
[
|
|
192
|
+
{
|
|
193
|
+
"channel": "opt-summary",
|
|
194
|
+
"instFamily": inst_family,
|
|
195
|
+
}
|
|
196
|
+
]
|
|
203
197
|
)
|
|
204
198
|
|
|
205
199
|
return Websocket(
|
|
@@ -244,12 +238,7 @@ class WebsocketManager:
|
|
|
244
238
|
if inst_id:
|
|
245
239
|
args["instId"] = inst_id
|
|
246
240
|
|
|
247
|
-
subscription_message =
|
|
248
|
-
{
|
|
249
|
-
"op": "subscribe",
|
|
250
|
-
"args": [args],
|
|
251
|
-
}
|
|
252
|
-
)
|
|
241
|
+
subscription_message = self._build_subscription_message([args])
|
|
253
242
|
|
|
254
243
|
return Websocket(
|
|
255
244
|
callback=callback,
|
|
@@ -274,16 +263,13 @@ class WebsocketManager:
|
|
|
274
263
|
Возвращает:
|
|
275
264
|
`Websocket`: Объект для управления вебсокет соединением.
|
|
276
265
|
"""
|
|
277
|
-
subscription_message =
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
}
|
|
285
|
-
],
|
|
286
|
-
}
|
|
266
|
+
subscription_message = self._build_subscription_message(
|
|
267
|
+
[
|
|
268
|
+
{
|
|
269
|
+
"channel": "mark-price",
|
|
270
|
+
"instId": inst_id,
|
|
271
|
+
}
|
|
272
|
+
]
|
|
287
273
|
)
|
|
288
274
|
|
|
289
275
|
return Websocket(
|
|
@@ -309,16 +295,13 @@ class WebsocketManager:
|
|
|
309
295
|
Возвращает:
|
|
310
296
|
`Websocket`: Объект для управления вебсокет соединением.
|
|
311
297
|
"""
|
|
312
|
-
subscription_message =
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
}
|
|
320
|
-
],
|
|
321
|
-
}
|
|
298
|
+
subscription_message = self._build_subscription_message(
|
|
299
|
+
[
|
|
300
|
+
{
|
|
301
|
+
"channel": "index-tickers",
|
|
302
|
+
"instId": inst_id,
|
|
303
|
+
}
|
|
304
|
+
]
|
|
322
305
|
)
|
|
323
306
|
|
|
324
307
|
return Websocket(
|
|
@@ -375,16 +358,13 @@ class WebsocketManager:
|
|
|
375
358
|
`Websocket`: Объект для управления вебсокет соединением.
|
|
376
359
|
"""
|
|
377
360
|
channel = f"mark-price-candle{interval}"
|
|
378
|
-
subscription_message =
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
}
|
|
386
|
-
],
|
|
387
|
-
}
|
|
361
|
+
subscription_message = self._build_subscription_message(
|
|
362
|
+
[
|
|
363
|
+
{
|
|
364
|
+
"channel": channel,
|
|
365
|
+
"instId": inst_id,
|
|
366
|
+
}
|
|
367
|
+
]
|
|
388
368
|
)
|
|
389
369
|
|
|
390
370
|
return Websocket(
|
|
@@ -440,16 +420,13 @@ class WebsocketManager:
|
|
|
440
420
|
`Websocket`: Объект для управления вебсокет соединением.
|
|
441
421
|
"""
|
|
442
422
|
channel = f"index-candle{interval}"
|
|
443
|
-
subscription_message =
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
}
|
|
451
|
-
],
|
|
452
|
-
}
|
|
423
|
+
subscription_message = self._build_subscription_message(
|
|
424
|
+
[
|
|
425
|
+
{
|
|
426
|
+
"channel": channel,
|
|
427
|
+
"instId": inst_id,
|
|
428
|
+
}
|
|
429
|
+
]
|
|
453
430
|
)
|
|
454
431
|
|
|
455
432
|
return Websocket(
|
|
@@ -475,16 +452,13 @@ class WebsocketManager:
|
|
|
475
452
|
Возвращает:
|
|
476
453
|
`Websocket`: Объект для управления вебсокет соединением.
|
|
477
454
|
"""
|
|
478
|
-
subscription_message =
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
}
|
|
486
|
-
],
|
|
487
|
-
}
|
|
455
|
+
subscription_message = self._build_subscription_message(
|
|
456
|
+
[
|
|
457
|
+
{
|
|
458
|
+
"channel": "liquidation-orders",
|
|
459
|
+
"instType": inst_type,
|
|
460
|
+
}
|
|
461
|
+
]
|
|
488
462
|
)
|
|
489
463
|
|
|
490
464
|
return Websocket(
|
|
@@ -520,12 +494,7 @@ class WebsocketManager:
|
|
|
520
494
|
if inst_family:
|
|
521
495
|
args["instFamily"] = inst_family
|
|
522
496
|
|
|
523
|
-
subscription_message =
|
|
524
|
-
{
|
|
525
|
-
"op": "subscribe",
|
|
526
|
-
"args": [args],
|
|
527
|
-
}
|
|
528
|
-
)
|
|
497
|
+
subscription_message = self._build_subscription_message([args])
|
|
529
498
|
|
|
530
499
|
return Websocket(
|
|
531
500
|
callback=callback,
|
|
@@ -550,16 +519,13 @@ class WebsocketManager:
|
|
|
550
519
|
Возвращает:
|
|
551
520
|
`Websocket`: Объект для управления вебсокет соединением.
|
|
552
521
|
"""
|
|
553
|
-
subscription_message =
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
}
|
|
561
|
-
],
|
|
562
|
-
}
|
|
522
|
+
subscription_message = self._build_subscription_message(
|
|
523
|
+
[
|
|
524
|
+
{
|
|
525
|
+
"channel": "tickers",
|
|
526
|
+
"instId": inst_id,
|
|
527
|
+
}
|
|
528
|
+
]
|
|
563
529
|
)
|
|
564
530
|
|
|
565
531
|
return Websocket(
|
|
@@ -615,17 +581,13 @@ class WebsocketManager:
|
|
|
615
581
|
Возвращает:
|
|
616
582
|
`Websocket`: Объект для управления вебсокет соединением.
|
|
617
583
|
"""
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
"instId": inst_id,
|
|
626
|
-
}
|
|
627
|
-
],
|
|
628
|
-
}
|
|
584
|
+
subscription_message = self._build_subscription_message(
|
|
585
|
+
[
|
|
586
|
+
{
|
|
587
|
+
"channel": f"candle{interval}",
|
|
588
|
+
"instId": inst_id,
|
|
589
|
+
}
|
|
590
|
+
]
|
|
629
591
|
)
|
|
630
592
|
|
|
631
593
|
return Websocket(
|
|
@@ -651,16 +613,13 @@ class WebsocketManager:
|
|
|
651
613
|
Возвращает:
|
|
652
614
|
`Websocket`: Объект для управления вебсокет соединением.
|
|
653
615
|
"""
|
|
654
|
-
subscription_message =
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
}
|
|
662
|
-
],
|
|
663
|
-
}
|
|
616
|
+
subscription_message = self._build_subscription_message(
|
|
617
|
+
[
|
|
618
|
+
{
|
|
619
|
+
"channel": "trades",
|
|
620
|
+
"instId": inst_id,
|
|
621
|
+
}
|
|
622
|
+
]
|
|
664
623
|
)
|
|
665
624
|
|
|
666
625
|
return Websocket(
|
|
@@ -686,16 +645,13 @@ class WebsocketManager:
|
|
|
686
645
|
Возвращает:
|
|
687
646
|
`Websocket`: Объект для управления вебсокет соединением.
|
|
688
647
|
"""
|
|
689
|
-
subscription_message =
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
}
|
|
697
|
-
],
|
|
698
|
-
}
|
|
648
|
+
subscription_message = self._build_subscription_message(
|
|
649
|
+
[
|
|
650
|
+
{
|
|
651
|
+
"channel": "trades-all",
|
|
652
|
+
"instId": inst_id,
|
|
653
|
+
}
|
|
654
|
+
]
|
|
699
655
|
)
|
|
700
656
|
|
|
701
657
|
return Websocket(
|
|
@@ -723,16 +679,13 @@ class WebsocketManager:
|
|
|
723
679
|
Возвращает:
|
|
724
680
|
`Websocket`: Объект для управления вебсокет соединением.
|
|
725
681
|
"""
|
|
726
|
-
subscription_message =
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
}
|
|
734
|
-
],
|
|
735
|
-
}
|
|
682
|
+
subscription_message = self._build_subscription_message(
|
|
683
|
+
[
|
|
684
|
+
{
|
|
685
|
+
"channel": channel,
|
|
686
|
+
"instId": inst_id,
|
|
687
|
+
}
|
|
688
|
+
]
|
|
736
689
|
)
|
|
737
690
|
|
|
738
691
|
return Websocket(
|
unicex/types.py
CHANGED
|
@@ -5,9 +5,9 @@ __all__ = [
|
|
|
5
5
|
"TickerDailyItem",
|
|
6
6
|
"KlineDict",
|
|
7
7
|
"TradeDict",
|
|
8
|
-
"AggTradeDict",
|
|
9
8
|
"RequestMethod",
|
|
10
9
|
"LoggerLike",
|
|
10
|
+
"NumberLike",
|
|
11
11
|
"OpenInterestDict",
|
|
12
12
|
"OpenInterestItem",
|
|
13
13
|
"TickerInfoItem",
|
|
@@ -26,6 +26,13 @@ type LoggerLike = LoggingLogger | loguru.Logger
|
|
|
26
26
|
type RequestMethod = Literal["GET", "POST", "PUT", "DELETE", "PATCH"]
|
|
27
27
|
"""Типы методов HTTP запросов."""
|
|
28
28
|
|
|
29
|
+
type NumberLike = str | int | float
|
|
30
|
+
"""
|
|
31
|
+
Числовое значение для аргументов API-клиентов.
|
|
32
|
+
API бирж принимают числа как str, int или float — значение
|
|
33
|
+
передаётся без преобразований и сериализуется HTTP-клиентом.
|
|
34
|
+
"""
|
|
35
|
+
|
|
29
36
|
|
|
30
37
|
class TickerDailyItem(TypedDict):
|
|
31
38
|
"""Статистика одного тикера за последние 24 часа."""
|
|
@@ -71,10 +78,10 @@ class KlineDict(TypedDict):
|
|
|
71
78
|
q: float
|
|
72
79
|
"""Объем свечи. В долларах."""
|
|
73
80
|
|
|
74
|
-
T: int | None
|
|
81
|
+
T: int | None # `None` means untrackable
|
|
75
82
|
"""Время закрытия. В миллисекундах."""
|
|
76
83
|
|
|
77
|
-
x: bool | None
|
|
84
|
+
x: bool | None # `None` means untrackable
|
|
78
85
|
"""Флаг закрыта ли свеча."""
|
|
79
86
|
|
|
80
87
|
|
|
@@ -97,12 +104,6 @@ class TradeDict(TypedDict):
|
|
|
97
104
|
"""Объем сделки. В монетах."""
|
|
98
105
|
|
|
99
106
|
|
|
100
|
-
class AggTradeDict(TradeDict):
|
|
101
|
-
"""Модель агрегированной сделки."""
|
|
102
|
-
|
|
103
|
-
pass
|
|
104
|
-
|
|
105
|
-
|
|
106
107
|
class OpenInterestItem(TypedDict):
|
|
107
108
|
"""Модель одного элемента открытого интереса."""
|
|
108
109
|
|
|
@@ -110,7 +111,10 @@ class OpenInterestItem(TypedDict):
|
|
|
110
111
|
"""Время. В миллисекундах."""
|
|
111
112
|
|
|
112
113
|
v: float
|
|
113
|
-
"""Открытый интерес.
|
|
114
|
+
"""Открытый интерес."""
|
|
115
|
+
|
|
116
|
+
u: Literal["coins", "usd"]
|
|
117
|
+
"""Единица измерения открытого интереса."""
|
|
114
118
|
|
|
115
119
|
|
|
116
120
|
type OpenInterestDict = dict[str, OpenInterestItem]
|
unicex/utils.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Модуль, который предоставляет дополнительные функции, которые нужны для внутренного использования в библиотеке."""
|
|
2
2
|
|
|
3
3
|
__all__ = [
|
|
4
|
+
"get_timestamp",
|
|
4
5
|
"dict_to_query_string",
|
|
5
6
|
"generate_hmac_sha256_signature",
|
|
6
7
|
"sort_params_by_alphabetical_order",
|
|
@@ -9,13 +10,15 @@ __all__ = [
|
|
|
9
10
|
"catch_adapter_errors",
|
|
10
11
|
"decorate_all_methods",
|
|
11
12
|
"symbol_to_exchange_format",
|
|
13
|
+
"validate_single_symbol_args",
|
|
12
14
|
]
|
|
13
15
|
|
|
14
16
|
import base64
|
|
15
17
|
import hashlib
|
|
16
18
|
import hmac
|
|
17
19
|
import json
|
|
18
|
-
|
|
20
|
+
import time
|
|
21
|
+
from collections.abc import Callable, Iterable, Sequence
|
|
19
22
|
from functools import wraps
|
|
20
23
|
from typing import Any, Literal
|
|
21
24
|
from urllib.parse import urlencode
|
|
@@ -24,6 +27,19 @@ from unicex.enums import Exchange, MarketType
|
|
|
24
27
|
from unicex.exceptions import AdapterError
|
|
25
28
|
|
|
26
29
|
|
|
30
|
+
def get_timestamp(milliseconds: bool = True) -> int:
|
|
31
|
+
"""Возвращает текущее время в миллисекундах или секундах.
|
|
32
|
+
|
|
33
|
+
Параметры:
|
|
34
|
+
milliseconds (`bool`, опционально): Если True, возвращает время в миллисекундах.
|
|
35
|
+
Если False, возвращает время в секундах.
|
|
36
|
+
|
|
37
|
+
Возвращает:
|
|
38
|
+
`int`: Текущее время в миллисекундах или секундах.
|
|
39
|
+
"""
|
|
40
|
+
return int(time.time() * 1000) if milliseconds else int(time.time())
|
|
41
|
+
|
|
42
|
+
|
|
27
43
|
def filter_params(params: dict) -> dict:
|
|
28
44
|
"""Фильтрует параметры запроса, удаляя None-значения.
|
|
29
45
|
|
|
@@ -215,4 +231,31 @@ def symbol_to_exchange_format(
|
|
|
215
231
|
return symbol.removesuffix("USDT") # Вот тут мб и не так, там вроде что-то к USDC
|
|
216
232
|
else:
|
|
217
233
|
return symbol.removesuffix("USDT") # Вот тут мб и не так, там вроде что-то к USDC
|
|
234
|
+
elif exchange == Exchange.KUCOIN:
|
|
235
|
+
if market_type == MarketType.FUTURES:
|
|
236
|
+
if symbol_upper == "BTCUSDT":
|
|
237
|
+
return "XBTUSDTM"
|
|
238
|
+
return symbol_upper + "M"
|
|
239
|
+
else:
|
|
240
|
+
return symbol_upper.replace("USDT", "-USDT")
|
|
241
|
+
elif exchange == Exchange.BINGX:
|
|
242
|
+
return symbol_upper.replace("USDT", "-USDT")
|
|
218
243
|
return symbol_upper
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def validate_single_symbol_args(
|
|
247
|
+
symbol: str | None = None, symbols: Sequence[str] | None = None
|
|
248
|
+
) -> None:
|
|
249
|
+
"""Проверяет, что передан ровно один из аргументов symbol/symbols.
|
|
250
|
+
|
|
251
|
+
Параметры:
|
|
252
|
+
symbol (`str | None`, опционально): Одиночный торговый символ.
|
|
253
|
+
symbols (`Sequence[str] | None`, опционально): Список торговых символов.
|
|
254
|
+
|
|
255
|
+
Возвращает:
|
|
256
|
+
`None`: Ничего не возвращает, выбрасывает ValueError при нарушении условий.
|
|
257
|
+
"""
|
|
258
|
+
if symbol and symbols:
|
|
259
|
+
raise ValueError("Parameters symbol and symbols cannot be used together")
|
|
260
|
+
if not (symbol or symbols):
|
|
261
|
+
raise ValueError("Either symbol or symbols must be provided")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: unicex
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.16.5
|
|
4
4
|
Summary: Unified Crypto Exchange API
|
|
5
5
|
Author-email: LoveBloodAndDiamonds <ayazshakirzyanov27@gmail.com>
|
|
6
6
|
License: BSD 3-Clause License
|
|
@@ -56,12 +56,14 @@ Dynamic: license-file
|
|
|
56
56
|
| Exchange | Client | Auth | WS Manager | User WS | Uni Client | Uni WS Manager | ExchangeInfo |
|
|
57
57
|
|-----------------|--------|------|------------|---------|------------|----------------|--------------|
|
|
58
58
|
| **Binance** | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
|
59
|
-
| **Bitget** | ✓ | ✓ | ✓ | | ✓ |
|
|
59
|
+
| **Bitget** | ✓ | ✓ | ✓ | | ✓ | ✓ | ✓ |
|
|
60
60
|
| **Bybit** | ✓ | ✓ | ✓ | | ✓ | ✓ | ✓ |
|
|
61
|
-
| **Gateio** | ✓ | ✓ | ✓ | | ✓ |
|
|
61
|
+
| **Gateio** | ✓ | ✓ | ✓ | | ✓ | ✓ | ✓ |
|
|
62
62
|
| **Hyperliquid** | ✓ | ✓ | ✓ | ✓ | ✓ | | |
|
|
63
|
-
| **Mexc** | ✓ | ✓ | ✓ | | ✓ |
|
|
64
|
-
| **Okx** | ✓ | ✓ | ✓ | | ✓ |
|
|
63
|
+
| **Mexc** | ✓ | ✓ | ✓ | | ✓ | ✓ | ✓ |
|
|
64
|
+
| **Okx** | ✓ | ✓ | ✓ | | ✓ | ✓ | ✓ |
|
|
65
|
+
| **Kucoin** | | | | | ✓ | | |
|
|
66
|
+
| **BingX** | | | | | ✓ | | |
|
|
65
67
|
---
|
|
66
68
|
|
|
67
69
|
|