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.
- unicex/__init__.py +200 -0
- unicex/_abc/__init__.py +11 -0
- unicex/_abc/exchange_info.py +216 -0
- unicex/_abc/uni_client.py +329 -0
- unicex/_abc/uni_websocket_manager.py +294 -0
- unicex/_base/__init__.py +9 -0
- unicex/_base/client.py +214 -0
- unicex/_base/websocket.py +261 -0
- unicex/binance/__init__.py +27 -0
- unicex/binance/adapter.py +202 -0
- unicex/binance/client.py +1577 -0
- unicex/binance/exchange_info.py +62 -0
- unicex/binance/uni_client.py +188 -0
- unicex/binance/uni_websocket_manager.py +166 -0
- unicex/binance/user_websocket.py +186 -0
- unicex/binance/websocket_manager.py +912 -0
- unicex/bitget/__init__.py +27 -0
- unicex/bitget/adapter.py +188 -0
- unicex/bitget/client.py +2514 -0
- unicex/bitget/exchange_info.py +48 -0
- unicex/bitget/uni_client.py +198 -0
- unicex/bitget/uni_websocket_manager.py +275 -0
- unicex/bitget/user_websocket.py +7 -0
- unicex/bitget/websocket_manager.py +232 -0
- unicex/bybit/__init__.py +27 -0
- unicex/bybit/adapter.py +208 -0
- unicex/bybit/client.py +1876 -0
- unicex/bybit/exchange_info.py +53 -0
- unicex/bybit/uni_client.py +200 -0
- unicex/bybit/uni_websocket_manager.py +291 -0
- unicex/bybit/user_websocket.py +7 -0
- unicex/bybit/websocket_manager.py +339 -0
- unicex/enums.py +273 -0
- unicex/exceptions.py +64 -0
- unicex/extra.py +335 -0
- unicex/gate/__init__.py +27 -0
- unicex/gate/adapter.py +178 -0
- unicex/gate/client.py +1667 -0
- unicex/gate/exchange_info.py +55 -0
- unicex/gate/uni_client.py +214 -0
- unicex/gate/uni_websocket_manager.py +269 -0
- unicex/gate/user_websocket.py +7 -0
- unicex/gate/websocket_manager.py +513 -0
- unicex/hyperliquid/__init__.py +27 -0
- unicex/hyperliquid/adapter.py +261 -0
- unicex/hyperliquid/client.py +2315 -0
- unicex/hyperliquid/exchange_info.py +119 -0
- unicex/hyperliquid/uni_client.py +325 -0
- unicex/hyperliquid/uni_websocket_manager.py +269 -0
- unicex/hyperliquid/user_websocket.py +7 -0
- unicex/hyperliquid/websocket_manager.py +393 -0
- unicex/mapper.py +111 -0
- unicex/mexc/__init__.py +27 -0
- unicex/mexc/_spot_ws_proto/PrivateAccountV3Api_pb2.py +38 -0
- unicex/mexc/_spot_ws_proto/PrivateDealsV3Api_pb2.py +38 -0
- unicex/mexc/_spot_ws_proto/PrivateOrdersV3Api_pb2.py +38 -0
- unicex/mexc/_spot_ws_proto/PublicAggreBookTickerV3Api_pb2.py +38 -0
- unicex/mexc/_spot_ws_proto/PublicAggreDealsV3Api_pb2.py +40 -0
- unicex/mexc/_spot_ws_proto/PublicAggreDepthsV3Api_pb2.py +40 -0
- unicex/mexc/_spot_ws_proto/PublicBookTickerBatchV3Api_pb2.py +38 -0
- unicex/mexc/_spot_ws_proto/PublicBookTickerV3Api_pb2.py +38 -0
- unicex/mexc/_spot_ws_proto/PublicDealsV3Api_pb2.py +40 -0
- unicex/mexc/_spot_ws_proto/PublicFuture_pb2.py +103 -0
- unicex/mexc/_spot_ws_proto/PublicIncreaseDepthsBatchV3Api_pb2.py +38 -0
- unicex/mexc/_spot_ws_proto/PublicIncreaseDepthsV3Api_pb2.py +40 -0
- unicex/mexc/_spot_ws_proto/PublicLimitDepthsV3Api_pb2.py +40 -0
- unicex/mexc/_spot_ws_proto/PublicMiniTickerV3Api_pb2.py +38 -0
- unicex/mexc/_spot_ws_proto/PublicMiniTickersV3Api_pb2.py +38 -0
- unicex/mexc/_spot_ws_proto/PublicSpotKlineV3Api_pb2.py +38 -0
- unicex/mexc/_spot_ws_proto/PushDataV3ApiWrapper_pb2.py +38 -0
- unicex/mexc/_spot_ws_proto/__init__.py +335 -0
- unicex/mexc/adapter.py +239 -0
- unicex/mexc/client.py +846 -0
- unicex/mexc/exchange_info.py +47 -0
- unicex/mexc/uni_client.py +211 -0
- unicex/mexc/uni_websocket_manager.py +269 -0
- unicex/mexc/user_websocket.py +7 -0
- unicex/mexc/websocket_manager.py +456 -0
- unicex/okx/__init__.py +27 -0
- unicex/okx/adapter.py +150 -0
- unicex/okx/client.py +2864 -0
- unicex/okx/exchange_info.py +47 -0
- unicex/okx/uni_client.py +202 -0
- unicex/okx/uni_websocket_manager.py +269 -0
- unicex/okx/user_websocket.py +7 -0
- unicex/okx/websocket_manager.py +743 -0
- unicex/types.py +164 -0
- unicex/utils.py +218 -0
- unicex-0.13.17.dist-info/METADATA +243 -0
- unicex-0.13.17.dist-info/RECORD +93 -0
- unicex-0.13.17.dist-info/WHEEL +5 -0
- unicex-0.13.17.dist-info/licenses/LICENSE +28 -0
- unicex-0.13.17.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
__all__ = ["Adapter"]
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
|
|
5
|
+
from unicex.types import (
|
|
6
|
+
KlineDict,
|
|
7
|
+
OpenInterestDict,
|
|
8
|
+
OpenInterestItem,
|
|
9
|
+
TickerDailyDict,
|
|
10
|
+
TickerDailyItem,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
# from unicex.utils import catch_adapter_errors, decorate_all_methods
|
|
14
|
+
from .exchange_info import ExchangeInfo
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# @decorate_all_methods(catch_adapter_errors)
|
|
18
|
+
class Adapter:
|
|
19
|
+
"""Адаптер для унификации данных с Hyperliquid API."""
|
|
20
|
+
|
|
21
|
+
@staticmethod
|
|
22
|
+
def tickers(raw_data: dict, resolve_symbols: bool) -> list[str]:
|
|
23
|
+
"""Преобразует данные Hyperliquid в список спотовых тикеров.
|
|
24
|
+
|
|
25
|
+
Параметры:
|
|
26
|
+
raw_data (dict): Сырой ответ с биржи.
|
|
27
|
+
resolve_symbols (bool): Если True, тикеры маппятся из вида "@123" в "BTC".
|
|
28
|
+
|
|
29
|
+
Возвращает:
|
|
30
|
+
list[str]: Список тикеров (например, "@123").
|
|
31
|
+
"""
|
|
32
|
+
if resolve_symbols:
|
|
33
|
+
return [ExchangeInfo.resolve_spot_symbol(item["name"]) for item in raw_data["universe"]]
|
|
34
|
+
else:
|
|
35
|
+
return [item["name"] for item in raw_data["universe"]]
|
|
36
|
+
|
|
37
|
+
@staticmethod
|
|
38
|
+
def futures_tickers(raw_data: dict) -> list[str]:
|
|
39
|
+
"""Преобразует данные Hyperliquid в список фьючерсных тикеров.
|
|
40
|
+
|
|
41
|
+
Параметры:
|
|
42
|
+
raw_data (dict): Сырой ответ с биржи.
|
|
43
|
+
|
|
44
|
+
Возвращает:
|
|
45
|
+
list[str]: Список тикеров (например, "@123").
|
|
46
|
+
"""
|
|
47
|
+
return [item["name"] for item in raw_data["universe"]]
|
|
48
|
+
|
|
49
|
+
@staticmethod
|
|
50
|
+
def last_price(raw_data: dict, resolve_symbols: bool) -> dict[str, float]:
|
|
51
|
+
"""Преобразует данные о последних ценах (spot) в унифицированный формат.
|
|
52
|
+
|
|
53
|
+
Параметры:
|
|
54
|
+
raw_data (dict): Сырой ответ с биржи.
|
|
55
|
+
resolve_symbols (bool): Если True, тикеры маппятся из вида "@123" в "BTC".
|
|
56
|
+
|
|
57
|
+
Возвращает:
|
|
58
|
+
dict[str, float]: Словарь тикеров и последних цен.
|
|
59
|
+
"""
|
|
60
|
+
if resolve_symbols:
|
|
61
|
+
return {
|
|
62
|
+
ExchangeInfo.resolve_spot_symbol(token): float(price)
|
|
63
|
+
for token, price in raw_data.items()
|
|
64
|
+
if token.startswith("@")
|
|
65
|
+
}
|
|
66
|
+
else:
|
|
67
|
+
return {
|
|
68
|
+
token: float(price) for token, price in raw_data.items() if token.startswith("@")
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@staticmethod
|
|
72
|
+
def futures_last_price(raw_data: dict) -> dict[str, float]:
|
|
73
|
+
"""Преобразует данные о последних ценах (futures) в унифицированный формат.
|
|
74
|
+
|
|
75
|
+
Параметры:
|
|
76
|
+
raw_data (dict): Сырой ответ с биржи.
|
|
77
|
+
|
|
78
|
+
Возвращает:
|
|
79
|
+
dict[str, float]: Словарь тикеров и последних цен.
|
|
80
|
+
"""
|
|
81
|
+
return {k: float(v) for k, v in raw_data.items() if not k.startswith("@")}
|
|
82
|
+
|
|
83
|
+
@staticmethod
|
|
84
|
+
def ticker_24hr(raw_data: list, resolve_symbols: bool) -> TickerDailyDict:
|
|
85
|
+
"""Преобразует 24-часовую статистику (spot) в унифицированный формат.
|
|
86
|
+
|
|
87
|
+
Параметры:
|
|
88
|
+
raw_data (list): Сырой ответ с биржи.
|
|
89
|
+
resolve_symbols (bool): Если True, тикеры маппятся из вида "@123" в "BTC".
|
|
90
|
+
|
|
91
|
+
Возвращает:
|
|
92
|
+
TickerDailyDict: Словарь тикеров и их статистики.
|
|
93
|
+
"""
|
|
94
|
+
metrics = raw_data[1]
|
|
95
|
+
result: TickerDailyDict = {}
|
|
96
|
+
|
|
97
|
+
for item in metrics:
|
|
98
|
+
try:
|
|
99
|
+
coin = item["coin"]
|
|
100
|
+
|
|
101
|
+
if resolve_symbols:
|
|
102
|
+
coin = ExchangeInfo.resolve_spot_symbol(coin) or coin
|
|
103
|
+
|
|
104
|
+
prev_day_px = float(item.get("prevDayPx") or "0")
|
|
105
|
+
mid_px = float(item.get("midPx") or "0")
|
|
106
|
+
mark_px = float(item.get("markPx") or "0")
|
|
107
|
+
day_ntl_vlm = float(item.get("dayNtlVlm") or "0")
|
|
108
|
+
|
|
109
|
+
p = round(((mark_px - prev_day_px) / prev_day_px * 100), 2) if prev_day_px else 0.0
|
|
110
|
+
v = (day_ntl_vlm / mid_px) if mid_px else 0.0
|
|
111
|
+
q = day_ntl_vlm
|
|
112
|
+
|
|
113
|
+
if coin in result:
|
|
114
|
+
# В случае с конфликтом оставляем ту монету, в которой больше дневного объема, т.к
|
|
115
|
+
# для 6 монет (на 07.10.2025) встречаются пары к USDH, которые повторяют идентификатор.
|
|
116
|
+
# Проблема не критичная - т.к. флаг resolve_symbols по идее использовать должен редко.
|
|
117
|
+
prev_ticker_daily = result[coin]
|
|
118
|
+
curr_ticker_daily = TickerDailyItem(p=p, v=v, q=q)
|
|
119
|
+
if prev_ticker_daily["q"] > curr_ticker_daily["q"]:
|
|
120
|
+
result[coin] = prev_ticker_daily
|
|
121
|
+
else:
|
|
122
|
+
result[coin] = curr_ticker_daily
|
|
123
|
+
else:
|
|
124
|
+
result[coin] = TickerDailyItem(p=p, v=v, q=q)
|
|
125
|
+
|
|
126
|
+
except (KeyError, TypeError, ValueError):
|
|
127
|
+
continue
|
|
128
|
+
|
|
129
|
+
return result
|
|
130
|
+
|
|
131
|
+
@staticmethod
|
|
132
|
+
def futures_ticker_24hr(raw_data: list) -> TickerDailyDict:
|
|
133
|
+
"""Преобразует 24-часовую статистику (futures) в унифицированный формат.
|
|
134
|
+
|
|
135
|
+
Параметры:
|
|
136
|
+
raw_data (list): Сырой ответ с биржи.
|
|
137
|
+
|
|
138
|
+
Возвращает:
|
|
139
|
+
TickerDailyDict: Словарь тикеров и их статистики.
|
|
140
|
+
"""
|
|
141
|
+
universe = raw_data[0]["universe"]
|
|
142
|
+
metrics = raw_data[1]
|
|
143
|
+
|
|
144
|
+
result: TickerDailyDict = {}
|
|
145
|
+
|
|
146
|
+
for i, item in enumerate(metrics):
|
|
147
|
+
try:
|
|
148
|
+
prev_day_px = float(item.get("prevDayPx", 0) or "0")
|
|
149
|
+
oracle_px = float(item.get("oraclePx", 0) or "0")
|
|
150
|
+
mark_px = float(item.get("markPx", 0) or "0")
|
|
151
|
+
day_ntl_vlm = float(item.get("dayNtlVlm", 0) or "0")
|
|
152
|
+
|
|
153
|
+
p = ((mark_px - prev_day_px) / prev_day_px * 100) if prev_day_px else 0.0
|
|
154
|
+
v = (day_ntl_vlm / oracle_px) if oracle_px else 0.0
|
|
155
|
+
q = day_ntl_vlm
|
|
156
|
+
|
|
157
|
+
result[universe[i]["name"]] = TickerDailyItem(p=p, v=v, q=q)
|
|
158
|
+
except (KeyError, TypeError, ValueError):
|
|
159
|
+
continue
|
|
160
|
+
|
|
161
|
+
return result
|
|
162
|
+
|
|
163
|
+
@staticmethod
|
|
164
|
+
def klines(raw_data: list[dict], resolve_symbols: bool) -> list[KlineDict]:
|
|
165
|
+
"""Преобразует сырой ответ, в котором содержатся данные о свечах, в унифицированный формат.
|
|
166
|
+
|
|
167
|
+
Параметры:
|
|
168
|
+
raw_data (list[dict]): Сырой ответ с биржи.
|
|
169
|
+
resolve_symbols (bool): Если True, тикер маппится из вида "@123" в "BTC".
|
|
170
|
+
|
|
171
|
+
Возвращает:
|
|
172
|
+
list[KlineDict]: Список словарей, где каждый словарь содержит данные о свече.
|
|
173
|
+
"""
|
|
174
|
+
return [
|
|
175
|
+
KlineDict(
|
|
176
|
+
s=kline["s"]
|
|
177
|
+
if not resolve_symbols
|
|
178
|
+
else ExchangeInfo.resolve_spot_symbol(kline["s"]),
|
|
179
|
+
t=kline["t"],
|
|
180
|
+
o=float(kline["o"]),
|
|
181
|
+
h=float(kline["h"]),
|
|
182
|
+
l=float(kline["l"]),
|
|
183
|
+
c=float(kline["c"]),
|
|
184
|
+
v=float(kline["v"]),
|
|
185
|
+
q=float(kline["v"]) * float(kline["c"]),
|
|
186
|
+
T=kline["T"],
|
|
187
|
+
x=None,
|
|
188
|
+
)
|
|
189
|
+
for kline in sorted(
|
|
190
|
+
raw_data,
|
|
191
|
+
key=lambda x: int(x["t"]),
|
|
192
|
+
)
|
|
193
|
+
]
|
|
194
|
+
|
|
195
|
+
@staticmethod
|
|
196
|
+
def futures_klines(raw_data: list[dict]) -> list[KlineDict]:
|
|
197
|
+
"""Преобразует сырой ответ, в котором содержатся данные о свечах, в унифицированный формат.
|
|
198
|
+
|
|
199
|
+
Параметры:
|
|
200
|
+
raw_data (list[dict]): Сырой ответ с биржи.
|
|
201
|
+
symbol (str): Символ тикера.
|
|
202
|
+
|
|
203
|
+
Возвращает:
|
|
204
|
+
list[KlineDict]: Список словарей, где каждый словарь содержит данные о свече.
|
|
205
|
+
"""
|
|
206
|
+
return [
|
|
207
|
+
KlineDict(
|
|
208
|
+
s=kline["s"],
|
|
209
|
+
t=kline["t"],
|
|
210
|
+
o=float(kline["o"]),
|
|
211
|
+
h=float(kline["h"]),
|
|
212
|
+
l=float(kline["l"]),
|
|
213
|
+
c=float(kline["c"]),
|
|
214
|
+
v=float(kline["v"]),
|
|
215
|
+
q=float(kline["v"]) * float(kline["c"]),
|
|
216
|
+
T=kline["T"],
|
|
217
|
+
x=None,
|
|
218
|
+
)
|
|
219
|
+
for kline in sorted(
|
|
220
|
+
raw_data,
|
|
221
|
+
key=lambda x: int(x["t"]),
|
|
222
|
+
)
|
|
223
|
+
]
|
|
224
|
+
|
|
225
|
+
@staticmethod
|
|
226
|
+
def funding_rate(raw_data: list) -> dict[str, float]:
|
|
227
|
+
"""Преобразует данные о ставках финансирования в унифицированный формат.
|
|
228
|
+
|
|
229
|
+
Параметры:
|
|
230
|
+
raw_data (list): Сырой ответ с биржи.
|
|
231
|
+
|
|
232
|
+
Возвращает:
|
|
233
|
+
dict[str, float]: Словарь тикеров и ставок финансирования (в %).
|
|
234
|
+
"""
|
|
235
|
+
universe = raw_data[0]["universe"]
|
|
236
|
+
metrics = raw_data[1]
|
|
237
|
+
return {
|
|
238
|
+
universe[i]["name"]: float(item["funding"]) * 100
|
|
239
|
+
for i, item in enumerate(metrics)
|
|
240
|
+
if item.get("funding") is not None
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
@staticmethod
|
|
244
|
+
def open_interest(raw_data: list) -> OpenInterestDict:
|
|
245
|
+
"""Преобразует данные об открытом интересе в унифицированный формат.
|
|
246
|
+
|
|
247
|
+
Параметры:
|
|
248
|
+
raw_data (list): Сырой ответ с биржи.
|
|
249
|
+
|
|
250
|
+
Возвращает:
|
|
251
|
+
OpenInterestDict: Словарь тикеров и значений открытого интереса.
|
|
252
|
+
"""
|
|
253
|
+
universe = raw_data[0]["universe"]
|
|
254
|
+
metrics = raw_data[1]
|
|
255
|
+
return {
|
|
256
|
+
universe[i]["name"]: OpenInterestItem(
|
|
257
|
+
t=int(time.time() * 1000),
|
|
258
|
+
v=float(item["openInterest"]),
|
|
259
|
+
)
|
|
260
|
+
for i, item in enumerate(metrics)
|
|
261
|
+
}
|