unicex 0.15.4__py3-none-any.whl → 0.16.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.
@@ -199,7 +199,7 @@ class UniWebsocketManager(IUniWebsocketManager):
199
199
  Возвращает:
200
200
  `Websocket`: Экземпляр вебсокета.
201
201
  """
202
- raise NotImplementedError()
202
+ return self.trades(callback, symbol=symbol, symbols=symbols) # type: ignore
203
203
 
204
204
  @overload
205
205
  def futures_trades(
@@ -280,4 +280,4 @@ class UniWebsocketManager(IUniWebsocketManager):
280
280
  Возвращает:
281
281
  `Websocket`: Экземпляр вебсокета.
282
282
  """
283
- raise NotImplementedError()
283
+ return self.futures_trades(callback, symbol=symbol, symbols=symbols) # type: ignore
@@ -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, MarketType, Timeframe
9
9
  from unicex.types import LoggerLike
10
10
 
11
11
  from .adapter import Adapter
@@ -76,7 +76,17 @@ class UniWebsocketManager(IUniWebsocketManager):
76
76
  Возвращает:
77
77
  `Websocket`: Экземпляр вебсокета для управления соединением.
78
78
  """
79
- raise NotImplementedError()
79
+ wrapper = self._make_wrapper(self._adapter.klines_message, callback)
80
+ return self._websocket_manager.candlestick(
81
+ callback=wrapper,
82
+ market_type="SPOT",
83
+ symbol=symbol,
84
+ symbols=symbols,
85
+ interval=timeframe.to_exchange_format(
86
+ Exchange.BITGET,
87
+ MarketType.FUTURES, # Тут пришлось поставить Futures, потому что:
88
+ ), # кто бы мог подумать, что у Bitget на споте для вебсокетов и HTTP запросов совершенно разные перечисления. Тупые ублюдки.
89
+ )
80
90
 
81
91
  @overload
82
92
  def futures_klines(
@@ -118,7 +128,14 @@ class UniWebsocketManager(IUniWebsocketManager):
118
128
  Возвращает:
119
129
  `Websocket`: Экземпляр вебсокета.
120
130
  """
121
- raise NotImplementedError()
131
+ wrapper = self._make_wrapper(self._adapter.klines_message, callback)
132
+ return self._websocket_manager.candlestick(
133
+ callback=wrapper,
134
+ market_type="USDT-FUTURES",
135
+ symbol=symbol,
136
+ symbols=symbols,
137
+ interval=timeframe.to_exchange_format(Exchange.BITGET, MarketType.FUTURES),
138
+ )
122
139
 
123
140
  @overload
