unicex 0.13.17__py3-none-any.whl → 0.16.5__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 +36 -2
- unicex/_abc/exchange_info.py +1 -1
- unicex/_abc/uni_client.py +31 -1
- unicex/_abc/uni_websocket_manager.py +1 -1
- unicex/_base/client.py +7 -0
- unicex/_base/websocket.py +31 -9
- unicex/binance/adapter.py +7 -16
- unicex/binance/client.py +25 -25
- unicex/binance/uni_websocket_manager.py +6 -2
- unicex/bingx/__init__.py +27 -0
- unicex/bingx/adapter.py +284 -0
- unicex/bingx/client.py +521 -0
- unicex/bingx/exchange_info.py +22 -0
- unicex/bingx/uni_client.py +191 -0
- unicex/bingx/uni_websocket_manager.py +283 -0
- unicex/bingx/user_websocket.py +7 -0
- unicex/bingx/websocket_manager.py +118 -0
- unicex/bitget/adapter.py +2 -2
- unicex/bitget/client.py +64 -64
- unicex/bitget/uni_websocket_manager.py +27 -6
- unicex/bitget/websocket_manager.py +2 -4
- unicex/bybit/adapter.py +1 -0
- unicex/bybit/client.py +4 -4
- unicex/bybit/exchange_info.py +1 -1
- unicex/bybit/uni_websocket_manager.py +33 -4
- unicex/bybit/websocket_manager.py +8 -24
- unicex/enums.py +19 -3
- unicex/extra.py +37 -35
- unicex/gate/adapter.py +113 -0
- unicex/gate/client.py +9 -9
- unicex/gate/uni_client.py +1 -3
- unicex/gate/uni_websocket_manager.py +47 -9
- unicex/hyperliquid/adapter.py +1 -0
- unicex/hyperliquid/client.py +12 -12
- unicex/hyperliquid/uni_client.py +4 -7
- unicex/hyperliquid/uni_websocket_manager.py +6 -2
- unicex/kucoin/__init__.py +27 -0
- unicex/kucoin/adapter.py +181 -0
- unicex/kucoin/client.py +135 -0
- unicex/kucoin/exchange_info.py +50 -0
- unicex/kucoin/uni_client.py +208 -0
- unicex/kucoin/uni_websocket_manager.py +273 -0
- unicex/kucoin/user_websocket.py +7 -0
- unicex/kucoin/websocket_manager.py +11 -0
- unicex/mapper.py +62 -21
- unicex/mexc/adapter.py +104 -0
- unicex/mexc/client.py +7 -7
- unicex/mexc/uni_client.py +1 -3
- unicex/mexc/uni_websocket_manager.py +31 -9
- unicex/mexc/websocket_manager.py +27 -6
- unicex/okx/adapter.py +51 -0
- unicex/okx/client.py +15 -15
- unicex/okx/exchange_info.py +2 -2
- unicex/okx/uni_websocket_manager.py +50 -9
- unicex/okx/websocket_manager.py +119 -166
- unicex/types.py +14 -10
- unicex/utils.py +44 -1
- {unicex-0.13.17.dist-info → unicex-0.16.5.dist-info}/METADATA +7 -5
- unicex-0.16.5.dist-info/RECORD +109 -0
- unicex-0.13.17.dist-info/RECORD +0 -93
- {unicex-0.13.17.dist-info → unicex-0.16.5.dist-info}/WHEEL +0 -0
- {unicex-0.13.17.dist-info → unicex-0.16.5.dist-info}/licenses/LICENSE +0 -0
- {unicex-0.13.17.dist-info → unicex-0.16.5.dist-info}/top_level.txt +0 -0
unicex/kucoin/adapter.py
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
__all__ = ["Adapter"]
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from unicex.types import (
|
|
6
|
+
KlineDict,
|
|
7
|
+
OpenInterestDict,
|
|
8
|
+
OpenInterestItem,
|
|
9
|
+
TickerDailyDict,
|
|
10
|
+
TickerDailyItem,
|
|
11
|
+
)
|
|
12
|
+
from unicex.utils import catch_adapter_errors, decorate_all_methods
|
|
13
|
+
|
|
14
|
+
from .exchange_info import ExchangeInfo
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@decorate_all_methods(catch_adapter_errors)
|
|
18
|
+
class Adapter:
|
|
19
|
+
"""Адаптер для унификации данных с Kucoin API."""
|
|
20
|
+
|
|
21
|
+
@staticmethod
|
|
22
|
+
def tickers(raw_data: dict, only_usdt: bool) -> list[str]:
|
|
23
|
+
"""Преобразует сырой ответ, в котором содержатся данные о тикерах в список тикеров.
|
|
24
|
+
|
|
25
|
+
Параметры:
|
|
26
|
+
raw_data (dict): Сырой ответ с биржи.
|
|
27
|
+
only_usdt (bool): Флаг, указывающий, нужно ли включать только тикеры в паре к USDT.
|
|
28
|
+
|
|
29
|
+
Возвращает:
|
|
30
|
+
list[str]: Список тикеров.
|
|
31
|
+
"""
|
|
32
|
+
return [
|
|
33
|
+
item["symbol"]
|
|
34
|
+
for item in raw_data["data"]["list"]
|
|
35
|
+
if item["symbol"].endswith("USDT") or not only_usdt
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
@staticmethod
|
|
39
|
+
def futures_tickers(raw_data: dict, only_usdt: bool) -> list[str]:
|
|
40
|
+
"""Преобразует сырой ответ, в котором содержатся данные о тикерах в список тикеров.
|
|
41
|
+
|
|
42
|
+
Параметры:
|
|
43
|
+
raw_data (dict): Сырой ответ с биржи.
|
|
44
|
+
only_usdt (bool): Флаг, указывающий, нужно ли включать только тикеры в паре к USDT.
|
|
45
|
+
|
|
46
|
+
Возвращает:
|
|
47
|
+
list[str]: Список тикеров.
|
|
48
|
+
"""
|
|
49
|
+
return [
|
|
50
|
+
item["symbol"]
|
|
51
|
+
for item in raw_data["data"]["list"]
|
|
52
|
+
if item["symbol"].endswith("USDTM") or not only_usdt
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
@staticmethod
|
|
56
|
+
def ticker_24hr(raw_data: dict) -> TickerDailyDict:
|
|
57
|
+
"""Преобразует сырой ответ, в котором содержатся данные о тикере за последние 24 часа в унифицированный формат.
|
|
58
|
+
|
|
59
|
+
Параметры:
|
|
60
|
+
raw_data (dict): Сырой ответ с биржи.
|
|
61
|
+
|
|
62
|
+
Возвращает:
|
|
63
|
+
TickerDailyDict: Словарь, где ключ - тикер, а значение - статистика за последние 24 часа.
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
def safe_float(value: object, default: float = 0.0) -> float:
|
|
67
|
+
try:
|
|
68
|
+
if value is None:
|
|
69
|
+
return default
|
|
70
|
+
return float(value) # type: ignore
|
|
71
|
+
except (TypeError, ValueError):
|
|
72
|
+
return default
|
|
73
|
+
|
|
74
|
+
result: dict[str, TickerDailyItem] = {}
|
|
75
|
+
|
|
76
|
+
for item in raw_data["data"]["list"]:
|
|
77
|
+
symbol = item.get("symbol")
|
|
78
|
+
if not symbol:
|
|
79
|
+
continue
|
|
80
|
+
|
|
81
|
+
last_price = safe_float(item.get("lastPrice"))
|
|
82
|
+
open_price = safe_float(item.get("open"))
|
|
83
|
+
base_volume = safe_float(item.get("baseVolume"))
|
|
84
|
+
quote_volume = safe_float(item.get("quoteVolume"))
|
|
85
|
+
|
|
86
|
+
if open_price > 0:
|
|
87
|
+
p = round((last_price / open_price - 1) * 100, 2)
|
|
88
|
+
else:
|
|
89
|
+
p = 0.0
|
|
90
|
+
|
|
91
|
+
result[symbol] = TickerDailyItem(
|
|
92
|
+
p=p,
|
|
93
|
+
v=base_volume,
|
|
94
|
+
q=quote_volume,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
return result
|
|
98
|
+
|
|
99
|
+
@staticmethod
|
|
100
|
+
def last_price(raw_data: dict) -> dict[str, float]:
|
|
101
|
+
"""Преобразует сырой ответ, в котором содержатся данные о последней цене, в унифицированный формат.
|
|
102
|
+
|
|
103
|
+
Параметры:
|
|
104
|
+
raw_data (dict): Сырой ответ с биржи.
|
|
105
|
+
|
|
106
|
+
Возвращает:
|
|
107
|
+
dict[str, float]: Словарь, где ключ - тикер, а значение - последняя цена.
|
|
108
|
+
"""
|
|
109
|
+
return {
|
|
110
|
+
item["symbol"]: float(item["lastPrice"])
|
|
111
|
+
for item in raw_data["data"]["list"]
|
|
112
|
+
if item["lastPrice"]
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
@staticmethod
|
|
116
|
+
def open_interest(raw_data: dict[str, Any]) -> OpenInterestDict:
|
|
117
|
+
"""Преобразует сырой ответ, в котором содержатся данные об открытом интересе, в унифицированный формат.
|
|
118
|
+
|
|
119
|
+
Параметры:
|
|
120
|
+
raw_data (dict): Сырой ответ с биржи.
|
|
121
|
+
|
|
122
|
+
Возвращает:
|
|
123
|
+
OpenInterestDict: Словарь, где ключ - тикер, а значение - агрегированные данные открытого интереса.
|
|
124
|
+
"""
|
|
125
|
+
return {
|
|
126
|
+
item["symbol"]: OpenInterestItem(
|
|
127
|
+
t=item["ts"],
|
|
128
|
+
v=float(item["openInterest"]) * Adapter._get_contract_size(item["symbol"]),
|
|
129
|
+
u="coins",
|
|
130
|
+
)
|
|
131
|
+
for item in raw_data["data"]
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
@staticmethod
|
|
135
|
+
def funding_rate(raw_data: dict) -> float:
|
|
136
|
+
"""Преобразует историю ставок финансирования в унифицированный формат.
|
|
137
|
+
|
|
138
|
+
Параметры:
|
|
139
|
+
raw_data (dict): Сырой ответ с биржи.
|
|
140
|
+
|
|
141
|
+
Возвращает:
|
|
142
|
+
float: Актуальная ставка финансирования.
|
|
143
|
+
"""
|
|
144
|
+
return round(raw_data["data"]["nextFundingRate"] * 100, 6)
|
|
145
|
+
|
|
146
|
+
@staticmethod
|
|
147
|
+
def _get_contract_size(symbol: str) -> float:
|
|
148
|
+
"""Возвращает размер контракта для указанного символа тикера."""
|
|
149
|
+
try:
|
|
150
|
+
return ExchangeInfo.get_futures_ticker_info(symbol)["contract_size"] or 1
|
|
151
|
+
except: # noqa
|
|
152
|
+
return 1
|
|
153
|
+
|
|
154
|
+
@staticmethod
|
|
155
|
+
def klines(raw_data: dict, symbol: str) -> list[KlineDict]:
|
|
156
|
+
"""Преобразует данные о свечах в унифицированный формат.
|
|
157
|
+
|
|
158
|
+
Параметры:
|
|
159
|
+
raw_data (dict): Сырой ответ с биржи.
|
|
160
|
+
symbol (str): Символ тикера.
|
|
161
|
+
|
|
162
|
+
Возвращает:
|
|
163
|
+
list[KlineDict]: Список свечей.
|
|
164
|
+
"""
|
|
165
|
+
klines: list[KlineDict] = []
|
|
166
|
+
for item in sorted(raw_data["data"]["list"], key=lambda x: int(float(x[0]))):
|
|
167
|
+
klines.append( # noqa: PERF401
|
|
168
|
+
KlineDict(
|
|
169
|
+
s=symbol,
|
|
170
|
+
t=item[0],
|
|
171
|
+
o=float(item[1]),
|
|
172
|
+
h=float(item[3]),
|
|
173
|
+
l=float(item[4]),
|
|
174
|
+
c=float(item[2]),
|
|
175
|
+
v=float(item[5]),
|
|
176
|
+
q=float(item[6]),
|
|
177
|
+
T=None,
|
|
178
|
+
x=None,
|
|
179
|
+
)
|
|
180
|
+
)
|
|
181
|
+
return klines
|
unicex/kucoin/client.py
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
__all__ = ["Client"]
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
from typing import Any, Literal
|
|
5
|
+
|
|
6
|
+
from unicex._base import BaseClient
|
|
7
|
+
from unicex.types import RequestMethod
|
|
8
|
+
from unicex.utils import filter_params
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Client(BaseClient):
|
|
12
|
+
"""Клиент для работы с Kucoin API."""
|
|
13
|
+
|
|
14
|
+
_BASE_URL: str = "https://api.kucoin.com"
|
|
15
|
+
"""Базовый URL для запросов."""
|
|
16
|
+
|
|
17
|
+
async def _make_request(
|
|
18
|
+
self,
|
|
19
|
+
method: RequestMethod,
|
|
20
|
+
endpoint: str,
|
|
21
|
+
*,
|
|
22
|
+
params: dict[str, Any] | None = None,
|
|
23
|
+
) -> dict[str, Any]:
|
|
24
|
+
"""Выполняет HTTP-запрос к эндпоинтам Kucoin API.
|
|
25
|
+
|
|
26
|
+
Параметры:
|
|
27
|
+
method (str): HTTP метод запроса ("GET", "POST", "DELETE" и т.д.).
|
|
28
|
+
endpoint (str): URL эндпоинта Kucoin API.
|
|
29
|
+
params (dict | None): Параметры запроса.
|
|
30
|
+
|
|
31
|
+
Возвращает:
|
|
32
|
+
dict: Ответ в формате JSON.
|
|
33
|
+
"""
|
|
34
|
+
# Составляем URL для запроса
|
|
35
|
+
url = self._BASE_URL + endpoint
|
|
36
|
+
|
|
37
|
+
# Фильтруем параметры от None значений
|
|
38
|
+
params = filter_params(params) if params else {}
|
|
39
|
+
|
|
40
|
+
# Выполняем запрос
|
|
41
|
+
return await super()._make_request(
|
|
42
|
+
method=method,
|
|
43
|
+
url=url,
|
|
44
|
+
params=params,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
async def symbol(
|
|
48
|
+
self,
|
|
49
|
+
trade_type: Literal["SPOT", "FUTURES", "ISOLATED", "CROSS"],
|
|
50
|
+
symbol: str | None = None,
|
|
51
|
+
) -> dict[str, Any]:
|
|
52
|
+
"""Получение символов и информации о них.
|
|
53
|
+
|
|
54
|
+
https://www.kucoin.com/docs-new/rest/ua/get-symbol
|
|
55
|
+
"""
|
|
56
|
+
params = {"tradeType": trade_type, "symbol": symbol}
|
|
57
|
+
|
|
58
|
+
return await self._make_request("GET", "/api/ua/v1/market/instrument", params=params)
|
|
59
|
+
|
|
60
|
+
async def ticker(
|
|
61
|
+
self,
|
|
62
|
+
trade_type: Literal["SPOT", "FUTURES"],
|
|
63
|
+
symbol: str | None = None,
|
|
64
|
+
) -> dict[str, Any]:
|
|
65
|
+
"""Получение тикеров и информации о них.
|
|
66
|
+
|
|
67
|
+
https://www.kucoin.com/docs-new/rest/ua/get-ticker
|
|
68
|
+
"""
|
|
69
|
+
params = {"tradeType": trade_type, "symbol": symbol}
|
|
70
|
+
|
|
71
|
+
return await self._make_request("GET", "/api/ua/v1/market/ticker", params=params)
|
|
72
|
+
|
|
73
|
+
async def open_interest(self) -> dict[str, Any]:
|
|
74
|
+
"""Получение открытого интереса.
|
|
75
|
+
|
|
76
|
+
https://www.kucoin.com/docs-new/3476287e0
|
|
77
|
+
"""
|
|
78
|
+
return await self._make_request("GET", "/api/ua/v1/market/open-interest")
|
|
79
|
+
|
|
80
|
+
async def kline(
|
|
81
|
+
self,
|
|
82
|
+
trade_type: Literal["SPOT", "FUTURES"],
|
|
83
|
+
symbol: str,
|
|
84
|
+
interval: str,
|
|
85
|
+
start_at: int | None = None,
|
|
86
|
+
end_at: int | None = None,
|
|
87
|
+
) -> dict[str, Any]:
|
|
88
|
+
"""Получение списка свечей.
|
|
89
|
+
|
|
90
|
+
https://www.kucoin.com/docs-new/rest/ua/get-klines
|
|
91
|
+
"""
|
|
92
|
+
params = {
|
|
93
|
+
"tradeType": trade_type,
|
|
94
|
+
"symbol": symbol,
|
|
95
|
+
"interval": interval,
|
|
96
|
+
"startAt": start_at,
|
|
97
|
+
"endAt": end_at,
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return await self._make_request("GET", "/api/ua/v1/market/kline", params=params)
|
|
101
|
+
|
|
102
|
+
async def funding_rate_history(
|
|
103
|
+
self,
|
|
104
|
+
symbol: str,
|
|
105
|
+
start_at: int,
|
|
106
|
+
end_at: int,
|
|
107
|
+
) -> dict[str, Any]:
|
|
108
|
+
"""Получение истории ставок финансирования.
|
|
109
|
+
|
|
110
|
+
https://www.kucoin.com/docs-new/rest/ua/get-history-funding-rate
|
|
111
|
+
"""
|
|
112
|
+
params = {
|
|
113
|
+
"symbol": symbol,
|
|
114
|
+
"startAt": start_at,
|
|
115
|
+
"endAt": end_at,
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return await self._make_request(
|
|
119
|
+
"GET",
|
|
120
|
+
"/api/ua/v1/market/funding-rate-history",
|
|
121
|
+
params=params,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
async def funding_rate(self, symbol: str) -> dict[str, Any]:
|
|
125
|
+
"""Получение текущей ставки финансирования.
|
|
126
|
+
|
|
127
|
+
https://www.kucoin.com/docs-new/rest/ua/get-current-funding-rate
|
|
128
|
+
"""
|
|
129
|
+
params = {"symbol": symbol}
|
|
130
|
+
|
|
131
|
+
return await self._make_request(
|
|
132
|
+
"GET",
|
|
133
|
+
"/api/ua/v1/market/funding-rate",
|
|
134
|
+
params=params,
|
|
135
|
+
)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
__all__ = ["ExchangeInfo"]
|
|
2
|
+
|
|
3
|
+
import aiohttp
|
|
4
|
+
|
|
5
|
+
from unicex._abc import IExchangeInfo
|
|
6
|
+
from unicex.types import TickerInfoItem
|
|
7
|
+
|
|
8
|
+
from .client import Client
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ExchangeInfo(IExchangeInfo):
|
|
12
|
+
"""Предзагружает информацию о тикерах для биржи Kucoin."""
|
|
13
|
+
|
|
14
|
+
exchange_name = "Kucoin"
|
|
15
|
+
"""Название биржи, на которой работает класс."""
|
|
16
|
+
|
|
17
|
+
@classmethod
|
|
18
|
+
async def _load_spot_exchange_info(cls, session: aiohttp.ClientSession) -> None:
|
|
19
|
+
"""Загружает информацию о бирже для спотового рынка."""
|
|
20
|
+
tickers_info = {}
|
|
21
|
+
exchange_info = await Client(session).symbol("SPOT")
|
|
22
|
+
for el in exchange_info["data"]["list"]:
|
|
23
|
+
tickers_info[el["symbol"]] = TickerInfoItem(
|
|
24
|
+
tick_precision=None,
|
|
25
|
+
tick_step=float(el["tickSize"]),
|
|
26
|
+
size_precision=None,
|
|
27
|
+
size_step=float(el["baseOrderStep"]),
|
|
28
|
+
contract_size=1,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
cls._tickers_info = tickers_info
|
|
32
|
+
|
|
33
|
+
@classmethod
|
|
34
|
+
async def _load_futures_exchange_info(cls, session: aiohttp.ClientSession) -> None:
|
|
35
|
+
"""Загружает информацию о бирже для фьючерсного рынка."""
|
|
36
|
+
tickers_info = {}
|
|
37
|
+
exchange_info = await Client(session).symbol("FUTURES")
|
|
38
|
+
for el in exchange_info["data"]["list"]:
|
|
39
|
+
try:
|
|
40
|
+
tickers_info[el["symbol"]] = TickerInfoItem(
|
|
41
|
+
tick_precision=None,
|
|
42
|
+
tick_step=float(el["tickSize"]),
|
|
43
|
+
size_precision=None,
|
|
44
|
+
size_step=float(el["lotSize"]),
|
|
45
|
+
contract_size=float(el["unitSize"]),
|
|
46
|
+
)
|
|
47
|
+
except Exception as e:
|
|
48
|
+
cls._logger.error(f"Error loading ticker info for {el}: {e}")
|
|
49
|
+
|
|
50
|
+
cls._futures_tickers_info = tickers_info
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
__all__ = ["UniClient"]
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
from typing import overload
|
|
5
|
+
|
|
6
|
+
from unicex._abc import IUniClient
|
|
7
|
+
from unicex.enums import Exchange, Timeframe
|
|
8
|
+
from unicex.types import KlineDict, OpenInterestDict, OpenInterestItem, TickerDailyDict
|
|
9
|
+
|
|
10
|
+
from .adapter import Adapter
|
|
11
|
+
from .client import Client
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class UniClient(IUniClient[Client]):
|
|
15
|
+
"""Унифицированный клиент для работы с Kucoin API."""
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def _client_cls(self) -> type[Client]:
|
|
19
|
+
"""Возвращает класс клиента для Kucoin.
|
|
20
|
+
|
|
21
|
+
Возвращает:
|
|
22
|
+
type[Client]: Класс клиента для Kucoin.
|
|
23
|
+
"""
|
|
24
|
+
return Client
|
|
25
|
+
|
|
26
|
+
async def tickers(self, only_usdt: bool = True) -> list[str]:
|
|
27
|
+
"""Возвращает список тикеров.
|
|
28
|
+
|
|
29
|
+
Параметры:
|
|
30
|
+
only_usdt (bool): Если True, возвращает только тикеры в паре к USDT.
|
|
31
|
+
|
|
32
|
+
Возвращает:
|
|
33
|
+
list[str]: Список тикеров.
|
|
34
|
+
"""
|
|
35
|
+
raw_data = await self._client.ticker("SPOT")
|
|
36
|
+
return Adapter.tickers(raw_data, only_usdt)
|
|
37
|
+
|
|
38
|
+
async def futures_tickers(self, only_usdt: bool = True) -> list[str]:
|
|
39
|
+
"""Возвращает список тикеров.
|
|
40
|
+
|
|
41
|
+
Параметры:
|
|
42
|
+
only_usdt (bool): Если True, возвращает только тикеры в паре к USDT.
|
|
43
|
+
|
|
44
|
+
Возвращает:
|
|
45
|
+
list[str]: Список тикеров.
|
|
46
|
+
"""
|
|
47
|
+
raw_data = await self._client.ticker("FUTURES")
|
|
48
|
+
return Adapter.futures_tickers(raw_data, only_usdt)
|
|
49
|
+
|
|
50
|
+
async def last_price(self) -> dict[str, float]:
|
|
51
|
+
"""Возвращает последнюю цену для каждого тикера.
|
|
52
|
+
|
|
53
|
+
Возвращает:
|
|
54
|
+
dict[str, float]: Словарь с последними ценами для каждого тикера.
|
|
55
|
+
"""
|
|
56
|
+
raw_data = await self._client.ticker("SPOT")
|
|
57
|
+
return Adapter.last_price(raw_data)
|
|
58
|
+
|
|
59
|
+
async def futures_last_price(self) -> dict[str, float]:
|
|
60
|
+
"""Возвращает последнюю цену для каждого тикера.
|
|
61
|
+
|
|
62
|
+
Возвращает:
|
|
63
|
+
dict[str, float]: Словарь с последними ценами для каждого тикера.
|
|
64
|
+
"""
|
|
65
|
+
raw_data = await self._client.ticker("FUTURES")
|
|
66
|
+
return Adapter.last_price(raw_data)
|
|
67
|
+
|
|
68
|
+
async def ticker_24hr(self) -> TickerDailyDict:
|
|
69
|
+
"""Возвращает статистику за последние 24 часа для каждого тикера.
|
|
70
|
+
|
|
71
|
+
Возвращает:
|
|
72
|
+
TickerDailyDict: Словарь с статистикой за последние 24 часа для каждого тикера.
|
|
73
|
+
"""
|
|
74
|
+
raw_data = await self._client.ticker("SPOT")
|
|
75
|
+
return Adapter.ticker_24hr(raw_data)
|
|
76
|
+
|
|
77
|
+
async def futures_ticker_24hr(self) -> TickerDailyDict:
|
|
78
|
+
"""Возвращает статистику за последние 24 часа для каждого тикера.
|
|
79
|
+
|
|
80
|
+
Возвращает:
|
|
81
|
+
TickerDailyDict: Словарь с статистикой за последние 24 часа для каждого тикера.
|
|
82
|
+
"""
|
|
83
|
+
raw_data = await self._client.ticker("FUTURES")
|
|
84
|
+
return Adapter.ticker_24hr(raw_data)
|
|
85
|
+
|
|
86
|
+
async def klines(
|
|
87
|
+
self,
|
|
88
|
+
symbol: str,
|
|
89
|
+
interval: Timeframe | str,
|
|
90
|
+
limit: int | None = None,
|
|
91
|
+
start_time: int | None = None,
|
|
92
|
+
end_time: int | None = None,
|
|
93
|
+
) -> list[KlineDict]:
|
|
94
|
+
"""Возвращает список свечей для тикера.
|
|
95
|
+
|
|
96
|
+
Параметры:
|
|
97
|
+
symbol (str): Название тикера.
|
|
98
|
+
limit (int | None): Количество свечей.
|
|
99
|
+
interval (Timeframe | str): Таймфрейм свечей.
|
|
100
|
+
start_time (int | None): Время начала периода в миллисекундах.
|
|
101
|
+
end_time (int | None): Время окончания периода в миллисекундах.
|
|
102
|
+
|
|
103
|
+
Возвращает:
|
|
104
|
+
list[KlineDict]: Список свечей для тикера.
|
|
105
|
+
"""
|
|
106
|
+
if not limit and not all([start_time, end_time]):
|
|
107
|
+
raise ValueError("limit or (start_time and end_time) must be provided")
|
|
108
|
+
|
|
109
|
+
if limit: # Перезаписываем start_time и end_time если указан limit, т.к. по умолчанию HyperLiquid не принимают этот параметр
|
|
110
|
+
if not isinstance(interval, Timeframe):
|
|
111
|
+
raise ValueError("interval must be a Timeframe if limit param provided")
|
|
112
|
+
start_time, end_time = self.limit_to_start_and_end_time(
|
|
113
|
+
interval, limit, use_milliseconds=False
|
|
114
|
+
)
|
|
115
|
+
interval = (
|
|
116
|
+
interval.to_exchange_format(Exchange.KUCOIN)
|
|
117
|
+
if isinstance(interval, Timeframe)
|
|
118
|
+
else interval
|
|
119
|
+
)
|
|
120
|
+
raw_data = await self._client.kline(
|
|
121
|
+
trade_type="SPOT",
|
|
122
|
+
symbol=symbol,
|
|
123
|
+
interval=interval,
|
|
124
|
+
start_at=self.to_seconds(start_time),
|
|
125
|
+
end_at=self.to_seconds(end_time),
|
|
126
|
+
)
|
|
127
|
+
return Adapter.klines(raw_data=raw_data, symbol=symbol)
|
|
128
|
+
|
|
129
|
+
async def futures_klines(
|
|
130
|
+
self,
|
|
131
|
+
symbol: str,
|
|
132
|
+
interval: Timeframe | str,
|
|
133
|
+
limit: int | None = None,
|
|
134
|
+
start_time: int | None = None,
|
|
135
|
+
end_time: int | None = None,
|
|
136
|
+
) -> list[KlineDict]:
|
|
137
|
+
"""Возвращает список свечей для тикера.
|
|
138
|
+
|
|
139
|
+
Параметры:
|
|
140
|
+
symbol (str): Название тикера.
|
|
141
|
+
limit (int | None): Количество свечей.
|
|
142
|
+
interval (Timeframe | str): Таймфрейм свечей.
|
|
143
|
+
start_time (int | None): Время начала периода в миллисекундах.
|
|
144
|
+
end_time (int | None): Время окончания периода в миллисекундах.
|
|
145
|
+
|
|
146
|
+
Возвращает:
|
|
147
|
+
list[KlineDict]: Список свечей для тикера.
|
|
148
|
+
"""
|
|
149
|
+
if not limit and not all([start_time, end_time]):
|
|
150
|
+
raise ValueError("limit or (start_time and end_time) must be provided")
|
|
151
|
+
|
|
152
|
+
if limit: # Перезаписываем start_time и end_time если указан limit, т.к. по умолчанию HyperLiquid не принимают этот параметр
|
|
153
|
+
if not isinstance(interval, Timeframe):
|
|
154
|
+
raise ValueError("interval must be a Timeframe if limit param provided")
|
|
155
|
+
start_time, end_time = self.limit_to_start_and_end_time(
|
|
156
|
+
interval, limit, use_milliseconds=False
|
|
157
|
+
)
|
|
158
|
+
interval = (
|
|
159
|
+
interval.to_exchange_format(Exchange.KUCOIN)
|
|
160
|
+
if isinstance(interval, Timeframe)
|
|
161
|
+
else interval
|
|
162
|
+
)
|
|
163
|
+
raw_data = await self._client.kline(
|
|
164
|
+
trade_type="FUTURES",
|
|
165
|
+
symbol=symbol,
|
|
166
|
+
interval=interval,
|
|
167
|
+
start_at=self.to_seconds(start_time),
|
|
168
|
+
end_at=self.to_seconds(end_time),
|
|
169
|
+
)
|
|
170
|
+
return Adapter.klines(raw_data=raw_data, symbol=symbol)
|
|
171
|
+
|
|
172
|
+
async def funding_rate(self, symbol: str | None = None) -> dict[str, float] | float:
|
|
173
|
+
"""Возвращает ставку финансирования для тикера.
|
|
174
|
+
|
|
175
|
+
Параметры:
|
|
176
|
+
symbol (`str | None`): Название тикера. На Kucoin параметр обязателен.
|
|
177
|
+
|
|
178
|
+
Возвращает:
|
|
179
|
+
`dict[str, float] | float`: Ставка финансирования в процентах.
|
|
180
|
+
"""
|
|
181
|
+
if not symbol:
|
|
182
|
+
raise ValueError("Symbol is required to fetch Kucoin funding rate")
|
|
183
|
+
raw_data = await self._client.funding_rate(symbol=symbol)
|
|
184
|
+
return Adapter.funding_rate(raw_data)
|
|
185
|
+
|
|
186
|
+
@overload
|
|
187
|
+
async def open_interest(self, symbol: str) -> OpenInterestItem: ...
|
|
188
|
+
|
|
189
|
+
@overload
|
|
190
|
+
async def open_interest(self, symbol: None) -> OpenInterestDict: ...
|
|
191
|
+
|
|
192
|
+
@overload
|
|
193
|
+
async def open_interest(self) -> OpenInterestDict: ...
|
|
194
|
+
|
|
195
|
+
async def open_interest(self, symbol: str | None = None) -> OpenInterestItem | OpenInterestDict:
|
|
196
|
+
"""Возвращает объем открытого интереса для тикера или всех тикеров, если тикер не указан.
|
|
197
|
+
|
|
198
|
+
Параметры:
|
|
199
|
+
symbol (`str | None`): Название тикера. (Опционально, но обязателен для следующих бирж: BINANCE).
|
|
200
|
+
|
|
201
|
+
Возвращает:
|
|
202
|
+
`OpenInterestItem | OpenInterestDict`: Если тикер передан - словарь со временем и объемом
|
|
203
|
+
открытого интереса в монетах. Если нет передан - то словарь, в котором ключ - тикер,
|
|
204
|
+
а значение - словарь с временем и объемом открытого интереса в монетах.
|
|
205
|
+
"""
|
|
206
|
+
raw_data = await self._client.open_interest()
|
|
207
|
+
adapted_data = Adapter.open_interest(raw_data)
|
|
208
|
+
return adapted_data[symbol] if symbol else adapted_data
|