unicex 0.13.17__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 (93) hide show
  1. unicex/__init__.py +200 -0
  2. unicex/_abc/__init__.py +11 -0
  3. unicex/_abc/exchange_info.py +216 -0
  4. unicex/_abc/uni_client.py +329 -0
  5. unicex/_abc/uni_websocket_manager.py +294 -0
  6. unicex/_base/__init__.py +9 -0
  7. unicex/_base/client.py +214 -0
  8. unicex/_base/websocket.py +261 -0
  9. unicex/binance/__init__.py +27 -0
  10. unicex/binance/adapter.py +202 -0
  11. unicex/binance/client.py +1577 -0
  12. unicex/binance/exchange_info.py +62 -0
  13. unicex/binance/uni_client.py +188 -0
  14. unicex/binance/uni_websocket_manager.py +166 -0
  15. unicex/binance/user_websocket.py +186 -0
  16. unicex/binance/websocket_manager.py +912 -0
  17. unicex/bitget/__init__.py +27 -0
  18. unicex/bitget/adapter.py +188 -0
  19. unicex/bitget/client.py +2514 -0
  20. unicex/bitget/exchange_info.py +48 -0
  21. unicex/bitget/uni_client.py +198 -0
  22. unicex/bitget/uni_websocket_manager.py +275 -0
  23. unicex/bitget/user_websocket.py +7 -0
  24. unicex/bitget/websocket_manager.py +232 -0
  25. unicex/bybit/__init__.py +27 -0
  26. unicex/bybit/adapter.py +208 -0
  27. unicex/bybit/client.py +1876 -0
  28. unicex/bybit/exchange_info.py +53 -0
  29. unicex/bybit/uni_client.py +200 -0
  30. unicex/bybit/uni_websocket_manager.py +291 -0
  31. unicex/bybit/user_websocket.py +7 -0
  32. unicex/bybit/websocket_manager.py +339 -0
  33. unicex/enums.py +273 -0
  34. unicex/exceptions.py +64 -0
  35. unicex/extra.py +335 -0
  36. unicex/gate/__init__.py +27 -0
  37. unicex/gate/adapter.py +178 -0
  38. unicex/gate/client.py +1667 -0
  39. unicex/gate/exchange_info.py +55 -0
  40. unicex/gate/uni_client.py +214 -0
  41. unicex/gate/uni_websocket_manager.py +269 -0
  42. unicex/gate/user_websocket.py +7 -0
  43. unicex/gate/websocket_manager.py +513 -0
  44. unicex/hyperliquid/__init__.py +27 -0
  45. unicex/hyperliquid/adapter.py +261 -0
  46. unicex/hyperliquid/client.py +2315 -0
  47. unicex/hyperliquid/exchange_info.py +119 -0
  48. unicex/hyperliquid/uni_client.py +325 -0
  49. unicex/hyperliquid/uni_websocket_manager.py +269 -0
  50. unicex/hyperliquid/user_websocket.py +7 -0
  51. unicex/hyperliquid/websocket_manager.py +393 -0
  52. unicex/mapper.py +111 -0
  53. unicex/mexc/__init__.py +27 -0
  54. unicex/mexc/_spot_ws_proto/PrivateAccountV3Api_pb2.py +38 -0
  55. unicex/mexc/_spot_ws_proto/PrivateDealsV3Api_pb2.py +38 -0
  56. unicex/mexc/_spot_ws_proto/PrivateOrdersV3Api_pb2.py +38 -0
  57. unicex/mexc/_spot_ws_proto/PublicAggreBookTickerV3Api_pb2.py +38 -0
  58. unicex/mexc/_spot_ws_proto/PublicAggreDealsV3Api_pb2.py +40 -0
  59. unicex/mexc/_spot_ws_proto/PublicAggreDepthsV3Api_pb2.py +40 -0
  60. unicex/mexc/_spot_ws_proto/PublicBookTickerBatchV3Api_pb2.py +38 -0
  61. unicex/mexc/_spot_ws_proto/PublicBookTickerV3Api_pb2.py +38 -0
  62. unicex/mexc/_spot_ws_proto/PublicDealsV3Api_pb2.py +40 -0
  63. unicex/mexc/_spot_ws_proto/PublicFuture_pb2.py +103 -0
  64. unicex/mexc/_spot_ws_proto/PublicIncreaseDepthsBatchV3Api_pb2.py +38 -0
  65. unicex/mexc/_spot_ws_proto/PublicIncreaseDepthsV3Api_pb2.py +40 -0
  66. unicex/mexc/_spot_ws_proto/PublicLimitDepthsV3Api_pb2.py +40 -0
  67. unicex/mexc/_spot_ws_proto/PublicMiniTickerV3Api_pb2.py +38 -0
  68. unicex/mexc/_spot_ws_proto/PublicMiniTickersV3Api_pb2.py +38 -0
  69. unicex/mexc/_spot_ws_proto/PublicSpotKlineV3Api_pb2.py +38 -0
  70. unicex/mexc/_spot_ws_proto/PushDataV3ApiWrapper_pb2.py +38 -0
  71. unicex/mexc/_spot_ws_proto/__init__.py +335 -0
  72. unicex/mexc/adapter.py +239 -0
  73. unicex/mexc/client.py +846 -0
  74. unicex/mexc/exchange_info.py +47 -0
  75. unicex/mexc/uni_client.py +211 -0
  76. unicex/mexc/uni_websocket_manager.py +269 -0
  77. unicex/mexc/user_websocket.py +7 -0
  78. unicex/mexc/websocket_manager.py +456 -0
  79. unicex/okx/__init__.py +27 -0
  80. unicex/okx/adapter.py +150 -0
  81. unicex/okx/client.py +2864 -0
  82. unicex/okx/exchange_info.py +47 -0
  83. unicex/okx/uni_client.py +202 -0
  84. unicex/okx/uni_websocket_manager.py +269 -0
  85. unicex/okx/user_websocket.py +7 -0
  86. unicex/okx/websocket_manager.py +743 -0
  87. unicex/types.py +164 -0
  88. unicex/utils.py +218 -0
  89. unicex-0.13.17.dist-info/METADATA +243 -0
  90. unicex-0.13.17.dist-info/RECORD +93 -0
  91. unicex-0.13.17.dist-info/WHEEL +5 -0
  92. unicex-0.13.17.dist-info/licenses/LICENSE +28 -0
  93. unicex-0.13.17.dist-info/top_level.txt +1 -0
