unicex 0.7.0__py3-none-any.whl → 0.8.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.
- unicex/binance/adapter.py +1 -1
- unicex/bybit/adapter.py +1 -1
- unicex/bybit/uni_client.py +2 -2
- unicex/extra.py +84 -6
- unicex/gateio/adapter.py +2 -2
- unicex/hyperliquid/adapter.py +12 -1
- unicex/mexc/adapter.py +2 -2
- unicex/okx/adapter.py +2 -2
- unicex/okx/client.py +2599 -26
- unicex/okx/uni_client.py +8 -8
- {unicex-0.7.0.dist-info → unicex-0.8.0.dist-info}/METADATA +2 -2
- {unicex-0.7.0.dist-info → unicex-0.8.0.dist-info}/RECORD +15 -15
- {unicex-0.7.0.dist-info → unicex-0.8.0.dist-info}/WHEEL +0 -0
- {unicex-0.7.0.dist-info → unicex-0.8.0.dist-info}/licenses/LICENSE +0 -0
- {unicex-0.7.0.dist-info → unicex-0.8.0.dist-info}/top_level.txt +0 -0
unicex/binance/adapter.py
CHANGED
|
@@ -17,7 +17,7 @@ class Adapter:
|
|
|
17
17
|
"""Адаптер для унификации данных с Binance API."""
|
|
18
18
|
|
|
19
19
|
@staticmethod
|
|
20
|
-
def tickers(raw_data: list[dict], only_usdt: bool
|
|
20
|
+
def tickers(raw_data: list[dict], only_usdt: bool) -> list[str]:
|
|
21
21
|
"""Преобразует сырой ответ, в котором содержатся данные о тикерах в список тикеров.
|
|
22
22
|
|
|
23
23
|
Параметры:
|
unicex/bybit/adapter.py
CHANGED
|
@@ -16,7 +16,7 @@ class Adapter:
|
|
|
16
16
|
"""Адаптер для унификации данных с Bybit API."""
|
|
17
17
|
|
|
18
18
|
@staticmethod
|
|
19
|
-
def tickers(raw_data: dict, only_usdt: bool
|
|
19
|
+
def tickers(raw_data: dict, only_usdt: bool) -> list[str]:
|
|
20
20
|
"""Преобразует сырой ответ, в котором содержатся данные о тикерах в список тикеров.
|
|
21
21
|
|
|
22
22
|
Параметры:
|
unicex/bybit/uni_client.py
CHANGED
|
@@ -33,7 +33,7 @@ class UniClient(IUniClient[Client]):
|
|
|
33
33
|
list[str]: Список тикеров.
|
|
34
34
|
"""
|
|
35
35
|
raw_data = await self._client.tickers("spot")
|
|
36
|
-
return Adapter.tickers(raw_data)
|
|
36
|
+
return Adapter.tickers(raw_data, only_usdt)
|
|
37
37
|
|
|
38
38
|
async def futures_tickers(self, only_usdt: bool = True) -> list[str]:
|
|
39
39
|
"""Возвращает список тикеров.
|
|
@@ -45,7 +45,7 @@ class UniClient(IUniClient[Client]):
|
|
|
45
45
|
list[str]: Список тикеров.
|
|
46
46
|
"""
|
|
47
47
|
raw_data = await self._client.tickers("linear")
|
|
48
|
-
return Adapter.tickers(raw_data)
|
|
48
|
+
return Adapter.tickers(raw_data, only_usdt)
|
|
49
49
|
|
|
50
50
|
async def last_price(self) -> dict[str, float]:
|
|
51
51
|
"""Возвращает последнюю цену для каждого тикера.
|
unicex/extra.py
CHANGED
|
@@ -8,6 +8,8 @@ __all__ = [
|
|
|
8
8
|
"generate_tv_link",
|
|
9
9
|
"generate_cg_link",
|
|
10
10
|
"make_humanreadable",
|
|
11
|
+
"normalize_ticker",
|
|
12
|
+
"normalize_symbol",
|
|
11
13
|
]
|
|
12
14
|
|
|
13
15
|
import time
|
|
@@ -32,7 +34,7 @@ def percent_greater(higher: float, lower: float) -> float:
|
|
|
32
34
|
`float`: На сколько процентов `higher` больше `lower`.
|
|
33
35
|
"""
|
|
34
36
|
if lower == 0:
|
|
35
|
-
return float(
|
|
37
|
+
return 0.0 # Не будем возвращать float('inf'), чтобы не ломать логику приложения
|
|
36
38
|
return (higher / lower - 1) * 100
|
|
37
39
|
|
|
38
40
|
|
|
@@ -51,7 +53,7 @@ def percent_less(higher: float, lower: float) -> float:
|
|
|
51
53
|
`float`: На сколько процентов `lower` меньше `higher`.
|
|
52
54
|
"""
|
|
53
55
|
if lower == 0:
|
|
54
|
-
return float(
|
|
56
|
+
return 0.0 # Не будем возвращать float('inf'), чтобы не ломать логику приложения
|
|
55
57
|
return (1 - lower / higher) * 100
|
|
56
58
|
|
|
57
59
|
|
|
@@ -91,6 +93,76 @@ class TimeoutTracker[T]:
|
|
|
91
93
|
self._blocked_items[item] = time.time() + duration
|
|
92
94
|
|
|
93
95
|
|
|
96
|
+
def normalize_ticker(raw_ticker: str) -> str:
|
|
97
|
+
"""Нормализует тикер и возвращает базовую валюту (например, `BTC`).
|
|
98
|
+
|
|
99
|
+
Эта функция принимает тикер в различных форматах (с разделителями, постфиксом SWAP,
|
|
100
|
+
в верхнем или нижнем регистре) и приводит его к стандартному виду — только базовый актив.
|
|
101
|
+
|
|
102
|
+
Примеры:
|
|
103
|
+
```python
|
|
104
|
+
normalize_ticker("BTC-USDT") # "BTC"
|
|
105
|
+
normalize_ticker("BTC-USDT-SWAP") # "BTC"
|
|
106
|
+
normalize_ticker("btc_usdt") # "BTC"
|
|
107
|
+
normalize_ticker("BTCUSDT") # "BTC"
|
|
108
|
+
normalize_ticker("BTC") # "BTC"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Параметры:
|
|
112
|
+
raw_ticker (`str`): Исходный тикер в любом из распространённых форматов.
|
|
113
|
+
|
|
114
|
+
Возвращает:
|
|
115
|
+
`str`: Базовый актив в верхнем регистре (например, `"BTC"`).
|
|
116
|
+
"""
|
|
117
|
+
ticker = raw_ticker.upper()
|
|
118
|
+
|
|
119
|
+
# Удаляем постфиксы SWAP
|
|
120
|
+
if ticker.endswith(("SWAP", "-SWAP", "_SWAP", ".SWAP")):
|
|
121
|
+
ticker = (
|
|
122
|
+
ticker.removesuffix("-SWAP")
|
|
123
|
+
.removesuffix("_SWAP")
|
|
124
|
+
.removesuffix(".SWAP")
|
|
125
|
+
.removesuffix("SWAP")
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# Удаляем разделители
|
|
129
|
+
ticker = ticker.translate(str.maketrans("", "", "-_."))
|
|
130
|
+
|
|
131
|
+
# Убираем суффикс валюты котировки
|
|
132
|
+
for quote in ("USDT", "USDC"):
|
|
133
|
+
if ticker.endswith(quote):
|
|
134
|
+
ticker = ticker.removesuffix(quote)
|
|
135
|
+
break
|
|
136
|
+
|
|
137
|
+
return ticker
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def normalize_symbol(raw_ticker: str, quote: Literal["USDT", "USDC"] = "USDT") -> str:
|
|
141
|
+
"""Нормализует тикер до унифицированного символа (например, `BTCUSDT`).
|
|
142
|
+
|
|
143
|
+
Функция принимает тикер в любом из популярных форматов и возвращает полный символ,
|
|
144
|
+
состоящий из базовой валюты и указанной валюты котировки (`USDT` или `USDC`).
|
|
145
|
+
|
|
146
|
+
Примеры:
|
|
147
|
+
```python
|
|
148
|
+
normalize_symbol("BTC-USDT") # "BTCUSDT"
|
|
149
|
+
normalize_symbol("BTC") # "BTCUSDT"
|
|
150
|
+
normalize_symbol("btc_usdt_swap") # "BTCUSDT"
|
|
151
|
+
normalize_symbol("ETH", "USDC") # "ETHUSDC"
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Параметры:
|
|
155
|
+
raw_ticker (`str`): Исходный тикер в любом из распространённых форматов.
|
|
156
|
+
quote (`Literal["USDT", "USDC"]`, optional): Валюта котировки.
|
|
157
|
+
По умолчанию `"USDT"`.
|
|
158
|
+
|
|
159
|
+
Возвращает:
|
|
160
|
+
`str`: Символ в унифицированном формате, например `"BTCUSDT"`.
|
|
161
|
+
"""
|
|
162
|
+
base = normalize_ticker(raw_ticker)
|
|
163
|
+
return f"{base}{quote}"
|
|
164
|
+
|
|
165
|
+
|
|
94
166
|
def generate_ex_link(exchange: Exchange, market_type: MarketType, symbol: str):
|
|
95
167
|
"""Генерирует ссылку на биржу.
|
|
96
168
|
|
|
@@ -102,7 +174,8 @@ def generate_ex_link(exchange: Exchange, market_type: MarketType, symbol: str):
|
|
|
102
174
|
Возвращает:
|
|
103
175
|
`str`: Ссылка на биржу.
|
|
104
176
|
"""
|
|
105
|
-
|
|
177
|
+
symbol = normalize_symbol(symbol)
|
|
178
|
+
ticker = normalize_ticker(symbol)
|
|
106
179
|
if exchange == Exchange.BINANCE:
|
|
107
180
|
if market_type == MarketType.FUTURES:
|
|
108
181
|
return f"https://www.binance.com/en/futures/{symbol}"
|
|
@@ -152,7 +225,7 @@ def generate_ex_link(exchange: Exchange, market_type: MarketType, symbol: str):
|
|
|
152
225
|
if market_type == MarketType.FUTURES:
|
|
153
226
|
return f"https://app.hyperliquid.xyz/trade/{ticker}"
|
|
154
227
|
else:
|
|
155
|
-
return f"https://
|
|
228
|
+
return f"https://app.hyperliquid.xyz/trade/{ticker}/USDC"
|
|
156
229
|
else:
|
|
157
230
|
raise NotSupported(f"Exchange {exchange} is not supported")
|
|
158
231
|
|
|
@@ -168,6 +241,7 @@ def generate_tv_link(exchange: Exchange, market_type: MarketType, symbol: str) -
|
|
|
168
241
|
Возвращает:
|
|
169
242
|
`str`: Ссылка для TradingView.
|
|
170
243
|
"""
|
|
244
|
+
symbol = normalize_symbol(symbol)
|
|
171
245
|
if market_type == MarketType.FUTURES:
|
|
172
246
|
return f"https://www.tradingview.com/chart/?symbol={exchange}:{symbol}.P"
|
|
173
247
|
else:
|
|
@@ -187,6 +261,8 @@ def generate_cg_link(exchange: Exchange, market_type: MarketType, symbol: str) -
|
|
|
187
261
|
"""
|
|
188
262
|
base_url = "https://www.coinglass.com/tv/ru"
|
|
189
263
|
|
|
264
|
+
symbol = normalize_symbol(symbol)
|
|
265
|
+
|
|
190
266
|
if market_type == MarketType.FUTURES:
|
|
191
267
|
match exchange:
|
|
192
268
|
case Exchange.OKX:
|
|
@@ -196,9 +272,11 @@ def generate_cg_link(exchange: Exchange, market_type: MarketType, symbol: str) -
|
|
|
196
272
|
case Exchange.BITGET:
|
|
197
273
|
return f"{base_url}/{exchange.capitalize()}_{symbol}_UMCBL"
|
|
198
274
|
case Exchange.GATEIO:
|
|
199
|
-
return f"{base_url}/{
|
|
275
|
+
return f"{base_url}/Gate_{symbol.replace('USDT', '_USDT')}"
|
|
200
276
|
case Exchange.BITUNIX:
|
|
201
277
|
return f"{base_url}/{exchange.capitalize()}_{symbol}"
|
|
278
|
+
case Exchange.HYPERLIQUID:
|
|
279
|
+
return f"{base_url}/{exchange.capitalize()}_{symbol.replace('USDT', '-USD')}"
|
|
202
280
|
case _:
|
|
203
281
|
return f"{base_url}/{exchange.capitalize()}_{symbol}"
|
|
204
282
|
else:
|
|
@@ -206,7 +284,7 @@ def generate_cg_link(exchange: Exchange, market_type: MarketType, symbol: str) -
|
|
|
206
284
|
if exchange == Exchange.OKX:
|
|
207
285
|
return f"{base_url}/SPOT_{exchange.upper()}_{symbol.replace('USDT', '-USDT')}"
|
|
208
286
|
# Для остальных бирж ссылки нет → возвращаем заглушку
|
|
209
|
-
return
|
|
287
|
+
return generate_cg_link(exchange, MarketType.FUTURES, symbol)
|
|
210
288
|
|
|
211
289
|
|
|
212
290
|
def make_humanreadable(value: float, locale: Literal["ru", "en"] = "ru") -> str:
|
unicex/gateio/adapter.py
CHANGED
|
@@ -19,7 +19,7 @@ class Adapter:
|
|
|
19
19
|
"""Адаптер для унификации данных с Gateio API."""
|
|
20
20
|
|
|
21
21
|
@staticmethod
|
|
22
|
-
def tickers(raw_data: list[dict], only_usdt: bool
|
|
22
|
+
def tickers(raw_data: list[dict], only_usdt: bool) -> list[str]:
|
|
23
23
|
"""Преобразует сырой ответ о тикерах в список символов.
|
|
24
24
|
|
|
25
25
|
Параметры:
|
|
@@ -36,7 +36,7 @@ class Adapter:
|
|
|
36
36
|
]
|
|
37
37
|
|
|
38
38
|
@staticmethod
|
|
39
|
-
def futures_tickers(raw_data: list[dict], only_usdt: bool
|
|
39
|
+
def futures_tickers(raw_data: list[dict], only_usdt: bool) -> list[str]:
|
|
40
40
|
"""Преобразует сырой ответ о фьючерсных тикерах в список символов.
|
|
41
41
|
|
|
42
42
|
Параметры:
|
unicex/hyperliquid/adapter.py
CHANGED
|
@@ -110,7 +110,18 @@ class Adapter:
|
|
|
110
110
|
v = (day_ntl_vlm / mid_px) if mid_px else 0.0
|
|
111
111
|
q = day_ntl_vlm
|
|
112
112
|
|
|
113
|
-
|
|
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)
|
|
114
125
|
|
|
115
126
|
except (KeyError, TypeError, ValueError):
|
|
116
127
|
continue
|
unicex/mexc/adapter.py
CHANGED
|
@@ -17,7 +17,7 @@ class Adapter:
|
|
|
17
17
|
"""Адаптер для унификации данных с Mexc API."""
|
|
18
18
|
|
|
19
19
|
@staticmethod
|
|
20
|
-
def tickers(raw_data: list[dict], only_usdt: bool
|
|
20
|
+
def tickers(raw_data: list[dict], only_usdt: bool) -> list[str]:
|
|
21
21
|
"""Преобразует сырой ответ, в котором содержатся данные о тикерах, в список тикеров.
|
|
22
22
|
|
|
23
23
|
Параметры:
|
|
@@ -32,7 +32,7 @@ class Adapter:
|
|
|
32
32
|
]
|
|
33
33
|
|
|
34
34
|
@staticmethod
|
|
35
|
-
def futures_tickers(raw_data: dict, only_usdt: bool
|
|
35
|
+
def futures_tickers(raw_data: dict, only_usdt: bool) -> list[str]:
|
|
36
36
|
"""Преобразует сырой ответ, в котором содержатся данные о фьючерсных тикерах, в список тикеров.
|
|
37
37
|
|
|
38
38
|
Параметры:
|
unicex/okx/adapter.py
CHANGED
|
@@ -18,7 +18,7 @@ class Adapter:
|
|
|
18
18
|
"""Адаптер для унификации данных с Okx API."""
|
|
19
19
|
|
|
20
20
|
@staticmethod
|
|
21
|
-
def tickers(raw_data: dict, only_usdt: bool
|
|
21
|
+
def tickers(raw_data: dict, only_usdt: bool) -> list[str]:
|
|
22
22
|
"""Преобразует сырые данные о тикерах в список унифицированных символов.
|
|
23
23
|
|
|
24
24
|
Параметры:
|
|
@@ -35,7 +35,7 @@ class Adapter:
|
|
|
35
35
|
]
|
|
36
36
|
|
|
37
37
|
@staticmethod
|
|
38
|
-
def futures_tickers(raw_data: dict, only_usdt: bool
|
|
38
|
+
def futures_tickers(raw_data: dict, only_usdt: bool) -> list[str]:
|
|
39
39
|
"""Преобразует сырые данные о тикерах в список унифицированных символов.
|
|
40
40
|
|
|
41
41
|
Параметры:
|