124
141
  def trades(
@@ -276,4 +293,4 @@ class UniWebsocketManager(IUniWebsocketManager):
276
293
  Возвращает:
277
294
  `Websocket`: Экземпляр вебсокета.
278
295
  """
279
- raise NotImplementedError()
296
+ return self.futures_trades(callback=callback, symbol=symbol, symbols=symbols) # type: ignore[reportCallIssue]
unicex/gate/adapter.py CHANGED
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import time
4
+ from typing import Any
4
5
 
5
6
  __all__ = ["Adapter"]
6
7
 
@@ -10,6 +11,7 @@ from unicex.types import (
10
11
  OpenInterestItem,
11
12
  TickerDailyDict,
12
13
  TickerDailyItem,
14
+ TradeDict,
13
15
  )
14
16
  from unicex.utils import catch_adapter_errors, decorate_all_methods
15
17
 
@@ -177,3 +179,103 @@ class Adapter:
177
179
  )
178
180
  for item in raw_data
179
181
  }
182
+
183
+ @staticmethod
184
+ def klines_message(raw_msg: Any) -> list[KlineDict]:
185
+ """Преобразует вебсокет-сообщение со свечами в унифицированный формат.
186
+
187
+ Параметры:
188
+ raw_msg (Any): Сырое сообщение с вебсокета.
189
+
190
+ Возвращает:
191
+ list[KlineDict]: Список свечей в унифицированном формате.
192
+ """
193
+ data = raw_msg["result"]
194
+ return [
195
+ KlineDict(
196
+ s=data["n"].split("_", 1)[1], # XRP_USDT
197
+ t=int(data["t"]) * 1000,
198
+ o=float(data["o"]),
199
+ h=float(data["h"]),
200
+ l=float(data["l"]),
201
+ c=float(data["c"]),
202
+ v=float(data["a"]),
203
+ q=float(data["v"]),
204
+ T=None,
205
+ x=not data["w"], # w=False → свеча закрыта
206
+ )
207
+ ]
208
+
209
+ @staticmethod
210
+ def futures_klines_message(raw_msg: Any) -> list[KlineDict]:
211
+ """Преобразует вебсокет-сообщение со свечами в унифицированный формат.
212
+
213
+ Параметры:
214
+ raw_msg (Any): Сырое сообщение с вебсокета.
215
+
216
+ Возвращает:
217
+ list[KlineDict]: Список свечей в унифицированном формате.
218
+ """
219
+ return [
220
+ KlineDict(
221
+ s=item["n"].split("_", 1)[1], # XRP_USDT
222
+ t=int(item["t"]) * 1000,
223
+ o=float(item["o"]),
224
+ h=float(item["h"]),
225
+ l=float(item["l"]),
226
+ c=float(item["c"]),
227
+ v=float(item["a"]),
228
+ q=float(item["v"]),
229
+ T=None,
230
+ x=not item["w"], # w=False → свеча закрыта
231
+ )
232
+ for item in sorted(
233
+ raw_msg["result"],
234
+ key=lambda x: int(x["t"]),
235
+ )
236
+ ]
237
+
238
+ @staticmethod
239
+ def trades_message(raw_msg: Any) -> list[TradeDict]:
240
+ """Преобразует вебсокет-сообщение со сделками в унифицированный формат.
241
+
242
+ Параметры:
243
+ raw_msg (Any): Сырое сообщение с вебсокета.
244
+
245
+ Возвращает:
246
+ list[TradeDict]: Список сделок в унифицированном формате.
247
+ """
248
+ trade = raw_msg["result"]
249
+ return [
250
+ TradeDict(
251
+ t=trade["create_time_ms"],
252
+ s=trade["currency_pair"],
253
+ S=trade["side"].upper(),
254
+ p=float(trade["price"]),
255
+ v=float(trade["amount"]),
256
+ )
257
+ ]
258
+
259
+ @staticmethod
260
+ def futures_trades_message(raw_msg: Any) -> list[TradeDict]:
261
+ """Преобразует вебсокет-сообщение со сделками в унифицированный формат.
262
+
263
+ Параметры:
264
+ raw_msg (Any): Сырое сообщение с вебсокета.
265
+
266
+ Возвращает:
267
+ list[TradeDict]: Список сделок в унифицированном формате.
268
+ """
269
+ return [
270
+ TradeDict(
271
+ t=item["create_time_ms"],
272
+ s=item["contract"],
273
+ S="BUY" if float(item["size"]) > 0 else "SELL",
274
+ p=float(item["price"]),
275
+ v=abs(float(item["size"])),
276
+ )
277
+ for item in sorted(
278
+ raw_msg["result"],
279
+ key=lambda x: x["create_time_ms"],
280
+ )
281
+ ]
@@ -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, MarketType, Timeframe
9
9
  from unicex.types import LoggerLike
10
10
 
11
11
  from .adapter import Adapter
@@ -36,6 +36,20 @@ class UniWebsocketManager(IUniWebsocketManager):
36
36
  self._websocket_manager = WebsocketManager(self._client, **ws_kwargs) # type: ignore
37
37
  self._adapter = Adapter()
38
38
 
39
+ def _normalize_symbols(
40
+ self,
41
+ symbol: str | None,
42
+ symbols: Sequence[str] | None,
43
+ ) -> list[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
+ return list(symbols)
51
+ raise ValueError("Either symbol or symbols must be provided")
52
+
39
53
  @overload
40
54
  def klines(
41
55
  self,
@@ -76,7 +90,14 @@ class UniWebsocketManager(IUniWebsocketManager):
76
90
  Возвращает:
77
91
  `Websocket`: Экземпляр вебсокета для управления соединением.
78
92
  """
79
- raise NotImplementedError()
93
+ tickers = self._normalize_symbols(symbol, symbols)
94
+
95
+ wrapper = self._make_wrapper(self._adapter.klines_message, callback)
96
+ return self._websocket_manager.candlesticks(
97
+ callback=wrapper,
98
+ interval=timeframe.to_exchange_format(Exchange.GATE, MarketType.SPOT),
99
+ symbols=tickers,
100
+ )
80
101
 
81
102
  @overload
82
103
  def futures_klines(
@@ -118,7 +139,14 @@ class UniWebsocketManager(IUniWebsocketManager):
118
139
  Возвращает:
119
140
  `Websocket`: Экземпляр вебсокета.
120
141
  """
121
- raise NotImplementedError()
142
+ tickers = self._normalize_symbols(symbol, symbols)
143
+
144
+ wrapper = self._make_wrapper(self._adapter.futures_klines_message, callback)
145
+ return self._websocket_manager.futures_candlesticks(
146
+ callback=wrapper,
147
+ interval=timeframe.to_exchange_format(Exchange.GATE, MarketType.FUTURES),
148
+ symbols=tickers,
149
+ )
122
150
 
123
151
  @overload
124
152
  def trades(
@@ -156,7 +184,10 @@ class UniWebsocketManager(IUniWebsocketManager):
156
184
  Возвращает:
157
185
  `Websocket`: Экземпляр вебсокета.
158
186
  """
159
- raise NotImplementedError()
187
+ tickers = self._normalize_symbols(symbol, symbols)
188
+
189
+ wrapper = self._make_wrapper(self._adapter.trades_message, callback)
190
+ return self._websocket_manager.trades(callback=wrapper, symbols=tickers)
160
191
 
161
192
  @overload
162
193
  def aggtrades(
@@ -194,7 +225,7 @@ class UniWebsocketManager(IUniWebsocketManager):
194
225
  Возвращает:
195
226
  `Websocket`: Экземпляр вебсокета.
196
227
  """
197
- raise NotImplementedError()
228
+ return self.trades(callback=callback, symbol=symbol, symbols=symbols) # type: ignore[reportCallIssue]
198
229
 
199
230
  @overload
200
231
  def futures_trades(
@@ -232,7 +263,10 @@ class UniWebsocketManager(IUniWebsocketManager):
232
263
  Возвращает:
233
264
  `Websocket`: Экземпляр вебсокета.
234
265
  """
235
- raise NotImplementedError()
266
+ tickers = self._normalize_symbols(symbol, symbols)
267
+
268
+ wrapper = self._make_wrapper(self._adapter.futures_trades_message, callback)
269
+ return self._websocket_manager.futures_trades(callback=wrapper, symbols=tickers)
236
270
 
237
271
  @overload
238
272
  def futures_aggtrades(
@@ -270,4 +304,4 @@ class UniWebsocketManager(IUniWebsocketManager):
270
304
  Возвращает:
271
305
  `Websocket`: Экземпляр вебсокета.
272
306
  """
273
- raise NotImplementedError()
307
+ return self.futures_trades(callback=callback, symbol=symbol, symbols=symbols) # type: ignore[reportCallIssue]
unicex/mexc/adapter.py CHANGED
@@ -1,11 +1,14 @@
1
1
  __all__ = ["Adapter"]
2
2
 
3
+ from typing import Any
4
+
3
5
  from unicex.types import (
4
6
  KlineDict,
5
7
  OpenInterestDict,
6
8
  OpenInterestItem,
7
9
  TickerDailyDict,
8
10
  TickerDailyItem,
11
+ TradeDict,
9
12
  )
10
13
  from unicex.utils import catch_adapter_errors, decorate_all_methods
11
14
 
@@ -231,6 +234,106 @@ class Adapter:
231
234
 
232
235
  return sorted(klines, key=lambda kline_item: kline_item["t"])
233
236
 
237
+ @staticmethod
238
+ def klines_message(raw_msg: Any) -> list[KlineDict]:
239
+ """Преобразует вебсокет-сообщение со свечами в унифицированный формат.
240
+
241
+ Параметры:
242
+ raw_msg (Any): Сырое сообщение с вебсокета.
243
+
244
+ Возвращает:
245
+ list[KlineDict]: Список свечей в унифицированном формате.
246
+ """
247
+ kline = raw_msg["publicSpotKline"]
248
+ return [
249
+ KlineDict(
250
+ s=raw_msg["symbol"],
251
+ t=int(kline["windowStart"]) * 1000,
252
+ o=float(kline["openingPrice"]),
253
+ h=float(kline["highestPrice"]),
254
+ l=float(kline["lowestPrice"]),
255
+ c=float(kline["closingPrice"]),
256
+ v=float(kline["volume"]),
257
+ T=int(kline["windowEnd"]) * 1000,
258
+ x=None,
259
+ q=float(kline["amount"]),
260
+ )
261
+ ]
262
+
263
+ @staticmethod
264
+ def futures_klines_message(raw_msg: Any) -> list[KlineDict]:
265
+ """Преобразует вебсокет-сообщение со свечами в унифицированный формат.
266
+
267
+ Параметры:
268
+ raw_msg (Any): Сырое сообщение с вебсокета.
269
+
270
+ Возвращает:
271
+ list[KlineDict]: Список свечей в унифицированном формате.
272
+ """
273
+ data = raw_msg["data"]
274
+ return [
275
+ KlineDict(
276
+ s=data["symbol"],
277
+ t=data["t"] * 1000,
278
+ o=data["o"],
279
+ h=data["h"],
280
+ l=data["l"],
281
+ c=data["c"],
282
+ v=data["q"], # Контракты
283
+ q=data["a"],
284
+ T=None,
285
+ x=None,
286
+ )
287
+ ]
288
+
289
+ @staticmethod
290
+ def trades_message(raw_msg: Any) -> list[TradeDict]:
291
+ """Преобразует вебсокет-сообщение со сделками в унифицированный формат.
292
+
293
+ Параметры:
294
+ raw_msg (Any): Сырое сообщение с вебсокета.
295
+
296
+ Возвращает:
297
+ list[TradeDict]: Список сделок в унифицированном формате.
298
+ """
299
+ return [
300
+ TradeDict(
301
+ t=trade["time"],
302
+ s=raw_msg["symbol"],
303
+ S="BUY" if trade["tradeType"] == 1 else "SELL",
304
+ p=float(trade["price"]),
305
+ v=float(trade["quantity"]),
306
+ )
307
+ for trade in sorted(
308
+ raw_msg["publicAggreDeals"]["deals"],
309
+ key=lambda item: item["time"],
310
+ )
311
+ ]
312
+
313
+ @staticmethod
314
+ def futures_trades_message(raw_msg: Any) -> list[TradeDict]:
315
+ """Преобразует вебсокет-сообщение со сделками в унифицированный формат.
316
+
317
+ Параметры:
318
+ raw_msg (Any): Сырое сообщение с вебсокета.
319
+
320
+ Возвращает:
321
+ list[TradeDict]: Список сделок в унифицированном формате.
322
+ """
323
+ return [
324
+ TradeDict(
325
+ t=item["t"],
326
+ s=raw_msg["symbol"],
327
+ S="BUY" if item["T"] == 1 else "SELL",
328
+ p=item["p"],
329
+ v=item["v"],
330
+ )
331
+ for item in sorted(
332
+ raw_msg["data"],
333
+ key=lambda item: item["t"],
334
+ )
335
+ ]
336
+
234
337
  @staticmethod
235
338
  def _get_contract_size(symbol: str) -> float:
236
339
  """Возвращает размер контракта для указанного символа тикера."""
@@ -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, MarketType, Timeframe
9
9
  from unicex.types import LoggerLike
10
10
 
11
11
  from .adapter import Adapter
@@ -76,7 +76,15 @@ class UniWebsocketManager(IUniWebsocketManager):
76
76
  Возвращает:
77
77
  `Websocket`: Экземпляр вебсокета для управления соединением.
78
78
  """
79
- raise NotImplementedError()
79
+ wrapper = self._make_wrapper(self._adapter.klines_message, callback)
80
+ return self._websocket_manager.klines(
81
+ callback=wrapper,
82
+ symbol=symbol,
83
+ symbols=symbols,
84
+ interval=timeframe.to_exchange_format(
85
+ Exchange.MEXC, MarketType.FUTURES
86
+ ), # Тут фьючерсный интервал, потому что для вебсокета MEXC решили что сделают так (идиоты)
87
+ )
80
88
 
81
89
  @overload
82
90
  def futures_klines(
@@ -118,7 +126,13 @@ class UniWebsocketManager(IUniWebsocketManager):
118
126
  Возвращает:
119
127
  `Websocket`: Экземпляр вебсокета.
120
128
  """
121
- raise NotImplementedError()
129
+ wrapper = self._make_wrapper(self._adapter.futures_klines_message, callback)
130
+ return self._websocket_manager.futures_kline(
131
+ callback=wrapper,
132
+ symbol=symbol,
133
+ symbols=symbols,
134
+ interval=timeframe.to_exchange_format(Exchange.MEXC, MarketType.FUTURES),
135
+ )
122
136
 
123
137
  @overload
124
138
  def trades(
@@ -156,7 +170,8 @@ class UniWebsocketManager(IUniWebsocketManager):
156
170
  Возвращает:
157
171
  `Websocket`: Экземпляр вебсокета.
158
172
  """
159
- raise NotImplementedError()
173
+ wrapper = self._make_wrapper(self._adapter.trades_message, callback)
174
+ return self._websocket_manager.trade(callback=wrapper, symbol=symbol, symbols=symbols)
160
175
 
161
176
  @overload
162
177
  def aggtrades(
@@ -194,7 +209,7 @@ class UniWebsocketManager(IUniWebsocketManager):
194
209
  Возвращает:
195
210
  `Websocket`: Экземпляр вебсокета.
196
211
  """
197
- raise NotImplementedError()
212
+ return self.trades(callback=callback, symbol=symbol, symbols=symbols) # type: ignore[reportCallIssue]
198
213
 
199
214
  @overload
200
215
  def futures_trades(
@@ -232,7 +247,10 @@ class UniWebsocketManager(IUniWebsocketManager):
232
247
  Возвращает:
233
248
  `Websocket`: Экземпляр вебсокета.
234
249
  """
235
- raise NotImplementedError()
250
+ wrapper = self._make_wrapper(self._adapter.futures_trades_message, callback)
251
+ return self._websocket_manager.futures_trade(
252
+ callback=wrapper, symbol=symbol, symbols=symbols
253
+ )
236
254
 
237
255
  @overload
238
256
  def futures_aggtrades(
@@ -270,4 +288,4 @@ class UniWebsocketManager(IUniWebsocketManager):
270
288
  Возвращает:
271
289
  `Websocket`: Экземпляр вебсокета.
272
290
  """
273
- raise NotImplementedError()
291
+ return self.futures_trades(callback=callback, symbol=symbol, symbols=symbols) # type: ignore[reportCallIssue]
@@ -380,7 +380,30 @@ class WebsocketManager:
380
380
  `Websocket`: Объект для управления вебсокет соединением.
381
381
  """
382
382
  subscription_messages = self._generate_futures_subscription_message(
383
- topic="sub.deal", symbol=symbol, symbols=symbols, interval=interval
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
384
407
  )
385
408
  return self._create_futures_websocket(callback, subscription_messages)
386
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
 
@@ -139,3 +142,50 @@ class Adapter:
139
142
  )
140
143
  for item in raw_data["data"]
141
144
  }
145
+
146
+ @staticmethod
147
+ def klines_message(raw_msg: Any) -> list[KlineDict]:
148
+ """Преобразует вебсокет-сообщение со свечами в унифицированный формат.
149
+
150
+ Параметры:
151
+ raw_msg (Any): Сырое сообщение с вебсокета.
152
+
153
+ Возвращает:
154
+ list[KlineDict]: Список свечей в унифицированном формате.
155
+ """
156
+ return [
157
+ KlineDict(
158
+ s=raw_msg["arg"]["instId"],
159
+ t=int(kline[0]),
160
+ o=float(kline[1]),
161
+ h=float(kline[2]),
162
+ l=float(kline[3]),
163
+ c=float(kline[4]),
164
+ v=float(kline[6]),
165
+ q=float(kline[7]),
166
+ T=None,
167
+ x=bool(int(kline[8])),
168
+ )
169
+ for kline in sorted(raw_msg["data"], key=lambda item: int(item[0]))
170
+ ]
171
+
172
+ @staticmethod
173
+ def trades_message(raw_msg: Any) -> list[TradeDict]:
174
+ """Преобразует вебсокет-сообщение со сделками в унифицированный формат.
175
+
176
+ Параметры:
177
+ raw_msg (Any): Сырое сообщение с вебсокета.
178
+
179
+ Возвращает:
180
+ list[TradeDict]: Список сделок в унифицированном формате.
181
+ """
182
+ return [
183
+ TradeDict(
184
+ t=int(trade["ts"]),
185
+ s=trade["instId"],
186
+ S=trade["side"].upper(),
187
+ p=float(trade["px"]),
188
+ v=float(trade["sz"]),
189
+ )
190
+ for trade in sorted(raw_msg["data"], key=lambda item: int(item["ts"]))
191
+ ]
@@ -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
@@ -36,6 +36,23 @@ class UniWebsocketManager(IUniWebsocketManager):
36
36
  self._websocket_manager = WebsocketManager(self._client, **ws_kwargs) # type: ignore
37
37
  self._adapter = Adapter()
38
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
+
39
56
  @overload
40
57
  def klines(
41
58
  self,
@@ -76,7 +93,13 @@ class UniWebsocketManager(IUniWebsocketManager):
76
93
  Возвращает:
77
94
  `Websocket`: Экземпляр вебсокета для управления соединением.
78
95
  """
79
- raise NotImplementedError()
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
+ )
80
103
 
81
104
  @overload
82
105
  def futures_klines(
@@ -118,7 +141,13 @@ class UniWebsocketManager(IUniWebsocketManager):
118
141
  Возвращает:
119
142
  `Websocket`: Экземпляр вебсокета.
120
143
  """
121
- raise NotImplementedError()
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
+ )
122
151
 
123
152
  @overload
124
153
  def trades(
@@ -156,7 +185,9 @@ class UniWebsocketManager(IUniWebsocketManager):
156
185
  Возвращает:
157
186
  `Websocket`: Экземпляр вебсокета.
158
187
  """
159
- raise NotImplementedError()
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)
160
191
 
161
192
  @overload
162
193
  def aggtrades(
@@ -194,7 +225,9 @@ class UniWebsocketManager(IUniWebsocketManager):
194
225
  Возвращает:
195
226
  `Websocket`: Экземпляр вебсокета.
196
227
  """
197
- raise NotImplementedError()
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)
198
231
 
199
232
  @overload
200
233
  def futures_trades(
@@ -232,7 +265,9 @@ class UniWebsocketManager(IUniWebsocketManager):
232
265
  Возвращает:
233
266
  `Websocket`: Экземпляр вебсокета.
234
267
  """
235
- raise NotImplementedError()
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)
236
271
 
237
272
  @overload
238
273
  def futures_aggtrades(
@@ -270,4 +305,6 @@ class UniWebsocketManager(IUniWebsocketManager):
270
305
  Возвращает:
271
306
  `Websocket`: Экземпляр вебсокета.
272
307
  """
273
- raise NotImplementedError()
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)
unicex/types.py CHANGED
@@ -79,10 +79,10 @@ class KlineDict(TypedDict):
79
79
  q: float
80
80
  """Объем свечи. В долларах."""
81
81
 
82
- T: int | None
82
+ T: int | None # `None` means untrackable
83
83
  """Время закрытия. В миллисекундах."""
84
84
 
85
- x: bool | None
85
+ x: bool | None # `None` means untrackable
86
86
  """Флаг закрыта ли свеча."""
87
87
 
88
88
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: unicex
3
- Version: 0.15.4
3
+ Version: 0.16.0
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,12 @@ 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
65
  | **Kucoin** | | | | | ✓ | | |
66
66
  | **BingX** | | | | | ✓ | | |
67
67
  ---
@@ -3,7 +3,7 @@ unicex/enums.py,sha256=5iJo1uokNlS9FQQtomK0LiEcXuHqF9cBEg2aPAX3QDk,10296
3
3
  unicex/exceptions.py,sha256=r-xZzX78VuxVnI5pe99AM8FIiGcdIUDcF5CaTkQ4NE0,2213
4
4
  unicex/extra.py,sha256=YJKl2X-T1BtaSR0t-CpvxaGE0emNpgts807lmD_3ejA,13686
5
5
  unicex/mapper.py,sha256=b4a99_VVpEBGzctUJxvxLvu8urSrIQEziCt9cKlfg6w,5331
6
- unicex/types.py,sha256=u2OtyfiXMpmafHNOXBCEC1MI3jzfG9Km_Gdr3ig80vM,5074
6
+ unicex/types.py,sha256=Vl7I_kg5W5UQysMCOKH9Hvu3zJF9uCr5zftBFH3UpVA,5130
7
7
  unicex/utils.py,sha256=1iK-ifZ-hUaU4Z-YCLoZsjAZREfJO7amYsjzG70JEk8,9963
8
8
  unicex/_abc/__init__.py,sha256=fxZjNFJFeFwWTXz8iSDe7eCWwE6xfFwFwAuG6l-TI8A,289
9
9
  unicex/_abc/exchange_info.py,sha256=TP_theOj1JS3Dcx5hqGT1yma1Jed776N4okOKXB7ePw,9537
@@ -25,7 +25,7 @@ unicex/bingx/adapter.py,sha256=1QZSfrpgMlTu-ZuLWtO61caqC6ygRTViI5Plt25Ybi4,11937
25
25
  unicex/bingx/client.py,sha256=VPPIDKH86i1KR-6Xr8RXO7nSt7KhKNnp7Sz4spnZm-E,16899
26
26
  unicex/bingx/exchange_info.py,sha256=dfUl2V7ec82eEDE_u6AuMB9dQ8iAWh03HcaUPaOo_mo,786
27
27
  unicex/bingx/uni_client.py,sha256=NKJVq2ce4UbK1jnKTLOIX2X2a5LzhPh_oG6_JrH4P6o,8196
28
- unicex/bingx/uni_websocket_manager.py,sha256=cFVR5uPdpooF6gRsAX_6cGRnud2UjXNUa82A0WW2Z08,9962
28
+ unicex/bingx/uni_websocket_manager.py,sha256=Hg1XXyAO1FW3_4PmoTB3Z0KuRt7traLBYHWtPqy7-YQ,10068
29
29
  unicex/bingx/user_websocket.py,sha256=UgWt2hMaNqEUibf-1MfCIkJijx7Vb_HN8DiXaclMCog,128
30
30
  unicex/bingx/websocket_manager.py,sha256=Is9aurewMICA0n90YTGK3ET4J269bvklJFwDJRzQKNg,4855
31
31
  unicex/bitget/__init__.py,sha256=8govSOEyWjA62js-ZTQIiSYWSmcEUFSC9hVTpS8eosk,929
@@ -33,7 +33,7 @@ unicex/bitget/adapter.py,sha256=t1Jsn9LYeMx_LUJjPmrAuuhTB1lcpyBViSMzjUIfX_k,7768
33
33
  unicex/bitget/client.py,sha256=0NFOixkMb0AcC5e-LytUd4Y1jxCO6Lv6-I4XlOGNtxQ,90618
34
34
  unicex/bitget/exchange_info.py,sha256=_UMvAqP0zcpmv9dkovkFxrXLlol6q8_v7-0sy6FSfrE,1959
35
35
  unicex/bitget/uni_client.py,sha256=MrXAmthTDTEQZ1ZY3LuqkCKL1bw_mKHMdiV4XiRFO-M,8641
36
- unicex/bitget/uni_websocket_manager.py,sha256=ybf-_HPU-aQy7M27rfKDPSdxjI5ZzkfKCzzim-WA5l8,10038
36
+ unicex/bitget/uni_websocket_manager.py,sha256=BAeH6GwVdYjpxe5xw1K7jrAyH6Lj02xawiv9kXvksLE,11105
37
37
  unicex/bitget/user_websocket.py,sha256=tlkv7Rmsw_FSfCJnEMOK_9jRsXRk2Ah_slqG8C-uhuo,129
38
38
  unicex/bitget/websocket_manager.py,sha256=Tra_E_z1QQ_snFYwqa49FmU-uWISYnbyJK5e7zqb48o,9765
39
39
  unicex/bybit/__init__.py,sha256=SrMBh6K5zUt4JheWUpNUYNb1NCDr2ujTFv4IDguaGZI,926
@@ -45,11 +45,11 @@ unicex/bybit/uni_websocket_manager.py,sha256=HhgFcGo2yQLT5knU3cFaKN85jJP0Z9EIwZ-
45
45
  unicex/bybit/user_websocket.py,sha256=IGGEnwyWs5jOppgK_R7SisBDvsiF1_piTswBrdQOgDg,128
46
46
  unicex/bybit/websocket_manager.py,sha256=y8YiQEPtVg3Xj7seuNSbQMt5FrM-snWx9KlNioKeNVo,14413
47
47
  unicex/gate/__init__.py,sha256=dsKvhQhDcw4_w0S4c9IjKkCoOg4DCUtSecEUOlfstug,929
48
- unicex/gate/adapter.py,sha256=wQcvwujl0aVwhJVLMjJE_yMWz19S98rVgT6oBzFBr7M,6956
48
+ unicex/gate/adapter.py,sha256=33ytBbyw2SrHDg-4so1mxXCqB7e-zG1wp6yR_XF8exY,10738
49
49
  unicex/gate/client.py,sha256=Mu8qropad8DTSDuG6mxyn6ZW2hwQK47PZnfb5yOEt2M,53828
50
50
  unicex/gate/exchange_info.py,sha256=ANzfe4mqxtLnj2TBJJxoc31KUosvxdApp1_xYrRNQDs,2300
51
51
  unicex/gate/uni_client.py,sha256=EVhQ4KF7F6y67b2oARcYzSrSnHTFsUjoXK1vLntK6u0,9649
52
- unicex/gate/uni_websocket_manager.py,sha256=_baRRpC0zUgAqpn6PygULhGkO1mhlepyIo0kOpUItRM,9574
52
+ unicex/gate/uni_websocket_manager.py,sha256=dESHYEPf832b5tdMwo_9wdMaE6I_ZOKwEtnhnuofx_c,11285
53
53
  unicex/gate/user_websocket.py,sha256=4qZX9N2RjlJ-e25Eszz12OeCM17j5DdXVimBVaLj53w,129
54
54
  unicex/gate/websocket_manager.py,sha256=phtHbvAGQD3mtewCUxBuuD1Nj0FXN6oZrd7tnmT7c2c,25832
55
55
  unicex/hyperliquid/__init__.py,sha256=qGTAkwfXLvknvHET_iA7Qml3jkxxxA0moU_98nGTcVU,944
@@ -69,13 +69,13 @@ unicex/kucoin/uni_websocket_manager.py,sha256=rvrhQkvktZhbfb505KmkiBtf7Y4drClgtq
69
69
  unicex/kucoin/user_websocket.py,sha256=Tx0yuGpf2HrPbcOHHZioYjVp6LBfagOKF-zzD3UM0Ok,129
70
70
  unicex/kucoin/websocket_manager.py,sha256=GNNpzxONgTuTByrsGk1MNMlj5-zx5vs_WBTgssYSYDQ,270
71
71
  unicex/mexc/__init__.py,sha256=lltANqM_2P-fmF5j8o5-pjmORPuK6C5sVjcQhuUU_R0,923
72
- unicex/mexc/adapter.py,sha256=WhjOsdBssBkWQhQjbpMWIeAqaKXvsq6rDRQD7A34yws,9889
72
+ unicex/mexc/adapter.py,sha256=zqWIQgzTytUrE46hi0XL52R5z-K_K1pSfkdJzf7eXNg,13583
73
73
  unicex/mexc/client.py,sha256=FBUSs4Hu2DExVKPKJG9OawbqidACPFJ1U_1md05E3Mc,31004
74
74
  unicex/mexc/exchange_info.py,sha256=z2bQsVU0ciXV2_DFkueZHo1X35KIK2alD-7ZZjNg5Kc,1763
75
75
  unicex/mexc/uni_client.py,sha256=_nYIl46-yvyUVKZxkSLCHRxgTnM75TmZqaxCsUp8woI,9482
76
- unicex/mexc/uni_websocket_manager.py,sha256=zN9U7geR1jO5VLWsjsTdITrlhyCnan5hiKO2p0gBhBQ,9572
76
+ unicex/mexc/uni_websocket_manager.py,sha256=4doElI-dPvAXs8a5HpU8gtpZznWf7YtAXTl8lTLjsiU,10804
77
77
  unicex/mexc/user_websocket.py,sha256=l77-e6i0B2btd7a5IcCytbgswnV171NqOhunTcbaq48,127
78
- unicex/mexc/websocket_manager.py,sha256=Z12jn6BEk1F1qvtuQ1xvTAlauK1sjo9fGgtcX9AoyCY,21750
78
+ unicex/mexc/websocket_manager.py,sha256=0VhgXJil4xXm-YLuW2WVT7REv0oaivd9nZ4VI14rUzI,22926
79
79
  unicex/mexc/_spot_ws_proto/PrivateAccountV3Api_pb2.py,sha256=3bP1pGjeO-Norp7DhhdrQ4FcQTEKkCiL2mLagyoJHp8,1879
80
80
  unicex/mexc/_spot_ws_proto/PrivateDealsV3Api_pb2.py,sha256=mamFaZHymW5HhoTO8_mZz9y8kQcIsguCpaLf6xpC4Cc,1991
81
81
  unicex/mexc/_spot_ws_proto/PrivateOrdersV3Api_pb2.py,sha256=HsQUfInnjlsn8SJkobN-5FK1PS_0NsIvyuT1ABtbdTY,2982
@@ -95,15 +95,15 @@ unicex/mexc/_spot_ws_proto/PublicSpotKlineV3Api_pb2.py,sha256=0FOMsSO4jzMQ6446yZ
95
95
  unicex/mexc/_spot_ws_proto/PushDataV3ApiWrapper_pb2.py,sha256=_V0StMrDE7-bsdRPQdTC2XLGDGqJ5U_scx8ZjcyCGgk,3735
96
96
  unicex/mexc/_spot_ws_proto/__init__.py,sha256=L8Jft1713_M8CLR9drgSjLBdY_46sPT3O9zDFlxYvgc,11431
97
97
  unicex/okx/__init__.py,sha256=Ljbw3AP0YrPF5bIPJi_3JP3B_czR9xurYHI24rgWk9M,920
98
- unicex/okx/adapter.py,sha256=B04_YmRr5R1FWSAbjWE51rd5zG_A88bmbXWrVez2HK8,5373
98
+ unicex/okx/adapter.py,sha256=33JHJobh5CnldEkmFi7fEdBszJI5IB1KxuJ5m7fUlg4,7185
99
99
  unicex/okx/client.py,sha256=N7ma49ToMGjYiTvuoV52-NaG-vLx3s087KF67dQCRBs,91079
100
100
  unicex/okx/exchange_info.py,sha256=gkTwYnXgswa1FGLXdKo9qLYqZA0BS9VefpALhR4_t-Q,1772
101
101
  unicex/okx/uni_client.py,sha256=E_Wod0JSGt1K6k1mAIWnOv350pELbv-nic7g1KgOuos,8694
102
- unicex/okx/uni_websocket_manager.py,sha256=CR877hj4pKwJbYlmKJvETl1Zlezpd81ZdzHkAMCYIwA,9571
102
+ unicex/okx/uni_websocket_manager.py,sha256=wrROl5RmxCJC8o_k6mc1UufbNsOKTRhIFqq5yinXUBQ,11626
103
103
  unicex/okx/user_websocket.py,sha256=8c9kpm-xVa729pW93OKUGLHaE9MY0uzEpjIgNIFRF80,126
104
104
  unicex/okx/websocket_manager.py,sha256=rougqBUOV8XeJszRDtmSFSyaaphmHr1kKQk926K080w,26042
105
- unicex-0.15.4.dist-info/licenses/LICENSE,sha256=lNNK4Vqak9cXm6qVJLhbqS7iR_BMj6k7fd7XQ6l1k54,1507
106
- unicex-0.15.4.dist-info/METADATA,sha256=qa34lhsjmWfZj1hkfjOU5iRiT6zgSWuWA6nxHsVn1M8,11964
107
- unicex-0.15.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
108
- unicex-0.15.4.dist-info/top_level.txt,sha256=_7rar-0OENIg4KRy6cgjWiebFYAJhjKEcMggAocGWG4,7
109
- unicex-0.15.4.dist-info/RECORD,,
105
+ unicex-0.16.0.dist-info/licenses/LICENSE,sha256=lNNK4Vqak9cXm6qVJLhbqS7iR_BMj6k7fd7XQ6l1k54,1507
106
+ unicex-0.16.0.dist-info/METADATA,sha256=-bb8mIOJnajGBe6JYCrPRFgroOhRDJ7MZhhGIywoQCc,11972
107
+ unicex-0.16.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
108
+ unicex-0.16.0.dist-info/top_level.txt,sha256=_7rar-0OENIg4KRy6cgjWiebFYAJhjKEcMggAocGWG4,7
109
+ unicex-0.16.0.dist-info/RECORD,,