unicex 0.16.6__py3-none-any.whl → 0.17.1__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/aster/client.py ADDED
@@ -0,0 +1,794 @@
1
+ __all__ = ["Client"]
2
+
3
+ import json
4
+ import time
5
+ from typing import Any, Literal
6
+
7
+ from unicex._base import BaseClient
8
+ from unicex.exceptions import NotAuthorized
9
+ from unicex.types import NumberLike, RequestMethod
10
+ from unicex.utils import dict_to_query_string, filter_params, generate_hmac_sha256_signature
11
+
12
+
13
+ class Client(BaseClient):
14
+ """Клиент для работы с Aster API."""
15
+
16
+ _BASE_FUTURES_URL: str = "https://fapi.asterdex.com"
17
+ """Базовый URL для REST API Aster Futures."""
18
+
19
+ _RECV_WINDOW: int = 5000
20
+ """Стандартный интервал времени для получения ответа от сервера."""
21
+
22
+ def _get_headers(self, method: RequestMethod) -> dict[str, str]:
23
+ """Возвращает заголовки для запросов к Aster API."""
24
+ headers = {"Accept": "application/json"}
25
+ if self._api_key: # type: ignore[attr-defined]
26
+ headers["X-MBX-APIKEY"] = self._api_key # type: ignore[attr-defined]
27
+ if method in {"POST", "PUT", "DELETE"}:
28
+ headers["Content-Type"] = "application/x-www-form-urlencoded"
29
+ return headers
30
+
31
+ def _prepare_payload(
32
+ self,
33
+ *,
34
+ method: RequestMethod,
35
+ signed: bool,
36
+ params: dict[str, Any] | None,
37
+ ) -> tuple[dict[str, Any], dict[str, Any]]:
38
+ """Подготавливает параметры запроса."""
39
+ params = filter_params(params) if params else {}
40
+ headers = self._get_headers(method)
41
+
42
+ if not signed:
43
+ return {"params": params}, headers
44
+
45
+ if not self.is_authorized():
46
+ raise NotAuthorized("Api key and api secret is required to private endpoints")
47
+
48
+ payload = {**params}
49
+ payload["timestamp"] = int(time.time() * 1000)
50
+ payload["recvWindow"] = self._RECV_WINDOW
51
+
52
+ # Подпись формируем по query string без параметра signature.
53
+ query_string = dict_to_query_string(payload)
54
+ payload["signature"] = generate_hmac_sha256_signature(
55
+ self._api_secret, # type: ignore[attr-defined]
56
+ query_string,
57
+ "hex",
58
+ )
59
+
60
+ return payload, headers
61
+
62
+ async def _make_request(
63
+ self,
64
+ method: RequestMethod,
65
+ url: str,
66
+ signed: bool = False,
67
+ *,
68
+ params: dict[str, Any] | None = None,
69
+ ) -> Any:
70
+ """Выполняет HTTP-запрос к эндпоинтам Aster API."""
71
+ payload, headers = self._prepare_payload(method=method, signed=signed, params=params)
72
+
73
+ if not signed:
74
+ return await super()._make_request(method=method, url=url, headers=headers, **payload)
75
+
76
+ return await super()._make_request(
77
+ method=method,
78
+ url=url,
79
+ params=payload,
80
+ headers=headers,
81
+ )
82
+
83
+ async def request(
84
+ self, method: RequestMethod, url: str, params: dict, data: dict, signed: bool
85
+ ) -> dict:
86
+ """Выполняет запрос к произвольному endpoint Aster API.
87
+
88
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation
89
+ """
90
+ return await self._make_request(method=method, url=url, params=params, signed=signed)
91
+
92
+ # topic: futures market data endpoints
93
+
94
+ async def futures_ping(self) -> dict:
95
+ """Проверка подключения к REST API.
96
+
97
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#test-connectivity
98
+ """
99
+ url = self._BASE_FUTURES_URL + "/fapi/v1/ping"
100
+
101
+ return await self._make_request("GET", url)
102
+
103
+ async def futures_server_time(self) -> dict:
104
+ """Получение серверного времени.
105
+
106
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#check-server-time
107
+ """
108
+ url = self._BASE_FUTURES_URL + "/fapi/v1/time"
109
+
110
+ return await self._make_request("GET", url)
111
+
112
+ async def futures_exchange_info(self) -> dict:
113
+ """Получение информации о символах рынка и текущих правилах биржевой торговли.
114
+
115
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#exchange-information
116
+ """
117
+ url = self._BASE_FUTURES_URL + "/fapi/v1/exchangeInfo"
118
+
119
+ return await self._make_request("GET", url)
120
+
121
+ async def futures_depth(self, symbol: str, limit: int | None = None) -> dict:
122
+ """Получение книги ордеров.
123
+
124
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#order-book
125
+ """
126
+ url = self._BASE_FUTURES_URL + "/fapi/v1/depth"
127
+ params = {"symbol": symbol, "limit": limit}
128
+
129
+ return await self._make_request("GET", url, params=params)
130
+
131
+ async def futures_trades(self, symbol: str, limit: int | None = None) -> list[dict]:
132
+ """Получение последних сделок.
133
+
134
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#recent-trades-list
135
+ """
136
+ url = self._BASE_FUTURES_URL + "/fapi/v1/trades"
137
+ params = {"symbol": symbol, "limit": limit}
138
+
139
+ return await self._make_request("GET", url, params=params)
140
+
141
+ async def futures_historical_trades(
142
+ self, symbol: str, limit: int | None = None, from_id: int | None = None
143
+ ) -> list[dict]:
144
+ """Получение исторических сделок.
145
+
146
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#old-trades-lookup-market_data
147
+ """
148
+ url = self._BASE_FUTURES_URL + "/fapi/v1/historicalTrades"
149
+ params = {"symbol": symbol, "limit": limit, "fromId": from_id}
150
+
151
+ return await self._make_request("GET", url, params=params)
152
+
153
+ async def futures_agg_trades(
154
+ self,
155
+ symbol: str,
156
+ from_id: int | None = None,
157
+ start_time: int | None = None,
158
+ end_time: int | None = None,
159
+ limit: int | None = None,
160
+ ) -> list[dict]:
161
+ """Получение агрегированных сделок на фьючерсах.
162
+
163
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#compressed-aggregate-trades-list
164
+ """
165
+ url = self._BASE_FUTURES_URL + "/fapi/v1/aggTrades"
166
+ params = {
167
+ "symbol": symbol,
168
+ "fromId": from_id,
169
+ "startTime": start_time,
170
+ "endTime": end_time,
171
+ "limit": limit,
172
+ }
173
+
174
+ return await self._make_request("GET", url, params=params)
175
+
176
+ async def futures_klines(
177
+ self,
178
+ symbol: str,
179
+ interval: str,
180
+ start_time: int | None = None,
181
+ end_time: int | None = None,
182
+ limit: int | None = None,
183
+ ) -> list[list]:
184
+ """Получение исторических свечей.
185
+
186
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#kline-candlestick-data
187
+ """
188
+ url = self._BASE_FUTURES_URL + "/fapi/v1/klines"
189
+ params = {
190
+ "symbol": symbol,
191
+ "interval": interval,
192
+ "startTime": start_time,
193
+ "endTime": end_time,
194
+ "limit": limit,
195
+ }
196
+
197
+ return await self._make_request("GET", url, params=params)
198
+
199
+ async def futures_index_price_klines(
200
+ self,
201
+ pair: str,
202
+ interval: str,
203
+ start_time: int | None = None,
204
+ end_time: int | None = None,
205
+ limit: int | None = None,
206
+ ) -> list[list]:
207
+ """Получение свечей по индексу цены.
208
+
209
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#index-price-kline-candlestick-data
210
+ """
211
+ url = self._BASE_FUTURES_URL + "/fapi/v1/indexPriceKlines"
212
+ params = {
213
+ "pair": pair,
214
+ "interval": interval,
215
+ "startTime": start_time,
216
+ "endTime": end_time,
217
+ "limit": limit,
218
+ }
219
+
220
+ return await self._make_request("GET", url, params=params)
221
+
222
+ async def futures_mark_price_klines(
223
+ self,
224
+ symbol: str,
225
+ interval: str,
226
+ start_time: int | None = None,
227
+ end_time: int | None = None,
228
+ limit: int | None = None,
229
+ ) -> list[list]:
230
+ """Получение свечей по марк-цене.
231
+
232
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#mark-price-kline-candlestick-data
233
+ """
234
+ url = self._BASE_FUTURES_URL + "/fapi/v1/markPriceKlines"
235
+ params = {
236
+ "symbol": symbol,
237
+ "interval": interval,
238
+ "startTime": start_time,
239
+ "endTime": end_time,
240
+ "limit": limit,
241
+ }
242
+
243
+ return await self._make_request("GET", url, params=params)
244
+
245
+ async def futures_mark_price(self, symbol: str | None = None) -> dict | list[dict]:
246
+ """Получение ставки финансирования и цены маркировки.
247
+
248
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#mark-price
249
+ """
250
+ url = self._BASE_FUTURES_URL + "/fapi/v1/premiumIndex"
251
+ params = {"symbol": symbol}
252
+
253
+ return await self._make_request("GET", url, params=params)
254
+
255
+ async def futures_funding_rate(
256
+ self,
257
+ symbol: str | None = None,
258
+ start_time: int | None = None,
259
+ end_time: int | None = None,
260
+ limit: int | None = None,
261
+ ) -> list[dict]:
262
+ """Получение истории ставок финансирования.
263
+
264
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#get-funding-rate-history
265
+ """
266
+ url = self._BASE_FUTURES_URL + "/fapi/v1/fundingRate"
267
+ params = {
268
+ "symbol": symbol,
269
+ "startTime": start_time,
270
+ "endTime": end_time,
271
+ "limit": limit,
272
+ }
273
+
274
+ return await self._make_request("GET", url, params=params)
275
+
276
+ async def futures_ticker_24hr(self, symbol: str | None = None) -> dict | list[dict]:
277
+ """Получение статистики изменения цен и объема за 24 часа.
278
+
279
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#id-24hr-ticker-price-change-statistics
280
+ """
281
+ url = self._BASE_FUTURES_URL + "/fapi/v1/ticker/24hr"
282
+ params = {"symbol": symbol}
283
+
284
+ return await self._make_request("GET", url, params=params)
285
+
286
+ async def futures_ticker_price(self, symbol: str | None = None) -> dict | list[dict]:
287
+ """Получение последней цены тикера(ов).
288
+
289
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#symbol-price-ticker
290
+ """
291
+ url = self._BASE_FUTURES_URL + "/fapi/v1/ticker/price"
292
+ params = {"symbol": symbol}
293
+
294
+ return await self._make_request("GET", url, params=params)
295
+
296
+ async def futures_ticker_book_ticker(self, symbol: str | None = None) -> dict | list[dict]:
297
+ """Получение лучших цен bid/ask в книге ордеров.
298
+
299
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#symbol-order-book-ticker
300
+ """
301
+ url = self._BASE_FUTURES_URL + "/fapi/v1/ticker/bookTicker"
302
+ params = {"symbol": symbol}
303
+
304
+ return await self._make_request("GET", url, params=params)
305
+
306
+ # topic: futures account/trade endpoints
307
+
308
+ async def futures_position_mode(self, dual_side_position: Literal["true", "false"]) -> dict:
309
+ """Изменение режима позиции.
310
+
311
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#change-position-mode-trade
312
+ """
313
+ url = self._BASE_FUTURES_URL + "/fapi/v1/positionSide/dual"
314
+ params = {"dualSidePosition": dual_side_position}
315
+
316
+ return await self._make_request("POST", url, True, params=params)
317
+
318
+ async def futures_position_mode_get(self) -> dict:
319
+ """Получение текущего режима позиции.
320
+
321
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#get-current-position-mode-user_data
322
+ """
323
+ url = self._BASE_FUTURES_URL + "/fapi/v1/positionSide/dual"
324
+
325
+ return await self._make_request("GET", url, True)
326
+
327
+ async def futures_multi_asset_mode(self, multi_assets_margin: Literal["true", "false"]) -> dict:
328
+ """Изменение режима мультиактивной маржи.
329
+
330
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#change-multi-assets-mode-trade
331
+ """
332
+ url = self._BASE_FUTURES_URL + "/fapi/v1/multiAssetsMargin"
333
+ params = {"multiAssetsMargin": multi_assets_margin}
334
+
335
+ return await self._make_request("POST", url, True, params=params)
336
+
337
+ async def futures_multi_asset_mode_get(self) -> dict:
338
+ """Получение режима мультиактивной маржи.
339
+
340
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#get-current-multi-assets-mode-user_data
341
+ """
342
+ url = self._BASE_FUTURES_URL + "/fapi/v1/multiAssetsMargin"
343
+
344
+ return await self._make_request("GET", url, True)
345
+
346
+ async def futures_order_create(
347
+ self,
348
+ symbol: str,
349
+ side: Literal["BUY", "SELL"],
350
+ type: Literal[
351
+ "LIMIT",
352
+ "MARKET",
353
+ "STOP",
354
+ "STOP_MARKET",
355
+ "TAKE_PROFIT",
356
+ "TAKE_PROFIT_MARKET",
357
+ "TRAILING_STOP_MARKET",
358
+ ],
359
+ position_side: Literal["BOTH", "LONG", "SHORT"] | None = None,
360
+ time_in_force: str | None = None,
361
+ quantity: NumberLike | None = None,
362
+ reduce_only: Literal["true", "false"] | None = None,
363
+ price: NumberLike | None = None,
364
+ new_client_order_id: str | None = None,
365
+ stop_price: NumberLike | None = None,
366
+ close_position: Literal["true", "false"] | None = None,
367
+ activation_price: NumberLike | None = None,
368
+ callback_rate: NumberLike | None = None,
369
+ working_type: Literal["MARK_PRICE", "CONTRACT_PRICE"] | None = None,
370
+ price_protect: Literal["TRUE", "FALSE"] | None = None,
371
+ new_order_resp_type: str | None = None,
372
+ ) -> dict:
373
+ """Создание нового ордера на фьючерсах.
374
+
375
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#new-order-trade
376
+ """
377
+ url = self._BASE_FUTURES_URL + "/fapi/v1/order"
378
+ params = {
379
+ "symbol": symbol,
380
+ "side": side,
381
+ "type": type,
382
+ "positionSide": position_side,
383
+ "timeInForce": time_in_force,
384
+ "quantity": quantity,
385
+ "reduceOnly": reduce_only,
386
+ "price": price,
387
+ "newClientOrderId": new_client_order_id,
388
+ "stopPrice": stop_price,
389
+ "closePosition": close_position,
390
+ "activationPrice": activation_price,
391
+ "callbackRate": callback_rate,
392
+ "workingType": working_type,
393
+ "priceProtect": price_protect,
394
+ "newOrderRespType": new_order_resp_type,
395
+ }
396
+
397
+ return await self._make_request("POST", url, True, params=params)
398
+
399
+ async def futures_batch_orders_create(self, orders: list[dict]) -> list[dict]:
400
+ """Создание множественных ордеров одновременно на фьючерсах.
401
+
402
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#place-multiple-orders-trade
403
+ """
404
+ url = self._BASE_FUTURES_URL + "/fapi/v1/batchOrders"
405
+ params = {
406
+ "batchOrders": json.dumps(orders, separators=(",", ":")),
407
+ }
408
+
409
+ return await self._make_request("POST", url, signed=True, params=params)
410
+
411
+ async def futures_order_get(
412
+ self,
413
+ symbol: str,
414
+ order_id: int | None = None,
415
+ orig_client_order_id: str | None = None,
416
+ ) -> dict:
417
+ """Получение информации об ордере на фьючерсах.
418
+
419
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#query-order-user_data
420
+ """
421
+ url = self._BASE_FUTURES_URL + "/fapi/v1/order"
422
+ params = {
423
+ "symbol": symbol,
424
+ "orderId": order_id,
425
+ "origClientOrderId": orig_client_order_id,
426
+ }
427
+
428
+ return await self._make_request("GET", url, True, params=params)
429
+
430
+ async def futures_order_cancel(
431
+ self, symbol: str, order_id: int | None = None, orig_client_order_id: str | None = None
432
+ ) -> dict:
433
+ """Отмена активного ордера на фьючерсном рынке.
434
+
435
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#cancel-order-trade
436
+ """
437
+ url = self._BASE_FUTURES_URL + "/fapi/v1/order"
438
+ params = {
439
+ "symbol": symbol,
440
+ "orderId": order_id,
441
+ "origClientOrderId": orig_client_order_id,
442
+ }
443
+
444
+ return await self._make_request("DELETE", url, True, params=params)
445
+
446
+ async def futures_orders_cancel_all(self, symbol: str) -> dict:
447
+ """Отмена всех активных ордеров на фьючерсах.
448
+
449
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#cancel-all-open-orders-trade
450
+ """
451
+ url = self._BASE_FUTURES_URL + "/fapi/v1/allOpenOrders"
452
+ params = {"symbol": symbol}
453
+
454
+ return await self._make_request("DELETE", url, True, params=params)
455
+
456
+ async def futures_batch_orders_cancel(
457
+ self,
458
+ symbol: str,
459
+ order_id_list: list[int] | None = None,
460
+ orig_client_order_id_list: list[str] | None = None,
461
+ ) -> list[dict]:
462
+ """Отмена множественных ордеров на фьючерсах.
463
+
464
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#cancel-multiple-orders-trade
465
+ """
466
+ url = self._BASE_FUTURES_URL + "/fapi/v1/batchOrders"
467
+ params = {"symbol": symbol}
468
+
469
+ if order_id_list:
470
+ params["orderIdList"] = json.dumps(order_id_list, separators=(",", ":"))
471
+
472
+ if orig_client_order_id_list:
473
+ params["origClientOrderIdList"] = json.dumps(
474
+ orig_client_order_id_list, separators=(",", ":")
475
+ )
476
+
477
+ return await self._make_request("DELETE", url, signed=True, params=params)
478
+
479
+ async def futures_countdown_cancel_all(
480
+ self,
481
+ symbol: str,
482
+ countdown_time: int,
483
+ ) -> dict:
484
+ """Автоотмена всех активных ордеров через указанное время.
485
+
486
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#auto-cancel-all-open-orders-trade
487
+ """
488
+ url = self._BASE_FUTURES_URL + "/fapi/v1/countdownCancelAll"
489
+ params = {
490
+ "symbol": symbol,
491
+ "countdownTime": countdown_time,
492
+ }
493
+
494
+ return await self._make_request("POST", url, True, params=params)
495
+
496
+ async def futures_order_open(
497
+ self,
498
+ symbol: str,
499
+ order_id: int | None = None,
500
+ orig_client_order_id: str | None = None,
501
+ ) -> dict:
502
+ """Получение активного ордера.
503
+
504
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#query-current-open-order-user_data
505
+ """
506
+ url = self._BASE_FUTURES_URL + "/fapi/v1/openOrder"
507
+ params = {
508
+ "symbol": symbol,
509
+ "orderId": order_id,
510
+ "origClientOrderId": orig_client_order_id,
511
+ }
512
+
513
+ return await self._make_request("GET", url, True, params=params)
514
+
515
+ async def futures_orders_open(self, symbol: str | None = None) -> list[dict]:
516
+ """Получение всех активных ордеров на фьючерсах.
517
+
518
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#current-all-open-orders-user_data
519
+ """
520
+ url = self._BASE_FUTURES_URL + "/fapi/v1/openOrders"
521
+ params = {"symbol": symbol}
522
+
523
+ return await self._make_request("GET", url, True, params=params)
524
+
525
+ async def futures_orders_all(
526
+ self,
527
+ symbol: str,
528
+ order_id: int | None = None,
529
+ start_time: int | None = None,
530
+ end_time: int | None = None,
531
+ limit: int | None = None,
532
+ ) -> list[dict]:
533
+ """Получение всех ордеров на фьючерсах.
534
+
535
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#all-orders-user_data
536
+ """
537
+ url = self._BASE_FUTURES_URL + "/fapi/v1/allOrders"
538
+ params = {
539
+ "symbol": symbol,
540
+ "orderId": order_id,
541
+ "startTime": start_time,
542
+ "endTime": end_time,
543
+ "limit": limit,
544
+ }
545
+
546
+ return await self._make_request("GET", url, True, params=params)
547
+
548
+ async def futures_balance(self) -> list[dict]:
549
+ """Получение баланса фьючерсного аккаунта.
550
+
551
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#futures-account-balance-v2-user_data
552
+ """
553
+ url = self._BASE_FUTURES_URL + "/fapi/v2/balance"
554
+
555
+ return await self._make_request("GET", url, True)
556
+
557
+ async def futures_account(self) -> dict:
558
+ """Получение информации об аккаунте фьючерсов.
559
+
560
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#account-information-v4-user_data
561
+ """
562
+ url = self._BASE_FUTURES_URL + "/fapi/v4/account"
563
+
564
+ return await self._make_request("GET", url, True)
565
+
566
+ async def futures_leverage_change(self, symbol: str, leverage: int) -> dict:
567
+ """Изменение кредитного плеча на фьючерсах.
568
+
569
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#change-initial-leverage-trade
570
+ """
571
+ url = self._BASE_FUTURES_URL + "/fapi/v1/leverage"
572
+ params = {"symbol": symbol, "leverage": leverage}
573
+
574
+ return await self._make_request("POST", url, True, params=params)
575
+
576
+ async def futures_margin_type_change(self, symbol: str, margin_type: str) -> dict:
577
+ """Изменение типа маржи на фьючерсах.
578
+
579
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#change-margin-type-trade
580
+ """
581
+ url = self._BASE_FUTURES_URL + "/fapi/v1/marginType"
582
+ params = {"symbol": symbol, "marginType": margin_type}
583
+
584
+ return await self._make_request("POST", url, True, params=params)
585
+
586
+ async def futures_position_margin_modify(
587
+ self,
588
+ symbol: str,
589
+ position_side: str | None,
590
+ amount: NumberLike,
591
+ type: int,
592
+ ) -> dict:
593
+ """Изменение изолированной маржи позиции.
594
+
595
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#modify-isolated-position-margin-trade
596
+ """
597
+ url = self._BASE_FUTURES_URL + "/fapi/v1/positionMargin"
598
+ params = {
599
+ "symbol": symbol,
600
+ "positionSide": position_side,
601
+ "amount": amount,
602
+ "type": type,
603
+ }
604
+
605
+ return await self._make_request("POST", url, True, params=params)
606
+
607
+ async def futures_position_margin_history(
608
+ self,
609
+ symbol: str,
610
+ type: int | None = None,
611
+ start_time: int | None = None,
612
+ end_time: int | None = None,
613
+ limit: int | None = None,
614
+ ) -> list[dict]:
615
+ """Получение истории изменений маржи позиции.
616
+
617
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#get-position-margin-change-history-trade
618
+ """
619
+ url = self._BASE_FUTURES_URL + "/fapi/v1/positionMargin/history"
620
+ params = {
621
+ "symbol": symbol,
622
+ "type": type,
623
+ "startTime": start_time,
624
+ "endTime": end_time,
625
+ "limit": limit,
626
+ }
627
+
628
+ return await self._make_request("GET", url, True, params=params)
629
+
630
+ async def futures_position_info(self, symbol: str | None = None) -> list[dict]:
631
+ """Получение информации о позициях на фьючерсах.
632
+
633
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#position-information-v2-user_data
634
+ """
635
+ url = self._BASE_FUTURES_URL + "/fapi/v2/positionRisk"
636
+ params = {"symbol": symbol}
637
+
638
+ return await self._make_request("GET", url, True, params=params)
639
+
640
+ async def futures_my_trades(
641
+ self,
642
+ symbol: str,
643
+ start_time: int | None = None,
644
+ end_time: int | None = None,
645
+ from_id: int | None = None,
646
+ limit: int | None = None,
647
+ ) -> list[dict]:
648
+ """Получение истории торгов на фьючерсах.
649
+
650
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#account-trade-list-user_data
651
+ """
652
+ url = self._BASE_FUTURES_URL + "/fapi/v1/userTrades"
653
+ params = {
654
+ "symbol": symbol,
655
+ "startTime": start_time,
656
+ "endTime": end_time,
657
+ "fromId": from_id,
658
+ "limit": limit,
659
+ }
660
+
661
+ return await self._make_request("GET", url, True, params=params)
662
+
663
+ async def futures_income(
664
+ self,
665
+ symbol: str | None = None,
666
+ income_type: str | None = None,
667
+ start_time: int | None = None,
668
+ end_time: int | None = None,
669
+ limit: int | None = None,
670
+ ) -> list[dict]:
671
+ """Получение истории доходов на фьючерсах.
672
+
673
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#get-income-historyuser_data
674
+ """
675
+ url = self._BASE_FUTURES_URL + "/fapi/v1/income"
676
+ params = {
677
+ "symbol": symbol,
678
+ "incomeType": income_type,
679
+ "startTime": start_time,
680
+ "endTime": end_time,
681
+ "limit": limit,
682
+ }
683
+
684
+ return await self._make_request("GET", url, True, params=params)
685
+
686
+ async def futures_leverage_brackets(self, symbol: str | None = None) -> dict | list[dict]:
687
+ """Получение лимитов по плечу и нотионалу.
688
+
689
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#notional-and-leverage-brackets-user_data
690
+ """
691
+ url = self._BASE_FUTURES_URL + "/fapi/v1/leverageBracket"
692
+ params = {"symbol": symbol}
693
+
694
+ return await self._make_request("GET", url, True, params=params)
695
+
696
+ async def futures_adl_quantile(self, symbol: str | None = None) -> list[dict]:
697
+ """Получение информации об автоматической ликвидации.
698
+
699
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#position-adl-quantile-estimation-user_data
700
+ """
701
+ url = self._BASE_FUTURES_URL + "/fapi/v1/adlQuantile"
702
+ params = {"symbol": symbol}
703
+
704
+ return await self._make_request("GET", url, True, params=params)
705
+
706
+ async def futures_force_orders(
707
+ self,
708
+ symbol: str | None = None,
709
+ auto_close_type: str | None = None,
710
+ start_time: int | None = None,
711
+ end_time: int | None = None,
712
+ limit: int | None = None,
713
+ ) -> list[dict]:
714
+ """Получение истории принудительных ордеров пользователя.
715
+
716
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#users-force-orders-user_data
717
+ """
718
+ url = self._BASE_FUTURES_URL + "/fapi/v1/forceOrders"
719
+ params = {
720
+ "symbol": symbol,
721
+ "autoCloseType": auto_close_type,
722
+ "startTime": start_time,
723
+ "endTime": end_time,
724
+ "limit": limit,
725
+ }
726
+
727
+ return await self._make_request("GET", url, True, params=params)
728
+
729
+ async def futures_commission_rate(self, symbol: str) -> dict:
730
+ """Получение комиссионных ставок на фьючерсах.
731
+
732
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#user-commission-rate-user_data
733
+ """
734
+ url = self._BASE_FUTURES_URL + "/fapi/v1/commissionRate"
735
+ params = {"symbol": symbol}
736
+
737
+ return await self._make_request("GET", url, True, params=params)
738
+
739
+ # topic: futures user data streams
740
+
741
+ async def futures_listen_key(self) -> dict:
742
+ """Создание ключа прослушивания для подключения к пользовательскому вебсокету.
743
+
744
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#start-user-data-stream-user_stream
745
+ """
746
+ url = self._BASE_FUTURES_URL + "/fapi/v1/listenKey"
747
+
748
+ return await super()._make_request("POST", url, headers=self._get_headers("POST"))
749
+
750
+ async def futures_renew_listen_key(self) -> dict:
751
+ """Обновление ключа прослушивания для подключения к пользовательскому вебсокету.
752
+
753
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#keepalive-user-data-stream-user_stream
754
+ """
755
+ url = self._BASE_FUTURES_URL + "/fapi/v1/listenKey"
756
+
757
+ return await super()._make_request("PUT", url, headers=self._get_headers("PUT"))
758
+
759
+ async def futures_close_listen_key(self) -> dict:
760
+ """Закрытие ключа прослушивания для подключения к пользовательскому вебсокету.
761
+
762
+ https://docs.asterdex.com/product/aster-perpetuals/api/api-documentation#close-user-data-stream-user_stream
763
+ """
764
+ url = self._BASE_FUTURES_URL + "/fapi/v1/listenKey"
765
+
766
+ return await super()._make_request("DELETE", url, headers=self._get_headers("DELETE"))
767
+
768
+ async def open_interest(self) -> dict:
769
+ """Секретный эндпоинт откопанный в недрах фронтенда asterdex.com разработчиком @RushanWork.
770
+
771
+ Формат возвращаемых данных:
772
+ ```python
773
+ {'code': '000000',
774
+ 'message': None,
775
+ 'messageDetail': None,
776
+ 'data': [
777
+ {
778
+ 'symbol': 'TRUTHUSDT',
779
+ 'baseAsset': 'TRUTH',
780
+ 'quoteAsset': 'USDT',
781
+ 'lastPrice': 0.0126301,
782
+ 'highPrice': 0.0138825,
783
+ 'lowPrice': 0.012459,
784
+ 'baseVolume': 2011775,
785
+ 'quoteVolume': 26613.48,
786
+ 'openInterest': 85333.69964392 // В USDT
787
+ }, ...
788
+ ]
789
+ ]
790
+ ```
791
+ """
792
+ url = "https://www.asterdex.com/bapi/future/v1/public/future/aster/ticker/pair"
793
+
794
+ return await super()._make_request("GET", url, headers=self._get_headers("GET"))