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,119 @@
|
|
|
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
|
+
"""Предзагружает информацию о тикерах для биржи Hyperliquid."""
|
|
13
|
+
|
|
14
|
+
exchange_name = "Hyperliquid"
|
|
15
|
+
"""Название биржи, на которой работает класс."""
|
|
16
|
+
|
|
17
|
+
_spot_meta: dict = {}
|
|
18
|
+
"""Словарь с метаинформацией о спотовом рынке."""
|
|
19
|
+
|
|
20
|
+
_spot_ident_to_idx: dict = {}
|
|
21
|
+
"""Словарь, в котором ключ - индетефикатор тикера на бирже, например '@123', а значение - его индекс в _spot_meta."""
|
|
22
|
+
|
|
23
|
+
_spot_idx_to_name: dict = {}
|
|
24
|
+
"""Словарь, в котором ключ - индекс в _spot_meta, например "123", а значение - название тикера, например 'BTC'."""
|
|
25
|
+
|
|
26
|
+
_futures_meta: dict = {}
|
|
27
|
+
"""Словарь с метаинформацией о фьючерсном рынке."""
|
|
28
|
+
|
|
29
|
+
# DOCS: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/tick-and-lot-size
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
async def _load_spot_exchange_info(cls, session: aiohttp.ClientSession) -> None:
|
|
33
|
+
"""Загружает информацию о бирже для спотового рынка."""
|
|
34
|
+
cls._spot_meta = await Client(session).spot_metadata()
|
|
35
|
+
cls._build_spot_mappings(cls._spot_meta)
|
|
36
|
+
|
|
37
|
+
tickers_info: dict[str, TickerInfoItem] = {}
|
|
38
|
+
for symbol_info in cls._spot_meta["tokens"]:
|
|
39
|
+
tickers_info[symbol_info["name"]] = TickerInfoItem(
|
|
40
|
+
tick_step=None,
|
|
41
|
+
tick_precision=int(symbol_info["weiDecimals"]),
|
|
42
|
+
size_step=None,
|
|
43
|
+
size_precision=int(symbol_info["szDecimals"]),
|
|
44
|
+
contract_size=1,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
cls._tickers_info = tickers_info
|
|
48
|
+
|
|
49
|
+
@classmethod
|
|
50
|
+
async def _load_futures_exchange_info(cls, session: aiohttp.ClientSession) -> None:
|
|
51
|
+
"""Загружает информацию о бирже для фьючерсного рынка."""
|
|
52
|
+
cls._futures_meta = await Client(session).perp_metadata()
|
|
53
|
+
|
|
54
|
+
@classmethod
|
|
55
|
+
def _build_spot_mappings(cls, spot_meta: dict) -> None:
|
|
56
|
+
"""Строит словари соответствия '@индекс' ↔ индекс ↔ 'BTC'."""
|
|
57
|
+
universe = spot_meta["universe"]
|
|
58
|
+
tokens = spot_meta["tokens"]
|
|
59
|
+
|
|
60
|
+
number_to_idx = {}
|
|
61
|
+
for u in universe:
|
|
62
|
+
number_to_idx[u["name"]] = u["tokens"][0]
|
|
63
|
+
cls._spot_ident_to_idx = number_to_idx
|
|
64
|
+
|
|
65
|
+
idx_to_name = {}
|
|
66
|
+
for t in tokens:
|
|
67
|
+
idx_to_name[t["index"]] = t["name"]
|
|
68
|
+
cls._spot_idx_to_name = idx_to_name
|
|
69
|
+
|
|
70
|
+
@classmethod
|
|
71
|
+
def get_spot_meta(cls) -> dict:
|
|
72
|
+
"""Возвращает метаинформацию о спотовом рынке."""
|
|
73
|
+
cls._check_loaded()
|
|
74
|
+
return cls._spot_meta
|
|
75
|
+
|
|
76
|
+
@classmethod
|
|
77
|
+
def get_futures_meta(cls) -> dict:
|
|
78
|
+
"""Возвращает метаинформацию о фьючерсном рынке."""
|
|
79
|
+
cls._check_loaded()
|
|
80
|
+
return cls._futures_meta
|
|
81
|
+
|
|
82
|
+
@classmethod
|
|
83
|
+
def resolve_spot_symbol(cls, ident: str) -> str:
|
|
84
|
+
"""Преобразует внутренний идентификатор вида '@142' в тикер, например 'BTC'.
|
|
85
|
+
Не рейзит KeyError, если тикер не найден.
|
|
86
|
+
|
|
87
|
+
Параметры:
|
|
88
|
+
token_name (str): Имя токена на бирже, например '@142' или 'BTC'.
|
|
89
|
+
|
|
90
|
+
Возвращает:
|
|
91
|
+
str | None: Название тикера (например 'BTC'), либо None, если не найден.
|
|
92
|
+
"""
|
|
93
|
+
cls._check_loaded()
|
|
94
|
+
|
|
95
|
+
try:
|
|
96
|
+
return cls._spot_idx_to_name[cls._spot_ident_to_idx[ident]]
|
|
97
|
+
except KeyError:
|
|
98
|
+
return ident
|
|
99
|
+
|
|
100
|
+
@classmethod
|
|
101
|
+
def resolve_spot_ident(cls, symbol: str) -> str:
|
|
102
|
+
"""Преобразует тикер (например, 'BTC') в внутренний идентификатор (например, '@142').
|
|
103
|
+
|
|
104
|
+
Параметры:
|
|
105
|
+
symbol (str): Название тикера, например 'BTC'.
|
|
106
|
+
|
|
107
|
+
Возвращает:
|
|
108
|
+
str: Внутренний идентификатор (например '@142').
|
|
109
|
+
|
|
110
|
+
Исключения:
|
|
111
|
+
KeyError: Если тикер не найден в локальном кэше биржи.
|
|
112
|
+
"""
|
|
113
|
+
cls._check_loaded()
|
|
114
|
+
|
|
115
|
+
# Находим индекс по тикеру
|
|
116
|
+
idx = next(k for k, v in cls._spot_idx_to_name.items() if v == symbol)
|
|
117
|
+
|
|
118
|
+
# Возвращаем внутренний идентификатор вида "@142"
|
|
119
|
+
return next(k for k, v in cls._spot_ident_to_idx.items() if v == idx)
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
__all__ = ["UniClient"]
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
from typing import Self, overload
|
|
5
|
+
|
|
6
|
+
import aiohttp
|
|
7
|
+
|
|
8
|
+
from unicex._abc import IUniClient
|
|
9
|
+
from unicex.enums import Exchange, MarketType, Timeframe
|
|
10
|
+
from unicex.types import KlineDict, LoggerLike, OpenInterestDict, OpenInterestItem, TickerDailyDict
|
|
11
|
+
from unicex.utils import batched_list
|
|
12
|
+
|
|
13
|
+
from .adapter import Adapter
|
|
14
|
+
from .client import Client
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class UniClient(IUniClient[Client]):
|
|
18
|
+
"""Унифицированный клиент для работы с Hyperliquid API."""
|
|
19
|
+
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
session: aiohttp.ClientSession,
|
|
23
|
+
private_key: str | bytes | None = None,
|
|
24
|
+
wallet_address: str | None = None,
|
|
25
|
+
vault_address: str | None = None,
|
|
26
|
+
logger: LoggerLike | None = None,
|
|
27
|
+
max_retries: int = 3,
|
|
28
|
+
retry_delay: int | float = 0.1,
|
|
29
|
+
proxies: list[str] | None = None,
|
|
30
|
+
timeout: int = 10,
|
|
31
|
+
) -> None:
|
|
32
|
+
"""Инициализация клиента.
|
|
33
|
+
|
|
34
|
+
Параметры:
|
|
35
|
+
session (`aiohttp.ClientSession`): Сессия для выполнения HTTP‑запросов.
|
|
36
|
+
private_key (`str | bytes | None`): Приватный ключ API для аутентификации (Hyperliquid).
|
|
37
|
+
wallet_address (`str | None`): Адрес кошелька для аутентификации (Hyperliquid).
|
|
38
|
+
vault_address (`str | None`): Адрес хранилища для аутентификации (Hyperliquid).
|
|
39
|
+
logger (`LoggerLike | None`): Логгер для вывода информации.
|
|
40
|
+
max_retries (`int`): Максимальное количество повторных попыток запроса.
|
|
41
|
+
retry_delay (`int | float`): Задержка между повторными попытками, сек.
|
|
42
|
+
proxies (`list[str] | None`): Список HTTP(S)‑прокси для циклического использования.
|
|
43
|
+
timeout (`int`): Максимальное время ожидания ответа от сервера, сек.
|
|
44
|
+
"""
|
|
45
|
+
self._client: Client = self._client_cls(
|
|
46
|
+
private_key=private_key,
|
|
47
|
+
wallet_address=wallet_address,
|
|
48
|
+
vault_address=vault_address,
|
|
49
|
+
session=session,
|
|
50
|
+
logger=logger,
|
|
51
|
+
max_retries=max_retries,
|
|
52
|
+
retry_delay=retry_delay,
|
|
53
|
+
proxies=proxies,
|
|
54
|
+
timeout=timeout,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
@classmethod
|
|
58
|
+
async def create(
|
|
59
|
+
cls,
|
|
60
|
+
private_key: str | bytes | None = None,
|
|
61
|
+
wallet_address: str | None = None,
|
|
62
|
+
vault_address: str | None = None,
|
|
63
|
+
logger: LoggerLike | None = None,
|
|
64
|
+
max_retries: int = 3,
|
|
65
|
+
retry_delay: int | float = 0.1,
|
|
66
|
+
proxies: list[str] | None = None,
|
|
67
|
+
timeout: int = 10,
|
|
68
|
+
) -> Self:
|
|
69
|
+
"""Создает инстанцию клиента.
|
|
70
|
+
Создать клиент можно и через __init__, но в таком случае session: `aiohttp.ClientSession` - обязательный параметр.
|
|
71
|
+
|
|
72
|
+
Параметры:
|
|
73
|
+
session (`aiohttp.ClientSession`): Сессия для выполнения HTTP‑запросов.
|
|
74
|
+
private_key (`str | bytes | None`): Приватный ключ API для аутентификации (Hyperliquid).
|
|
75
|
+
wallet_address (`str | None`): Адрес кошелька для аутентификации (Hyperliquid).
|
|
76
|
+
vault_address (`str | None`): Адрес хранилища для аутентификации (Hyperliquid).
|
|
77
|
+
logger (`LoggerLike | None`): Логгер для вывода информации.
|
|
78
|
+
max_retries (`int`): Максимальное количество повторных попыток запроса.
|
|
79
|
+
retry_delay (`int | float`): Задержка между повторными попытками, сек.
|
|
80
|
+
proxies (`list[str] | None`): Список HTTP(S)‑прокси для циклического использования.
|
|
81
|
+
timeout (`int`): Максимальное время ожидания ответа от сервера, сек.
|
|
82
|
+
|
|
83
|
+
Возвращает:
|
|
84
|
+
`IUniClient`: Созданный экземпляр клиента.
|
|
85
|
+
"""
|
|
86
|
+
return cls(
|
|
87
|
+
session=aiohttp.ClientSession(),
|
|
88
|
+
private_key=private_key,
|
|
89
|
+
wallet_address=wallet_address,
|
|
90
|
+
vault_address=vault_address,
|
|
91
|
+
logger=logger,
|
|
92
|
+
max_retries=max_retries,
|
|
93
|
+
retry_delay=retry_delay,
|
|
94
|
+
proxies=proxies,
|
|
95
|
+
timeout=timeout,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
@property
|
|
99
|
+
def _client_cls(self) -> type[Client]:
|
|
100
|
+
"""Возвращает класс клиента для Hyperliquid.
|
|
101
|
+
|
|
102
|
+
Возвращает:
|
|
103
|
+
type[Client]: Класс клиента для Hyperliquid.
|
|
104
|
+
"""
|
|
105
|
+
return Client
|
|
106
|
+
|
|
107
|
+
async def tickers(self, resolve_symbols: bool = False) -> list[str]:
|
|
108
|
+
"""Возвращает список тикеров.
|
|
109
|
+
|
|
110
|
+
Параметры:
|
|
111
|
+
resolve_symbols (bool): Если True, тикеры маппятся из вида "@123" в "BTC".
|
|
112
|
+
|
|
113
|
+
Возвращает:
|
|
114
|
+
list[str]: Список тикеров.
|
|
115
|
+
"""
|
|
116
|
+
raw_data = await self._client.spot_metadata()
|
|
117
|
+
return Adapter.tickers(raw_data, resolve_symbols)
|
|
118
|
+
|
|
119
|
+
async def tickers_batched(
|
|
120
|
+
self, resolve_symbols: bool = False, batch_size: int = 20
|
|
121
|
+
) -> list[list[str]]:
|
|
122
|
+
"""Возвращает список тикеров в чанках.
|
|
123
|
+
|
|
124
|
+
Параметры:
|
|
125
|
+
resolve_symbols (bool): Если True, тикеры маппятся из вида "@123" в "BTC".
|
|
126
|
+
batch_size (`int`): Размер чанка.
|
|
127
|
+
|
|
128
|
+
Возвращает:
|
|
129
|
+
`list[list[str]]`: Список тикеров в чанках.
|
|
130
|
+
"""
|
|
131
|
+
tickers = await self.tickers(resolve_symbols)
|
|
132
|
+
return batched_list(tickers, batch_size)
|
|
133
|
+
|
|
134
|
+
async def futures_tickers(self) -> list[str]:
|
|
135
|
+
"""Возвращает список тикеров.
|
|
136
|
+
|
|
137
|
+
Возвращает:
|
|
138
|
+
list[str]: Список тикеров.
|
|
139
|
+
"""
|
|
140
|
+
raw_data = await self._client.perp_metadata()
|
|
141
|
+
return Adapter.futures_tickers(raw_data)
|
|
142
|
+
|
|
143
|
+
async def futures_tickers_batched(self, batch_size: int = 20) -> list[list[str]]:
|
|
144
|
+
"""Возвращает список тикеров в чанках.
|
|
145
|
+
|
|
146
|
+
Параметры:
|
|
147
|
+
batch_size (`int`): Размер чанка.
|
|
148
|
+
|
|
149
|
+
Возвращает:
|
|
150
|
+
`list[list[str]]`: Список тикеров в чанках.
|
|
151
|
+
"""
|
|
152
|
+
tickers = await self.futures_tickers()
|
|
153
|
+
return batched_list(tickers, batch_size)
|
|
154
|
+
|
|
155
|
+
async def last_price(self, resolve_symbols: bool = False) -> dict[str, float]:
|
|
156
|
+
"""Возвращает последнюю цену для каждого тикера.
|
|
157
|
+
|
|
158
|
+
Параметры:
|
|
159
|
+
resolve_symbols (bool): Если True, тикеры маппятся из вида "@123" в "BTC".
|
|
160
|
+
|
|
161
|
+
Возвращает:
|
|
162
|
+
dict[str, float]: Словарь с последними ценами для каждого тикера.
|
|
163
|
+
"""
|
|
164
|
+
raw_data = await self._client.all_mids()
|
|
165
|
+
return Adapter.last_price(raw_data, resolve_symbols)
|
|
166
|
+
|
|
167
|
+
async def futures_last_price(self) -> dict[str, float]:
|
|
168
|
+
"""Возвращает последнюю цену для каждого тикера.
|
|
169
|
+
|
|
170
|
+
Возвращает:
|
|
171
|
+
dict[str, float]: Словарь с последними ценами для каждого тикера.
|
|
172
|
+
"""
|
|
173
|
+
raw_data = await self._client.all_mids()
|
|
174
|
+
return Adapter.futures_last_price(raw_data)
|
|
175
|
+
|
|
176
|
+
async def ticker_24hr(self, resolve_symbols: bool = False) -> TickerDailyDict:
|
|
177
|
+
"""Возвращает статистику за последние 24 часа для каждого тикера.
|
|
178
|
+
|
|
179
|
+
Параметры:
|
|
180
|
+
resolve_symbols (bool): Если True, тикеры маппятся из вида "@123" в "BTC".
|
|
181
|
+
|
|
182
|
+
Возвращает:
|
|
183
|
+
TickerDailyDict: Словарь с статистикой за последние 24 часа для каждого тикера.
|
|
184
|
+
"""
|
|
185
|
+
raw_data = await self._client.spot_meta_and_asset_contexts()
|
|
186
|
+
return Adapter.ticker_24hr(raw_data, resolve_symbols)
|
|
187
|
+
|
|
188
|
+
async def futures_ticker_24hr(self) -> TickerDailyDict:
|
|
189
|
+
"""Возвращает статистику за последние 24 часа для каждого тикера.
|
|
190
|
+
|
|
191
|
+
Возвращает:
|
|
192
|
+
TickerDailyDict: Словарь с статистикой за последние 24 часа для каждого тикера.
|
|
193
|
+
"""
|
|
194
|
+
raw_data = await self._client.perp_meta_and_asset_contexts()
|
|
195
|
+
return Adapter.futures_ticker_24hr(raw_data)
|
|
196
|
+
|
|
197
|
+
async def klines(
|
|
198
|
+
self,
|
|
199
|
+
symbol: str,
|
|
200
|
+
interval: Timeframe | str,
|
|
201
|
+
limit: int | None = None,
|
|
202
|
+
start_time: int | None = None,
|
|
203
|
+
end_time: int | None = None,
|
|
204
|
+
resolve_symbols: bool = False,
|
|
205
|
+
) -> list[KlineDict]:
|
|
206
|
+
"""Возвращает список свечей для тикера.
|
|
207
|
+
|
|
208
|
+
Параметры:
|
|
209
|
+
symbol (str): Название тикера. Например "@1".
|
|
210
|
+
limit (int | None): Количество свечей.
|
|
211
|
+
interval (Timeframe | str): Таймфрейм свечей.
|
|
212
|
+
start_time (int | None): Время начала периода в миллисекундах.
|
|
213
|
+
end_time (int | None): Время окончания периода в миллисекундах.
|
|
214
|
+
resolve_symbols (bool): Если True, тикер маппится из вида "@123" в "BTC".
|
|
215
|
+
|
|
216
|
+
Возвращает:
|
|
217
|
+
list[KlineDict]: Список свечей для тикера.
|
|
218
|
+
"""
|
|
219
|
+
if not limit and not all([start_time, end_time]):
|
|
220
|
+
raise ValueError("limit and (start_time and end_time) must be provided")
|
|
221
|
+
|
|
222
|
+
if limit: # Перезаписываем start_time и end_time если указан limit, т.к. по умолчанию HyperLiquid не принимают этот параметр
|
|
223
|
+
if not isinstance(interval, Timeframe):
|
|
224
|
+
raise ValueError("interval must be a Timeframe if limit param provided")
|
|
225
|
+
end_time = int(time.time() * 1000)
|
|
226
|
+
start_time = end_time - (limit * interval.to_seconds * 1000) # type: ignore[reportOptionalOperand]
|
|
227
|
+
interval = (
|
|
228
|
+
interval.to_exchange_format(Exchange.HYPERLIQUID, MarketType.SPOT)
|
|
229
|
+
if isinstance(interval, Timeframe)
|
|
230
|
+
else interval
|
|
231
|
+
)
|
|
232
|
+
raw_data = await self._client.candle_snapshot(
|
|
233
|
+
coin=symbol,
|
|
234
|
+
interval=interval,
|
|
235
|
+
start_time=start_time, # type: ignore[reportArgumentType]
|
|
236
|
+
end_time=end_time, # type: ignore[reportArgumentType]
|
|
237
|
+
)
|
|
238
|
+
return Adapter.klines(raw_data=raw_data, resolve_symbols=resolve_symbols)
|
|
239
|
+
|
|
240
|
+
async def futures_klines(
|
|
241
|
+
self,
|
|
242
|
+
symbol: str,
|
|
243
|
+
interval: Timeframe | str,
|
|
244
|
+
limit: int | None = None,
|
|
245
|
+
start_time: int | None = None,
|
|
246
|
+
end_time: int | None = None,
|
|
247
|
+
) -> list[KlineDict]:
|
|
248
|
+
"""Возвращает список свечей для тикера.
|
|
249
|
+
|
|
250
|
+
Параметры:
|
|
251
|
+
symbol (str): Название тикера. Например "BTC".
|
|
252
|
+
limit (int | None): Количество свечей.
|
|
253
|
+
interval (Timeframe | str): Таймфрейм свечей.
|
|
254
|
+
start_time (int | None): Время начала периода в миллисекундах.
|
|
255
|
+
end_time (int | None): Время окончания периода в миллисекундах.
|
|
256
|
+
|
|
257
|
+
Возвращает:
|
|
258
|
+
list[KlineDict]: Список свечей для тикера.
|
|
259
|
+
"""
|
|
260
|
+
if not limit and not all([start_time, end_time]):
|
|
261
|
+
raise ValueError("limit and (start_time and end_time) must be provided")
|
|
262
|
+
|
|
263
|
+
if limit: # Перезаписываем start_time и end_time если указан limit, т.к. по умолчанию HyperLiquid не принимают этот параметр
|
|
264
|
+
if not isinstance(interval, Timeframe):
|
|
265
|
+
raise ValueError("interval must be a Timeframe if limit param provided")
|
|
266
|
+
end_time = int(time.time() * 1000)
|
|
267
|
+
start_time = end_time - (limit * interval.to_seconds * 1000) # type: ignore[reportOptionalOperand]
|
|
268
|
+
interval = (
|
|
269
|
+
interval.to_exchange_format(Exchange.HYPERLIQUID, MarketType.FUTURES)
|
|
270
|
+
if isinstance(interval, Timeframe)
|
|
271
|
+
else interval
|
|
272
|
+
)
|
|
273
|
+
raw_data = await self._client.candle_snapshot(
|
|
274
|
+
coin=symbol,
|
|
275
|
+
interval=interval,
|
|
276
|
+
start_time=start_time, # type: ignore[reportArgumentType]
|
|
277
|
+
end_time=end_time, # type: ignore[reportArgumentType]
|
|
278
|
+
)
|
|
279
|
+
return Adapter.futures_klines(raw_data)
|
|
280
|
+
|
|
281
|
+
@overload
|
|
282
|
+
async def funding_rate(self, symbol: str) -> float: ...
|
|
283
|
+
|
|
284
|
+
@overload
|
|
285
|
+
async def funding_rate(self, symbol: None) -> dict[str, float]: ...
|
|
286
|
+
|
|
287
|
+
@overload
|
|
288
|
+
async def funding_rate(self) -> dict[str, float]: ...
|
|
289
|
+
|
|
290
|
+
async def funding_rate(self, symbol: str | None = None) -> dict[str, float] | float:
|
|
291
|
+
"""Возвращает ставку финансирования для тикера или всех тикеров, если тикер не указан.
|
|
292
|
+
|
|
293
|
+
Параметры:
|
|
294
|
+
symbol (`str | None`): Название тикера (Опционально).
|
|
295
|
+
|
|
296
|
+
Возвращает:
|
|
297
|
+
`dict[str, float] | float`: Ставка финансирования для тикера или словарь со ставками для всех тикеров.
|
|
298
|
+
"""
|
|
299
|
+
raw_data = await self._client.perp_meta_and_asset_contexts()
|
|
300
|
+
adapted_data = Adapter.funding_rate(raw_data)
|
|
301
|
+
return adapted_data[symbol] if symbol else adapted_data
|
|
302
|
+
|
|
303
|
+
@overload
|
|
304
|
+
async def open_interest(self, symbol: str) -> OpenInterestItem: ...
|
|
305
|
+
|
|
306
|
+
@overload
|
|
307
|
+
async def open_interest(self, symbol: None) -> OpenInterestDict: ...
|
|
308
|
+
|
|
309
|
+
@overload
|
|
310
|
+
async def open_interest(self) -> OpenInterestDict: ...
|
|
311
|
+
|
|
312
|
+
async def open_interest(self, symbol: str | None = None) -> OpenInterestItem | OpenInterestDict:
|
|
313
|
+
"""Возвращает объем открытого интереса для тикера или всех тикеров, если тикер не указан.
|
|
314
|
+
|
|
315
|
+
Параметры:
|
|
316
|
+
symbol (`str | None`): Название тикера. (Опционально, но обязателен для следующих бирж: BINANCE).
|
|
317
|
+
|
|
318
|
+
Возвращает:
|
|
319
|
+
`OpenInterestItem | OpenInterestDict`: Если тикер передан - словарь со временем и объемом
|
|
320
|
+
открытого интереса в монетах. Если нет передан - то словарь, в котором ключ - тикер,
|
|
321
|
+
а значение - словарь с временем и объемом открытого интереса в монетах.
|
|
322
|
+
"""
|
|
323
|
+
raw_data = await self._client.perp_meta_and_asset_contexts()
|
|
324
|
+
adapted_data = Adapter.open_interest(raw_data)
|
|
325
|
+
return adapted_data[symbol] if symbol else adapted_data
|