@@ -0,0 +1,456 @@
1
+ __all__ = ["WebsocketManager"]
2
+
3
+ import json
4
+ from collections.abc import Awaitable, Callable, Sequence
5
+ from typing import Any, Literal
6
+
7
+ import orjson
8
+ from google.protobuf.json_format import MessageToDict
9
+
10
+ from unicex._base import Websocket
11
+
12
+ from ._spot_ws_proto import PushDataV3ApiWrapper
13
+ from .client import Client
14
+
15
+ type CallbackType = Callable[[Any], Awaitable[None]]
16
+
17
+
18
+ class WebsocketManager:
19
+ """Менеджер асинхронных вебсокетов для Mexc."""
20
+
21
+ _SPOT_URL: str = "wss://wbs-api.mexc.com/ws"
22
+ """Базовый URL для вебсокета на спот."""
23
+
24
+ _FUTURES_URL: str = "wss://contract.mexc.com/edge"
25
+ """Базовый URL для вебсокета на фьючерсы."""
26
+
27
+ class _MexcProtobufDecoder:
28
+ """Класс для декодирования сообщений в формате Protobuf со спотового рынка Mexc."""
29
+
30
+ def decode(self, message: Any) -> dict:
31
+ if isinstance(message, bytes):
32
+ wrapper = PushDataV3ApiWrapper() # noqa
33
+ wrapper.ParseFromString(message)
34
+ return MessageToDict(wrapper, preserving_proto_field_name=True) # type: ignore
35
+ elif isinstance(message, str):
36
+ return orjson.loads(message)
37
+ else:
38
+ raise ValueError(f"Invalid message type: {type(message)}")
39
+
40
+ def __init__(self, client: Client | None = None, **ws_kwargs: Any) -> None:
41
+ """Инициализирует менеджер вебсокетов для Mexc.
42
+
43
+ Параметры:
44
+ client (`Client | None`): Клиент для выполнения запросов. Нужен, чтобы открыть приватные вебсокеты.
45
+ ws_kwargs (`dict[str, Any]`): Дополнительные аргументы, которые прокидываются в `Websocket`.
46
+ """
47
+ self.client = client
48
+ self._ws_kwargs = ws_kwargs
49
+
50
+ def _generate_subscription_message(
51
+ self,
52
+ channel_template: str,
53
+ symbol: str | None = None,
54
+ symbols: Sequence[str] | None = None,
55
+ **template_kwargs: Any,
56
+ ) -> list[str]:
57
+ """Сформировать сообщение для подписки на вебсокет."""
58
+ if symbol and symbols:
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")
62
+
63
+ if symbol:
64
+ params = [channel_template.format(symbol=symbol, **template_kwargs)]
65
+ elif symbols:
66
+ params = [
67
+ channel_template.format(symbol=symbol, **template_kwargs) for symbol in symbols
68
+ ]
69
+
70
+ return [json.dumps({"method": "SUBSCRIPTION", "params": params})]
71
+
72
+ def _generate_futures_subscription_message(
73
+ self,
74
+ topic: str,
75
+ symbol: str | None = None,
76
+ symbols: Sequence[str] | None = None,
77
+ require_symbol: bool = True,
78
+ **additional_params_kwargs: Any,
79
+ ) -> list[str]:
80
+ """Сформировать сообщение для подписки на фьючерсный вебсокет."""
81
+ if symbol and symbols:
82
+ raise ValueError("Parameters symbol and symbols cannot be used together")
83
+ if require_symbol and not (symbol or symbols):
84
+ raise ValueError("Either symbol or symbols must be provided")
85
+
86
+ if symbol:
87
+ symbols = [symbol]
88
+ if symbols:
89
+ return [
90
+ json.dumps({"method": topic, "param": {"symbol": s, **additional_params_kwargs}})
91
+ for s in symbols
92
+ ] # type: ignore
93
+ return [json.dumps({"method": topic, "param": {**additional_params_kwargs}})]
94
+
95
+ def _create_websocket(
96
+ self, callback: CallbackType, subscription_messages: list[str]
97
+ ) -> Websocket:
98
+ """Шорткат для создания вебсокета."""
99
+ return Websocket(
100
+ callback=callback,
101
+ url=self._SPOT_URL,
102
+ subscription_messages=subscription_messages,
103
+ decoder=self._MexcProtobufDecoder,
104
+ ping_message='{"method": "PING"}',
105
+ **self._ws_kwargs,
106
+ )
107
+
108
+ def _create_futures_websocket(
109
+ self, callback: CallbackType, subscription_messages: list[str]
110
+ ) -> Websocket:
111
+ """Шорткат для создания фьючерсного вебсокета."""
112
+ return Websocket(
113
+ callback=callback,
114
+ url=self._FUTURES_URL,
115
+ subscription_messages=subscription_messages,
116
+ ping_message='{"method": "ping"}',
117
+ **self._ws_kwargs,
118
+ )
119
+
120
+ def trade(
121
+ self,
122
+ callback: CallbackType,
123
+ symbol: str | None = None,
124
+ symbols: Sequence[str] | None = None,
125
+ update_interval: Literal["100ms", "10ms"] = "100ms",
126
+ ) -> Websocket:
127
+ """Создает вебсокет для получения сделок.
128
+
129
+ https://mexcdevelop.github.io/apidocs/spot_v3_en/#trade-streams
130
+
131
+ Параметры:
132
+ callback (`CallbackType`): Асинхронная функция обратного вызова для обработки сообщений.
133
+ symbol (`str | None`): Один символ для подписки.
134
+ symbols (`Sequence[str] | None`): Список символов для мультиплекс‑подключения.
135
+ update_interval (`Literal["100ms", "10ms"]`): Интервал обновления.
136
+
137
+ Возвращает:
138
+ `Websocket`: Объект для управления вебсокет соединением.
139
+ """
140
+ subscription_messages = self._generate_subscription_message(
141
+ channel_template="spot@public.aggre.deals.v3.api.pb@{update_interval}@{symbol}",
142
+ symbol=symbol,
143
+ symbols=symbols,
144
+ update_interval=update_interval,
145
+ )
146
+ return self._create_websocket(callback, subscription_messages)
147
+
148
+ def klines(
149
+ self,
150
+ callback: CallbackType,
151
+ interval: str,
152
+ symbol: str | None = None,
153
+ symbols: Sequence[str] | None = None,
154
+ ) -> Websocket:
155
+ """Создает вебсокет для получения K-line (candlestick) данных.
156
+
157
+ https://mexcdevelop.github.io/apidocs/spot_v3_en/#k-line-streams
158
+
159
+ Параметры:
160
+ callback (`CallbackType`): Асинхронная функция обратного вызова для обработки сообщений.
161
+ symbol (`str | None`): Один символ для подписки.
162
+ symbols (`Sequence[str] | None`): Список символов для мультиплекс‑подключения.
163
+ interval (`Literal[...]`): Интервал K-line.
164
+
165
+ Возвращает:
166
+ `Websocket`: Объект для управления вебсокет соединением.
167
+ """
168
+ subscription_messages = self._generate_subscription_message(
169
+ channel_template="spot@public.kline.v3.api.pb@{symbol}@{interval}",
170
+ symbol=symbol,
171
+ symbols=symbols,
172
+ interval=interval,
173
+ )
174
+ return self._create_websocket(callback, subscription_messages)
175
+
176
+ def diff_depth(
177
+ self,
178
+ callback: CallbackType,
179
+ symbol: str | None = None,
180
+ symbols: Sequence[str] | None = None,
181
+ update_speed: Literal["100ms", "10ms"] = "100ms",
182
+ ) -> Websocket:
183
+ """Создает вебсокет для получения инкрементальных изменений в книге заявок.
184
+
185
+ https://mexcdevelop.github.io/apidocs/spot_v3_en/#diff-depth-stream
186
+
187
+ Параметры:
188
+ callback (`CallbackType`): Асинхронная функция обратного вызова для обработки сообщений.
189
+ symbol (`str | None`): Один символ для подписки.
190
+ symbols (`Sequence[str] | None`): Список символов для мультиплекс‑подключения.
191
+ update_speed (`Literal["100ms", "10ms"]`): Скорость обновления данных.
192
+
193
+ Возвращает:
194
+ `Websocket`: Объект для управления вебсокет соединением.
195
+ """
196
+ subscription_messages = self._generate_subscription_message(
197
+ channel_template="spot@public.aggre.depth.v3.api.pb@{update_speed}@{symbol}",
198
+ symbol=symbol,
199
+ symbols=symbols,
200
+ update_speed=update_speed,
201
+ )
202
+ return self._create_websocket(callback, subscription_messages)
203
+
204
+ def partial_depth(
205
+ self,
206
+ callback: CallbackType,
207
+ symbol: str | None = None,
208
+ symbols: Sequence[str] | None = None,
209
+ levels: Literal["5", "10", "20"] = "5",
210
+ ) -> Websocket:
211
+ """Создает вебсокет для получения ограниченной глубины книги заявок.
212
+
213
+ https://mexcdevelop.github.io/apidocs/spot_v3_en/#partial-book-depth-streams
214
+
215
+ Параметры:
216
+ callback (`CallbackType`): Асинхронная функция обратного вызова для обработки сообщений.
217
+ symbol (`str | None`): Один символ для подписки.
218
+ symbols (`Sequence[str] | None`): Список символов для мультиплекс‑подключения.
219
+ levels (`Literal["5", "10", "20"]`): Количество уровней глубины.
220
+
221
+ Возвращает:
222
+ `Websocket`: Объект для управления вебсокет соединением.
223
+ """
224
+ subscription_messages = self._generate_subscription_message(
225
+ channel_template="spot@public.limit.depth.v3.api.pb@{symbol}@{levels}",
226
+ symbol=symbol,
227
+ symbols=symbols,
228
+ levels=levels,
229
+ )
230
+ return self._create_websocket(callback, subscription_messages)
231
+
232
+ def book_ticker(
233
+ self,
234
+ callback: CallbackType,
235
+ symbol: str | None = None,
236
+ symbols: Sequence[str] | None = None,
237
+ update_speed: Literal["100ms", "10ms"] = "100ms",
238
+ ) -> Websocket:
239
+ """Создает вебсокет для получения лучших цен покупки и продажи в реальном времени.
240
+
241
+ https://mexcdevelop.github.io/apidocs/spot_v3_en/#individual-symbol-book-ticker-streams
242
+
243
+ Параметры:
244
+ callback (`CallbackType`): Асинхронная функция обратного вызова для обработки сообщений.
245
+ symbol (`str | None`): Один символ для подписки.
246
+ symbols (`Sequence[str] | None`): Список символов для мультиплекс‑подключения.
247
+ update_speed (`Literal["100ms", "10ms"]`): Скорость обновления данных.
248
+
249
+ Возвращает:
250
+ `Websocket`: Объект для управления вебсокет соединением.
251
+ """
252
+ subscription_messages = self._generate_subscription_message(
253
+ channel_template="spot@public.aggre.bookTicker.v3.api.pb@{update_speed}@{symbol}",
254
+ symbol=symbol,
255
+ symbols=symbols,
256
+ update_speed=update_speed,
257
+ )
258
+ return self._create_websocket(callback, subscription_messages)
259
+
260
+ def book_ticker_batch(
261
+ self,
262
+ callback: CallbackType,
263
+ symbol: str | None = None,
264
+ symbols: Sequence[str] | None = None,
265
+ ) -> Websocket:
266
+ """Создает вебсокет для получения лучших цен покупки и продажи (батч версия).
267
+
268
+ https://mexcdevelop.github.io/apidocs/spot_v3_en/#individual-symbol-book-ticker-streams-batch-aggregation
269
+
270
+ Параметры:
271
+ callback (`CallbackType`): Асинхронная функция обратного вызова для обработки сообщений.
272
+ symbol (`str | None`): Один символ для подписки.
273
+ symbols (`Sequence[str] | None`): Список символов для мультиплекс‑подключения.
274
+
275
+ Возвращает:
276
+ `Websocket`: Объект для управления вебсокет соединением.
277
+ """
278
+ subscription_messages = self._generate_subscription_message(
279
+ channel_template="spot@public.bookTicker.batch.v3.api.pb@{symbol}",
280
+ symbol=symbol,
281
+ symbols=symbols,
282
+ )
283
+ return self._create_websocket(callback, subscription_messages)
284
+
285
+ def futures_tickers(
286
+ self,
287
+ callback: CallbackType,
288
+ ) -> Websocket:
289
+ """Создает вебсокет для получения тикеров всех фьючерсных контрактов.
290
+
291
+ https://mexcdevelop.github.io/apidocs/contract_v1_en/#public-channels
292
+
293
+ Параметры:
294
+ callback (`CallbackType`): Асинхронная функция обратного вызова для обработки сообщений.
295
+
296
+ Возвращает:
297
+ `Websocket`: Объект для управления вебсокет соединением.
298
+ """
299
+ subscription_messages = self._generate_futures_subscription_message(
300
+ topic="sub.tickers", require_symbol=False
301
+ )
302
+ return self._create_futures_websocket(callback, subscription_messages)
303
+
304
+ def futures_ticker(
305
+ self,
306
+ callback: CallbackType,
307
+ symbol: str | None = None,
308
+ symbols: Sequence[str] | None = None,
309
+ ) -> Websocket:
310
+ """Создает вебсокет для получения тикера конкретных фьючерсных контрактов.
311
+
312
+ https://mexcdevelop.github.io/apidocs/contract_v1_en/#public-channels
313
+
314
+ Параметры:
315
+ callback (`CallbackType`): Асинхронная функция обратного вызова для обработки сообщений.
316
+ symbol (`str | None`): Символ фьючерсного контракта.
317
+ symbols (`Sequence[str] | None`): Последовательность символов фьючерсных контрактов.
318
+
319
+ Возвращает:
320
+ `Websocket`: Объект для управления вебсокет соединением.
321
+ """
322
+ subscription_messages = self._generate_futures_subscription_message(
323
+ topic="sub.ticker", symbol=symbol, symbols=symbols
324
+ )
325
+ return self._create_futures_websocket(callback, subscription_messages)
326
+
327
+ def futures_depth(
328
+ self,
329
+ callback: CallbackType,
330
+ limit: Literal[5, 10, 20] | None = None,
331
+ is_full: bool = False,
332
+ compress: bool = False,
333
+ symbol: str | None = None,
334
+ symbols: Sequence[str] | None = None,
335
+ ) -> Websocket:
336
+ """Создает вебсокет для получения глубины рынка фьючерсных контрактов.
337
+
338
+ https://mexcdevelop.github.io/apidocs/contract_v1_en/#public-channels
339
+
340
+ Параметры:
341
+ callback (`CallbackType`): Асинхронная функция обратного вызова для обработки сообщений.
342
+ limit (`Literal[5, 10, 20] | None`): Количество уровней в стакане заявок.
343
+ is_full (`bool`): Получать полную глубину рынка.
344
+ compress (`bool`): Использовать сжатие данных.
345
+ symbol (`str | None`): Символ фьючерсного контракта.
346
+ symbols (`Sequence[str] | None`): Последовательность символов фьючерсных контрактов.
347
+
348
+ Возвращает:
349
+ `Websocket`: Объект для управления вебсокет соединением.
350
+ """
351
+ additional_params = {}
352
+ if limit:
353
+ additional_params["limit"] = limit
354
+ if compress:
355
+ additional_params["compress"] = compress
356
+ topic = "sub.depth"
357
+ if is_full:
358
+ topic += ".full"
359
+ subscription_messages = self._generate_futures_subscription_message(
360
+ topic=topic, symbol=symbol, symbols=symbols, **additional_params
361
+ )
362
+ return self._create_futures_websocket(callback, subscription_messages)
363
+
364
+ def futures_kline(
365
+ self,
366
+ callback: CallbackType,
367
+ interval: str,
368
+ symbol: str | None = None,
369
+ symbols: Sequence[str] | None = None,
370
+ ) -> Websocket:
371
+ """Создает вебсокет для получения свечных данных фьючерсных контрактов.
372
+
373
+ https://mexcdevelop.github.io/apidocs/contract_v1_en/#public-channels
374
+
375
+ Параметры:
376
+ callback (`CallbackType`): Асинхронная функция обратного вызова для обработки сообщений.
377
+ interval (`str`): Временной интервал для свечей.
378
+ symbol (`str | None`): Символ фьючерсного контракта.
379
+ symbols (`Sequence[str] | None`): Последовательность символов фьючерсных контрактов.
380
+
381
+ Возвращает:
382
+ `Websocket`: Объект для управления вебсокет соединением.
383
+ """
384
+ subscription_messages = self._generate_futures_subscription_message(
385
+ topic="sub.deal", symbol=symbol, symbols=symbols, interval=interval
386
+ )
387
+ return self._create_futures_websocket(callback, subscription_messages)
388
+
389
+ def funding_rate(
390
+ self,
391
+ callback: CallbackType,
392
+ symbol: str | None = None,
393
+ symbols: Sequence[str] | None = None,
394
+ ) -> Websocket:
395
+ """Создает вебсокет для получения ставки финансирования фьючерсных контрактов.
396
+
397
+ https://mexcdevelop.github.io/apidocs/contract_v1_en/#public-channels
398
+
399
+ Параметры:
400
+ callback (`CallbackType`): Асинхронная функция обратного вызова для обработки сообщений.
401
+ symbol (`str | None`): Символ фьючерсного контракта.
402
+ symbols (`Sequence[str] | None`): Последовательность символов фьючерсных контрактов.
403
+
404
+ Возвращает:
405
+ `Websocket`: Объект для управления вебсокет соединением.
406
+ """
407
+ subscription_messages = self._generate_futures_subscription_message(
408
+ topic="sub.funding.rate", symbol=symbol, symbols=symbols
409
+ )
410
+ return self._create_futures_websocket(callback, subscription_messages)
411
+
412
+ def futures_index_price(
413
+ self,
414
+ callback: CallbackType,
415
+ symbol: str | None = None,
416
+ symbols: Sequence[str] | None = None,
417
+ ) -> Websocket:
418
+ """Создает вебсокет для получения индексной цены фьючерсных контрактов.
419
+
420
+ https://mexcdevelop.github.io/apidocs/contract_v1_en/#public-channels
421
+
422
+ Параметры:
423
+ callback (`CallbackType`): Асинхронная функция обратного вызова для обработки сообщений.
424
+ symbol (`str | None`): Символ фьючерсного контракта.
425
+ symbols (`Sequence[str] | None`): Последовательность символов фьючерсных контрактов.
426
+
427
+ Возвращает:
428
+ `Websocket`: Объект для управления вебсокет соединением.
429
+ """
430
+ subscription_messages = self._generate_futures_subscription_message(
431
+ topic="sub.index.price", symbol=symbol, symbols=symbols
432
+ )
433
+ return self._create_futures_websocket(callback, subscription_messages)
434
+
435
+ def futures_fair_price(
436
+ self,
437
+ callback: CallbackType,
438
+ symbol: str | None = None,
439
+ symbols: Sequence[str] | None = None,
440
+ ) -> Websocket:
441
+ """Создает вебсокет для получения справедливой цены фьючерсных контрактов.
442
+
443
+ https://mexcdevelop.github.io/apidocs/contract_v1_en/#public-channels
444
+
445
+ Параметры:
446
+ callback (`CallbackType`): Асинхронная функция обратного вызова для обработки сообщений.
447
+ symbol (`str | None`): Символ фьючерсного контракта.
448
+ symbols (`Sequence[str] | None`): Последовательность символов фьючерсных контрактов.
449
+
450
+ Возвращает:
451
+ `Websocket`: Объект для управления вебсокет соединением.
452
+ """
453
+ subscription_messages = self._generate_futures_subscription_message(
454
+ topic="sub.fair.price", symbol=symbol, symbols=symbols
455
+ )
456
+ return self._create_futures_websocket(callback, subscription_messages)
unicex/okx/__init__.py ADDED
@@ -0,0 +1,27 @@
1
+ """Пакет, содержащий реализации клиентов и менеджеров для работы с биржей Okx."""
2
+
3
+ __all__ = [
4
+ "Client",
5
+ "UniClient",
6
+ "UserWebsocket",
7
+ "WebsocketManager",
8
+ "UniWebsocketManager",
9
+ "ExchangeInfo",
10
+ ]
11
+
12
+ from .client import Client
13
+ from .exchange_info import ExchangeInfo
14
+ from .uni_client import UniClient
15
+ from .uni_websocket_manager import UniWebsocketManager
16
+ from .user_websocket import UserWebsocket
17
+ from .websocket_manager import WebsocketManager
18
+
19
+
20
+ async def load_exchange_info() -> None:
21
+ """Загружает информацию о бирже Okx."""
22
+ await ExchangeInfo.load_exchange_info()
23
+
24
+
25
+ async def start_exchange_info(parse_interval_seconds: int = 60 * 60) -> None:
26
+ """Запускает процесс обновления информации о бирже Okx."""
27
+ await ExchangeInfo.start(parse_interval_seconds)
unicex/okx/adapter.py ADDED
@@ -0,0 +1,150 @@
1
+ __all__ = ["Adapter"]
2
+
3
+
4
+ from unicex.types import (
5
+ KlineDict,
6
+ OpenInterestDict,
7
+ OpenInterestItem,
8
+ TickerDailyDict,
9
+ TickerDailyItem,
10
+ )
11
+ from unicex.utils import catch_adapter_errors, decorate_all_methods
12
+
13
+ from .exchange_info import ExchangeInfo
14
+
15
+
16
+ @decorate_all_methods(catch_adapter_errors)
17
+ class Adapter:
18
+ """Адаптер для унификации данных с Okx API."""
19
+
20
+ @staticmethod
21
+ def tickers(raw_data: dict, only_usdt: bool) -> list[str]:
22
+ """Преобразует сырые данные о тикерах в список унифицированных символов.
23
+
24
+ Параметры:
25
+ raw_data (`dict`): Сырой ответ от OKX.
26
+ only_usdt (`bool`): Возвращать только тикеры в паре с USDT.
27
+
28
+ Возвращает:
29
+ `list[str]`: Список тикеров.
30
+ """
31
+ return [
32
+ item["instId"]
33
+ for item in raw_data["data"]
34
+ if item["instId"].endswith("-USDT") or not only_usdt
35
+ ]
36
+
37
+ @staticmethod
38
+ def futures_tickers(raw_data: dict, only_usdt: bool) -> list[str]:
39
+ """Преобразует сырые данные о тикерах в список унифицированных символов.
40
+
41
+ Параметры:
42
+ raw_data (`dict`): Сырой ответ от OKX.
43
+ only_usdt (`bool`): Возвращать только тикеры в паре с USDT.
44
+
45
+ Возвращает:
46
+ `list[str]`: Список тикеров.
47
+ """
48
+ return [
49
+ item["instId"]
50
+ for item in raw_data["data"]
51
+ if item["instId"].endswith("-USDT-SWAP") or not only_usdt
52
+ ]
53
+
54
+ @staticmethod
55
+ def ticker_24hr(raw_data: dict) -> TickerDailyDict:
56
+ """Преобразует статистику 24ч в унифицированный формат.
57
+
58
+ # NOTE: Обратите внимание, изменение цены в случае с OKX возвращается относительно открытия 1 day свечи.
59
+ """
60
+ result = {}
61
+ for item in raw_data["data"]:
62
+ try:
63
+ result[item["instId"]] = TickerDailyItem(
64
+ p=round(
65
+ (float(item["last"]) - float(item["open24h"]))
66
+ / float(item["open24h"])
67
+ * 100,
68
+ 2,
69
+ ),
70
+ v=float(item["vol24h"]),
71
+ q=float(item["volCcy24h"]),
72
+ )
73
+ except (ValueError, TypeError, KeyError):
74
+ continue
75
+ return result
76
+
77
+ @staticmethod
78
+ def futures_ticker_24hr(raw_data: dict) -> TickerDailyDict:
79
+ """Преобразует статистику 24ч в унифицированный формат.
80
+
81
+ # NOTE: Обратите внимание, изменение цены в случае с OKX возвращается относительно открытия 1 day свечи.
82
+ """
83
+ return {
84
+ item["instId"]: TickerDailyItem(
85
+ p=round(
86
+ (float(item["last"]) - float(item["open24h"])) / float(item["open24h"]) * 100, 2
87
+ ),
88
+ v=float(item["volCcy24h"]),
89
+ q=float(item["volCcy24h"]) * float(item["last"]),
90
+ )
91
+ for item in raw_data["data"]
92
+ }
93
+
94
+ @staticmethod
95
+ def last_price(raw_data: dict) -> dict[str, float]:
96
+ """Преобразует данные о последней цене в унифицированный формат."""
97
+ result = {}
98
+ for item in raw_data["data"]:
99
+ try:
100
+ result[item["instId"]] = float(item["last"])
101
+ except (ValueError, TypeError, KeyError):
102
+ continue
103
+ return result
104
+
105
+ @staticmethod
106
+ def klines(raw_data: dict, symbol: str) -> list[KlineDict]:
107
+ """Преобразует данные о свечах в унифицированный формат."""
108
+ return [
109
+ KlineDict(
110
+ s=symbol,
111
+ t=int(kline[0]),
112
+ o=float(kline[1]),
113
+ h=float(kline[2]),
114
+ l=float(kline[3]),
115
+ c=float(kline[4]),
116
+ v=float(kline[6]),
117
+ q=float(kline[7]),
118
+ T=None,
119
+ x=bool(int(kline[8])),
120
+ )
121
+ for kline in sorted(
122
+ raw_data["data"],
123
+ key=lambda x: int(x[0]),
124
+ )
125
+ ]
126
+
127
+ @staticmethod
128
+ def funding_rate(raw_data: dict) -> dict[str, float]:
129
+ """Преобразует данные о ставках финансирования в унифицированный формат."""
130
+ data = raw_data["data"][0]
131
+ return {data["instId"]: float(data["fundingRate"]) * 100}
132
+
133
+ @staticmethod
134
+ def open_interest(raw_data: dict) -> OpenInterestDict:
135
+ """Преобразует данные об открытом интересе в унифицированный формат."""
136
+ return {
137
+ item["instId"]: OpenInterestItem(
138
+ t=int(item["ts"]),
139
+ v=float(item["oiCcy"]),
140
+ )
141
+ for item in raw_data["data"]
142
+ }
143
+
144
+ @staticmethod
145
+ def _get_contract_size(symbol: str) -> float:
146
+ """Возвращает размер контракта для указанного символа тикера."""
147
+ try:
148
+ return ExchangeInfo.get_futures_ticker_info(symbol)["contract_size"] or 1
149
+ except: # noqa
150
+ return 1