unicex 0.15.4__py3-none-any.whl → 0.16.2__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 +0 -2
- unicex/binance/adapter.py +2 -3
- unicex/bingx/uni_websocket_manager.py +2 -2
- unicex/bitget/adapter.py +1 -2
- unicex/bitget/uni_websocket_manager.py +21 -4
- unicex/gate/adapter.py +112 -0
- unicex/gate/uni_websocket_manager.py +41 -7
- unicex/mexc/adapter.py +103 -0
- unicex/mexc/uni_websocket_manager.py +25 -7
- unicex/mexc/websocket_manager.py +24 -1
- unicex/okx/adapter.py +60 -0
- unicex/okx/exchange_info.py +2 -2
- unicex/okx/uni_websocket_manager.py +44 -7
- unicex/okx/websocket_manager.py +116 -163
- unicex/types.py +2 -9
- {unicex-0.15.4.dist-info → unicex-0.16.2.dist-info}/METADATA +5 -5
- {unicex-0.15.4.dist-info → unicex-0.16.2.dist-info}/RECORD +20 -20
- {unicex-0.15.4.dist-info → unicex-0.16.2.dist-info}/WHEEL +0 -0
- {unicex-0.15.4.dist-info → unicex-0.16.2.dist-info}/licenses/LICENSE +0 -0
- {unicex-0.15.4.dist-info → unicex-0.16.2.dist-info}/top_level.txt +0 -0
unicex/__init__.py
CHANGED
|
@@ -18,7 +18,6 @@ __all__ = [
|
|
|
18
18
|
"TickerDailyItem",
|
|
19
19
|
"KlineDict",
|
|
20
20
|
"TradeDict",
|
|
21
|
-
"AggTradeDict",
|
|
22
21
|
"RequestMethod",
|
|
23
22
|
"LoggerLike",
|
|
24
23
|
"OpenInterestDict",
|
|
@@ -112,7 +111,6 @@ from .types import (
|
|
|
112
111
|
TickerDailyItem,
|
|
113
112
|
KlineDict,
|
|
114
113
|
TradeDict,
|
|
115
|
-
AggTradeDict,
|
|
116
114
|
RequestMethod,
|
|
117
115
|
LoggerLike,
|
|
118
116
|
OpenInterestDict,
|
unicex/binance/adapter.py
CHANGED
|
@@ -2,7 +2,6 @@ __all__ = ["Adapter"]
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
from unicex.types import (
|
|
5
|
-
AggTradeDict,
|
|
6
5
|
KlineDict,
|
|
7
6
|
OpenInterestItem,
|
|
8
7
|
TickerDailyDict,
|
|
@@ -150,7 +149,7 @@ class Adapter:
|
|
|
150
149
|
]
|
|
151
150
|
|
|
152
151
|
@staticmethod
|
|
153
|
-
def aggtrades_message(raw_msg: dict) -> list[
|
|
152
|
+
def aggtrades_message(raw_msg: dict) -> list[TradeDict]:
|
|
154
153
|
"""Преобразует сырое сообщение с вебсокета, в котором содержится информация о
|
|
155
154
|
аггрегированных сделке/сделках в унифицированный вид.
|
|
156
155
|
|
|
@@ -162,7 +161,7 @@ class Adapter:
|
|
|
162
161
|
"""
|
|
163
162
|
msg = raw_msg.get("data", raw_msg)
|
|
164
163
|
return [
|
|
165
|
-
|
|
164
|
+
TradeDict(
|
|
166
165
|
t=int(msg["T"]),
|
|
167
166
|
s=str(msg["s"]),
|
|
168
167
|
S="SELL" if bool(msg["m"]) else "BUY",
|
|
@@ -199,7 +199,7 @@ class UniWebsocketManager(IUniWebsocketManager):
|
|
|
199
199
|
Возвращает:
|
|
200
200
|
`Websocket`: Экземпляр вебсокета.
|
|
201
201
|
"""
|
|
202
|
-
|
|
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
|
-
|
|
283
|
+
return self.futures_trades(callback, symbol=symbol, symbols=symbols) # type: ignore
|
unicex/bitget/adapter.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from typing import Any
|
|
2
2
|
|
|
3
3
|
from unicex.types import (
|
|
4
|
-
AggTradeDict,
|
|
5
4
|
KlineDict,
|
|
6
5
|
OpenInterestDict,
|
|
7
6
|
OpenInterestItem,
|
|
@@ -155,7 +154,7 @@ class Adapter:
|
|
|
155
154
|
symbol = raw_msg["arg"]["instId"]
|
|
156
155
|
|
|
157
156
|
return [
|
|
158
|
-
|
|
157
|
+
TradeDict(
|
|
159
158
|
t=int(trade["ts"]),
|
|
160
159
|
s=symbol,
|
|
161
160
|
S=trade["side"].upper(),
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,9 +11,12 @@ 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
|
|
|
18
|
+
from .exchange_info import ExchangeInfo
|
|
19
|
+
|
|
16
20
|
|
|
17
21
|
@decorate_all_methods(catch_adapter_errors)
|
|
18
22
|
class Adapter:
|
|
@@ -177,3 +181,111 @@ class Adapter:
|
|
|
177
181
|
)
|
|
178
182
|
for item in raw_data
|
|
179
183
|
}
|
|
184
|
+
|
|
185
|
+
@staticmethod
|
|
186
|
+
def klines_message(raw_msg: Any) -> list[KlineDict]:
|
|
187
|
+
"""Преобразует вебсокет-сообщение со свечами в унифицированный формат.
|
|
188
|
+
|
|
189
|
+
Параметры:
|
|
190
|
+
raw_msg (Any): Сырое сообщение с вебсокета.
|
|
191
|
+
|
|
192
|
+
Возвращает:
|
|
193
|
+
list[KlineDict]: Список свечей в унифицированном формате.
|
|
194
|
+
"""
|
|
195
|
+
data = raw_msg["result"]
|
|
196
|
+
return [
|
|
197
|
+
KlineDict(
|
|
198
|
+
s=data["n"].split("_", 1)[1], # XRP_USDT
|
|
199
|
+
t=int(data["t"]) * 1000,
|
|
200
|
+
o=float(data["o"]),
|
|
201
|
+
h=float(data["h"]),
|
|
202
|
+
l=float(data["l"]),
|
|
203
|
+
c=float(data["c"]),
|
|
204
|
+
v=float(data["a"]),
|
|
205
|
+
q=float(data["v"]),
|
|
206
|
+
T=None,
|
|
207
|
+
x=not data["w"], # w=False → свеча закрыта
|
|
208
|
+
)
|
|
209
|
+
]
|
|
210
|
+
|
|
211
|
+
@staticmethod
|
|
212
|
+
def futures_klines_message(raw_msg: Any) -> list[KlineDict]:
|
|
213
|
+
"""Преобразует вебсокет-сообщение со свечами в унифицированный формат.
|
|
214
|
+
|
|
215
|
+
Параметры:
|
|
216
|
+
raw_msg (Any): Сырое сообщение с вебсокета.
|
|
217
|
+
|
|
218
|
+
Возвращает:
|
|
219
|
+
list[KlineDict]: Список свечей в унифицированном формате.
|
|
220
|
+
"""
|
|
221
|
+
return [
|
|
222
|
+
KlineDict(
|
|
223
|
+
s=item["n"].split("_", 1)[1], # XRP_USDT
|
|
224
|
+
t=int(item["t"]) * 1000,
|
|
225
|
+
o=float(item["o"]),
|
|
226
|
+
h=float(item["h"]),
|
|
227
|
+
l=float(item["l"]),
|
|
228
|
+
c=float(item["c"]),
|
|
229
|
+
v=float(item["a"]),
|
|
230
|
+
q=float(item["v"]),
|
|
231
|
+
T=None,
|
|
232
|
+
x=not item["w"], # w=False → свеча закрыта
|
|
233
|
+
)
|
|
234
|
+
for item in sorted(
|
|
235
|
+
raw_msg["result"],
|
|
236
|
+
key=lambda x: int(x["t"]),
|
|
237
|
+
)
|
|
238
|
+
]
|
|
239
|
+
|
|
240
|
+
@staticmethod
|
|
241
|
+
def trades_message(raw_msg: Any) -> list[TradeDict]:
|
|
242
|
+
"""Преобразует вебсокет-сообщение со сделками в унифицированный формат.
|
|
243
|
+
|
|
244
|
+
Параметры:
|
|
245
|
+
raw_msg (Any): Сырое сообщение с вебсокета.
|
|
246
|
+
|
|
247
|
+
Возвращает:
|
|
248
|
+
list[TradeDict]: Список сделок в унифицированном формате.
|
|
249
|
+
"""
|
|
250
|
+
trade = raw_msg["result"]
|
|
251
|
+
return [
|
|
252
|
+
TradeDict(
|
|
253
|
+
t=trade["create_time_ms"],
|
|
254
|
+
s=trade["currency_pair"],
|
|
255
|
+
S=trade["side"].upper(),
|
|
256
|
+
p=float(trade["price"]),
|
|
257
|
+
v=float(trade["amount"]),
|
|
258
|
+
)
|
|
259
|
+
]
|
|
260
|
+
|
|
261
|
+
@staticmethod
|
|
262
|
+
def futures_trades_message(raw_msg: Any) -> list[TradeDict]:
|
|
263
|
+
"""Преобразует вебсокет-сообщение со сделками в унифицированный формат.
|
|
264
|
+
|
|
265
|
+
Параметры:
|
|
266
|
+
raw_msg (Any): Сырое сообщение с вебсокета.
|
|
267
|
+
|
|
268
|
+
Возвращает:
|
|
269
|
+
list[TradeDict]: Список сделок в унифицированном формате.
|
|
270
|
+
"""
|
|
271
|
+
return [
|
|
272
|
+
TradeDict(
|
|
273
|
+
t=item["create_time_ms"],
|
|
274
|
+
s=item["contract"],
|
|
275
|
+
S="BUY" if float(item["size"]) > 0 else "SELL",
|
|
276
|
+
p=float(item["price"]),
|
|
277
|
+
v=abs(float(item["size"])) * Adapter._get_contract_size(item["contract"]),
|
|
278
|
+
)
|
|
279
|
+
for item in sorted(
|
|
280
|
+
raw_msg["result"],
|
|
281
|
+
key=lambda x: x["create_time_ms"],
|
|
282
|
+
)
|
|
283
|
+
]
|
|
284
|
+
|
|
285
|
+
@staticmethod
|
|
286
|
+
def _get_contract_size(symbol: str) -> float:
|
|
287
|
+
"""Возвращает размер контракта для указанного символа тикера."""
|
|
288
|
+
try:
|
|
289
|
+
return ExchangeInfo.get_futures_ticker_info(symbol)["contract_size"] or 1
|
|
290
|
+
except: # noqa
|
|
291
|
+
return 1
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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"] * Adapter._get_contract_size(raw_msg["symbol"]),
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
291
|
+
return self.futures_trades(callback=callback, symbol=symbol, symbols=symbols) # type: ignore[reportCallIssue]
|
unicex/mexc/websocket_manager.py
CHANGED
|
@@ -380,7 +380,30 @@ class WebsocketManager:
|
|
|
380
380
|
`Websocket`: Объект для управления вебсокет соединением.
|
|
381
381
|
"""
|
|
382
382
|
subscription_messages = self._generate_futures_subscription_message(
|
|
383
|
-
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
|
|
384
407
|
)
|
|
385
408
|
return self._create_futures_websocket(callback, subscription_messages)
|
|
386
409
|
|
unicex/okx/adapter.py
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
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
|
|
|
16
|
+
from .exchange_info import ExchangeInfo
|
|
17
|
+
|
|
13
18
|
|
|
14
19
|
@decorate_all_methods(catch_adapter_errors)
|
|
15
20
|
class Adapter:
|
|
@@ -139,3 +144,58 @@ class Adapter:
|
|
|
139
144
|
)
|
|
140
145
|
for item in raw_data["data"]
|
|
141
146
|
}
|
|
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
|
+
|
|
195
|
+
@staticmethod
|
|
196
|
+
def _get_contract_size(symbol: str) -> float:
|
|
197
|
+
"""Возвращает размер контракта для указанного символа тикера."""
|
|
198
|
+
try:
|
|
199
|
+
return ExchangeInfo.get_futures_ticker_info(symbol)["contract_size"] or 1
|
|
200
|
+
except: # noqa
|
|
201
|
+
return 1
|
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
|
|