repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources16d ago| #1 | """Aster DEX Client - Perpetuals and Spot Trading""" |
| #2 | |
| #3 | import json |
| #4 | import math |
| #5 | import time |
| #6 | import httpx |
| #7 | from typing import Optional, Dict, Any, List, Literal |
| #8 | from dataclasses import dataclass |
| #9 | from eth_abi import encode |
| #10 | from eth_account import Account |
| #11 | from eth_account.messages import encode_defunct |
| #12 | from web3 import Web3 |
| #13 | |
| #14 | |
| #15 | ASTER_BASE_URL = "https://fapi.asterdex.com" |
| #16 | |
| #17 | |
| #18 | @dataclass |
| #19 | class AsterPosition: |
| #20 | """Position information""" |
| #21 | symbol: str |
| #22 | position_side: str |
| #23 | position_amt: float |
| #24 | entry_price: float |
| #25 | unrealized_profit: float |
| #26 | leverage: int |
| #27 | margin_type: str |
| #28 | isolated_margin: float |
| #29 | is_auto_add_margin: bool |
| #30 | position_initial_margin: float |
| #31 | maint_margin: float |
| #32 | initial_margin: float |
| #33 | open_order_initial_margin: float |
| #34 | max_notional_value: float |
| #35 | bid_notional: float |
| #36 | ask_notional: float |
| #37 | |
| #38 | |
| #39 | @dataclass |
| #40 | class AsterOrder: |
| #41 | """Order information""" |
| #42 | order_id: int |
| #43 | symbol: str |
| #44 | status: str |
| #45 | client_order_id: str |
| #46 | price: float |
| #47 | avg_price: float |
| #48 | orig_qty: float |
| #49 | executed_qty: float |
| #50 | cumulative_quote_qty: float |
| #51 | time_in_force: str |
| #52 | type: str |
| #53 | reduce_only: bool |
| #54 | close_position: bool |
| #55 | side: str |
| #56 | position_side: str |
| #57 | stop_price: float |
| #58 | working_type: str |
| #59 | price_protect: bool |
| #60 | orig_type: str |
| #61 | update_time: int |
| #62 | |
| #63 | |
| #64 | class AsterClient: |
| #65 | """Client for Aster DEX Perpetuals and Spot Trading""" |
| #66 | |
| #67 | def __init__( |
| #68 | self, |
| #69 | user_address: str, |
| #70 | signer_address: str, |
| #71 | private_key: str, |
| #72 | base_url: str = ASTER_BASE_URL, |
| #73 | ): |
| #74 | """ |
| #75 | Initialize Aster DEX client. |
| #76 | |
| #77 | Args: |
| #78 | user_address: Main account wallet address (0x...) |
| #79 | signer_address: API wallet address (0x...) |
| #80 | private_key: Private key for signing (0x...) |
| #81 | base_url: Aster API base URL |
| #82 | """ |
| #83 | self.user = user_address |
| #84 | self.signer = signer_address |
| #85 | self.private_key = private_key |
| #86 | self.base_url = base_url |
| #87 | |
| #88 | self._client = httpx.AsyncClient( |
| #89 | base_url=self.base_url, |
| #90 | timeout=30.0 |
| #91 | ) |
| #92 | |
| #93 | def _generate_nonce(self) -> int: |
| #94 | """Generate nonce (current time in microseconds)""" |
| #95 | return math.trunc(time.time() * 1000000) |
| #96 | |
| #97 | def _trim_dict(self, my_dict: Dict[str, Any]) -> Dict[str, Any]: |
| #98 | """Convert all values to strings for signing""" |
| #99 | for key in my_dict: |
| #100 | value = my_dict[key] |
| #101 | if isinstance(value, list): |
| #102 | new_value = [] |
| #103 | for item in value: |
| #104 | if isinstance(item, dict): |
| #105 | new_value.append(json.dumps(self._trim_dict(item))) |
| #106 | else: |
| #107 | new_value.append(str(item)) |
| #108 | my_dict[key] = json.dumps(new_value) |
| #109 | continue |
| #110 | if isinstance(value, dict): |
| #111 | my_dict[key] = json.dumps(self._trim_dict(value)) |
| #112 | continue |
| #113 | my_dict[key] = str(value) |
| #114 | return my_dict |
| #115 | |
| #116 | def _sign_request(self, params: Dict[str, Any], nonce: int) -> str: |
| #117 | """ |
| #118 | Generate signature for request. |
| #119 | |
| #120 | Args: |
| #121 | params: Request parameters |
| #122 | nonce: Current timestamp in microseconds |
| #123 | |
| #124 | Returns: |
| #125 | Signature string (0x...) |
| #126 | """ |
| #127 | # Remove None values |
| #128 | params = {k: v for k, v in params.items() if v is not None} |
| #129 | |
| #130 | # Add timing parameters |
| #131 | params['recvWindow'] = 50000 |
| #132 | params['timestamp'] = int(round(time.time() * 1000)) |
| #133 | |
| #134 | # Convert to strings |
| #135 | self._trim_dict(params) |
| #136 | |
| #137 | # Generate sorted JSON string |
| #138 | json_str = json.dumps(params, sort_keys=True).replace(' ', '').replace("'", '"') |
| #139 | |
| #140 | # ABI encode |
| #141 | encoded = encode( |
| #142 | ['string', 'address', 'address', 'uint256'], |
| #143 | [json_str, self.user, self.signer, nonce] |
| #144 | ) |
| #145 | |
| #146 | # Keccak hash |
| #147 | keccak_hex = Web3.keccak(encoded).hex() |
| #148 | |
| #149 | # Sign with private key |
| #150 | signable_msg = encode_defunct(hexstr=keccak_hex) |
| #151 | signed_message = Account.sign_message( |
| #152 | signable_message=signable_msg, |
| #153 | private_key=self.private_key |
| #154 | ) |
| #155 | |
| #156 | return '0x' + signed_message.signature.hex() |
| #157 | |
| #158 | async def _request( |
| #159 | self, |
| #160 | method: str, |
| #161 | endpoint: str, |
| #162 | params: Optional[Dict[str, Any]] = None, |
| #163 | signed: bool = False |
| #164 | ) -> Dict[str, Any]: |
| #165 | """ |
| #166 | Make HTTP request to Aster API. |
| #167 | |
| #168 | Args: |
| #169 | method: HTTP method (GET, POST, DELETE) |
| #170 | endpoint: API endpoint |
| #171 | params: Request parameters |
| #172 | signed: Whether to sign the request |
| #173 | |
| #174 | Returns: |
| #175 | JSON response |
| #176 | """ |
| #177 | if params is None: |
| #178 | params = {} |
| #179 | |
| #180 | if signed: |
| #181 | nonce = self._generate_nonce() |
| #182 | signature = self._sign_request(params.copy(), nonce) |
| #183 | |
| #184 | params['nonce'] = nonce |
| #185 | params['user'] = self.user |
| #186 | params['signer'] = self.signer |
| #187 | params['signature'] = signature |
| #188 | |
| #189 | if method == 'GET': |
| #190 | response = await self._client.get(endpoint, params=params) |
| #191 | elif method == 'POST': |
| #192 | headers = { |
| #193 | 'Content-Type': 'application/x-www-form-urlencoded', |
| #194 | 'User-Agent': 'MAWD/1.0' |
| #195 | } |
| #196 | response = await self._client.post(endpoint, data=params, headers=headers) |
| #197 | elif method == 'DELETE': |
| #198 | response = await self._client.delete(endpoint, data=params) |
| #199 | else: |
| #200 | raise ValueError(f"Unsupported method: {method}") |
| #201 | |
| #202 | response.raise_for_status() |
| #203 | return response.json() |
| #204 | |
| #205 | # ================== |
| #206 | # Market Data |
| #207 | # ================== |
| #208 | |
| #209 | async def get_exchange_info(self) -> Dict[str, Any]: |
| #210 | """Get exchange information""" |
| #211 | return await self._request('GET', '/fapi/v1/exchangeInfo') |
| #212 | |
| #213 | async def get_ticker_24h(self, symbol: Optional[str] = None) -> Dict[str, Any]: |
| #214 | """Get 24hr ticker price change statistics""" |
| #215 | params = {} |
| #216 | if symbol: |
| #217 | params['symbol'] = symbol |
| #218 | return await self._request('GET', '/fapi/v1/ticker/24hr', params) |
| #219 | |
| #220 | async def get_mark_price(self, symbol: Optional[str] = None) -> Dict[str, Any]: |
| #221 | """Get mark price and funding rate""" |
| #222 | params = {} |
| #223 | if symbol: |
| #224 | params['symbol'] = symbol |
| #225 | return await self._request('GET', '/fapi/v1/premiumIndex', params) |
| #226 | |
| #227 | async def get_orderbook(self, symbol: str, limit: int = 500) -> Dict[str, Any]: |
| #228 | """Get order book""" |
| #229 | return await self._request('GET', '/fapi/v1/depth', {'symbol': symbol, 'limit': limit}) |
| #230 | |
| #231 | async def get_klines( |
| #232 | self, |
| #233 | symbol: str, |
| #234 | interval: str, |
| #235 | start_time: Optional[int] = None, |
| #236 | end_time: Optional[int] = None, |
| #237 | limit: int = 500 |
| #238 | ) -> List[List]: |
| #239 | """Get kline/candlestick data""" |
| #240 | params = { |
| #241 | 'symbol': symbol, |
| #242 | 'interval': interval, |
| #243 | 'limit': limit |
| #244 | } |
| #245 | if start_time: |
| #246 | params['startTime'] = start_time |
| #247 | if end_time: |
| #248 | params['endTime'] = end_time |
| #249 | return await self._request('GET', '/fapi/v1/klines', params) |
| #250 | |
| #251 | # ================== |
| #252 | # Trading - Perpetuals |
| #253 | # ================== |
| #254 | |
| #255 | async def place_order( |
| #256 | self, |
| #257 | symbol: str, |
| #258 | side: Literal['BUY', 'SELL'], |
| #259 | order_type: Literal['LIMIT', 'MARKET', 'STOP', 'STOP_MARKET', 'TAKE_PROFIT', 'TAKE_PROFIT_MARKET'], |
| #260 | quantity: float, |
| #261 | position_side: Literal['BOTH', 'LONG', 'SHORT'] = 'BOTH', |
| #262 | price: Optional[float] = None, |
| #263 | time_in_force: Optional[str] = 'GTC', |
| #264 | reduce_only: bool = False, |
| #265 | stop_price: Optional[float] = None, |
| #266 | close_position: bool = False, |
| #267 | ) -> Dict[str, Any]: |
| #268 | """ |
| #269 | Place a new order. |
| #270 | |
| #271 | Args: |
| #272 | symbol: Trading pair (e.g., 'BTCUSDT') |
| #273 | side: BUY or SELL |
| #274 | order_type: Order type |
| #275 | quantity: Order quantity |
| #276 | position_side: Position side (BOTH, LONG, SHORT) |
| #277 | price: Order price (required for LIMIT orders) |
| #278 | time_in_force: GTC, IOC, FOK, GTX |
| #279 | reduce_only: Reduce only |
| #280 | stop_price: Stop price (for stop orders) |
| #281 | close_position: Close position |
| #282 | |
| #283 | Returns: |
| #284 | Order response |
| #285 | """ |
| #286 | params = { |
| #287 | 'symbol': symbol, |
| #288 | 'side': side, |
| #289 | 'type': order_type, |
| #290 | 'quantity': quantity, |
| #291 | 'positionSide': position_side, |
| #292 | 'reduceOnly': reduce_only, |
| #293 | 'closePosition': close_position, |
| #294 | } |
| #295 | |
| #296 | if price is not None: |
| #297 | params['price'] = price |
| #298 | if time_in_force: |
| #299 | params['timeInForce'] = time_in_force |
| #300 | if stop_price is not None: |
| #301 | params['stopPrice'] = stop_price |
| #302 | |
| #303 | return await self._request('POST', '/fapi/v3/order', params, signed=True) |
| #304 | |
| #305 | async def cancel_order( |
| #306 | self, |
| #307 | symbol: str, |
| #308 | order_id: Optional[int] = None, |
| #309 | orig_client_order_id: Optional[str] = None |
| #310 | ) -> Dict[str, Any]: |
| #311 | """Cancel an order""" |
| #312 | params = {'symbol': symbol} |
| #313 | if order_id: |
| #314 | params['orderId'] = order_id |
| #315 | if orig_client_order_id: |
| #316 | params['origClientOrderId'] = orig_client_order_id |
| #317 | |
| #318 | return await self._request('DELETE', '/fapi/v3/order', params, signed=True) |
| #319 | |
| #320 | async def cancel_all_orders(self, symbol: str) -> Dict[str, Any]: |
| #321 | """Cancel all open orders""" |
| #322 | return await self._request('DELETE', '/fapi/v3/allOpenOrders', {'symbol': symbol}, signed=True) |
| #323 | |
| #324 | async def get_order( |
| #325 | self, |
| #326 | symbol: str, |
| #327 | order_id: Optional[int] = None, |
| #328 | orig_client_order_id: Optional[str] = None |
| #329 | ) -> Dict[str, Any]: |
| #330 | """Query order""" |
| #331 | params = {'symbol': symbol} |
| #332 | if order_id: |
| #333 | params['orderId'] = order_id |
| #334 | if orig_client_order_id: |
| #335 | params['origClientOrderId'] = orig_client_order_id |
| #336 | |
| #337 | return await self._request('GET', '/fapi/v3/order', params, signed=True) |
| #338 | |
| #339 | async def get_open_orders(self, symbol: Optional[str] = None) -> List[Dict[str, Any]]: |
| #340 | """Get all open orders""" |
| #341 | params = {} |
| #342 | if symbol: |
| #343 | params['symbol'] = symbol |
| #344 | return await self._request('GET', '/fapi/v3/openOrders', params, signed=True) |
| #345 | |
| #346 | async def get_all_orders( |
| #347 | self, |
| #348 | symbol: str, |
| #349 | order_id: Optional[int] = None, |
| #350 | start_time: Optional[int] = None, |
| #351 | end_time: Optional[int] = None, |
| #352 | limit: int = 500 |
| #353 | ) -> List[Dict[str, Any]]: |
| #354 | """Get all orders""" |
| #355 | params = {'symbol': symbol, 'limit': limit} |
| #356 | if order_id: |
| #357 | params['orderId'] = order_id |
| #358 | if start_time: |
| #359 | params['startTime'] = start_time |
| #360 | if end_time: |
| #361 | params['endTime'] = end_time |
| #362 | |
| #363 | return await self._request('GET', '/fapi/v3/allOrders', params, signed=True) |
| #364 | |
| #365 | # ================== |
| #366 | # Account |
| #367 | # ================== |
| #368 | |
| #369 | async def get_account_balance(self) -> List[Dict[str, Any]]: |
| #370 | """Get futures account balance""" |
| #371 | return await self._request('GET', '/fapi/v3/balance', {}, signed=True) |
| #372 | |
| #373 | async def get_account_info(self) -> Dict[str, Any]: |
| #374 | """Get account information""" |
| #375 | return await self._request('GET', '/fapi/v3/account', {}, signed=True) |
| #376 | |
| #377 | async def get_positions(self, symbol: Optional[str] = None) -> List[Dict[str, Any]]: |
| #378 | """Get position information""" |
| #379 | params = {} |
| #380 | if symbol: |
| #381 | params['symbol'] = symbol |
| #382 | return await self._request('GET', '/fapi/v3/positionRisk', params, signed=True) |
| #383 | |
| #384 | async def change_leverage(self, symbol: str, leverage: int) -> Dict[str, Any]: |
| #385 | """Change initial leverage""" |
| #386 | return await self._request( |
| #387 | 'POST', |
| #388 | '/fapi/v3/leverage', |
| #389 | {'symbol': symbol, 'leverage': leverage}, |
| #390 | signed=True |
| #391 | ) |
| #392 | |
| #393 | async def change_margin_type( |
| #394 | self, |
| #395 | symbol: str, |
| #396 | margin_type: Literal['ISOLATED', 'CROSSED'] |
| #397 | ) -> Dict[str, Any]: |
| #398 | """Change margin type""" |
| #399 | return await self._request( |
| #400 | 'POST', |
| #401 | '/fapi/v3/marginType', |
| #402 | {'symbol': symbol, 'marginType': margin_type}, |
| #403 | signed=True |
| #404 | ) |
| #405 | |
| #406 | async def change_position_mode(self, dual_side_position: bool) -> Dict[str, Any]: |
| #407 | """Change position mode (hedge mode)""" |
| #408 | return await self._request( |
| #409 | 'POST', |
| #410 | '/fapi/v3/positionSide/dual', |
| #411 | {'dualSidePosition': 'true' if dual_side_position else 'false'}, |
| #412 | signed=True |
| #413 | ) |
| #414 | |
| #415 | async def get_position_mode(self) -> Dict[str, Any]: |
| #416 | """Get current position mode""" |
| #417 | return await self._request('GET', '/fapi/v3/positionSide/dual', {}, signed=True) |
| #418 | |
| #419 | # ================== |
| #420 | # Transfers |
| #421 | # ================== |
| #422 | |
| #423 | async def transfer_between_futures_spot( |
| #424 | self, |
| #425 | asset: str, |
| #426 | amount: float, |
| #427 | transfer_type: Literal[1, 2] # 1: spot to futures, 2: futures to spot |
| #428 | ) -> Dict[str, Any]: |
| #429 | """Transfer between futures and spot""" |
| #430 | return await self._request( |
| #431 | 'POST', |
| #432 | '/fapi/v3/transfer', |
| #433 | {'asset': asset, 'amount': amount, 'type': transfer_type}, |
| #434 | signed=True |
| #435 | ) |
| #436 | |
| #437 | # ================== |
| #438 | # Spot Trading |
| #439 | # ================== |
| #440 | |
| #441 | async def spot_place_order( |
| #442 | self, |
| #443 | symbol: str, |
| #444 | side: Literal['BUY', 'SELL'], |
| #445 | order_type: Literal['LIMIT', 'MARKET'], |
| #446 | quantity: Optional[float] = None, |
| #447 | quote_order_qty: Optional[float] = None, |
| #448 | price: Optional[float] = None, |
| #449 | time_in_force: Optional[str] = 'GTC', |
| #450 | new_client_order_id: Optional[str] = None, |
| #451 | ) -> Dict[str, Any]: |
| #452 | """ |
| #453 | Place a spot order. |
| #454 | |
| #455 | Args: |
| #456 | symbol: Trading pair (e.g., 'BTCUSDT') |
| #457 | side: BUY or SELL |
| #458 | order_type: LIMIT or MARKET |
| #459 | quantity: Order quantity (base asset) |
| #460 | quote_order_qty: Quote asset quantity (for MARKET BUY only) |
| #461 | price: Order price (required for LIMIT orders) |
| #462 | time_in_force: GTC, IOC, FOK |
| #463 | new_client_order_id: Custom order ID |
| #464 | |
| #465 | Returns: |
| #466 | Order response |
| #467 | """ |
| #468 | params = { |
| #469 | 'symbol': symbol, |
| #470 | 'side': side, |
| #471 | 'type': order_type, |
| #472 | } |
| #473 | |
| #474 | if quantity is not None: |
| #475 | params['quantity'] = quantity |
| #476 | if quote_order_qty is not None: |
| #477 | params['quoteOrderQty'] = quote_order_qty |
| #478 | if price is not None: |
| #479 | params['price'] = price |
| #480 | if time_in_force: |
| #481 | params['timeInForce'] = time_in_force |
| #482 | if new_client_order_id: |
| #483 | params['newClientOrderId'] = new_client_order_id |
| #484 | |
| #485 | return await self._request('POST', '/api/v3/order', params, signed=True) |
| #486 | |
| #487 | async def spot_cancel_order( |
| #488 | self, |
| #489 | symbol: str, |
| #490 | order_id: Optional[int] = None, |
| #491 | orig_client_order_id: Optional[str] = None |
| #492 | ) -> Dict[str, Any]: |
| #493 | """Cancel a spot order""" |
| #494 | params = {'symbol': symbol} |
| #495 | if order_id: |
| #496 | params['orderId'] = order_id |
| #497 | if orig_client_order_id: |
| #498 | params['origClientOrderId'] = orig_client_order_id |
| #499 | |
| #500 | return await self._request('DELETE', '/api/v3/order', params, signed=True) |
| #501 | |
| #502 | async def spot_cancel_all_orders(self, symbol: str) -> Dict[str, Any]: |
| #503 | """Cancel all open spot orders""" |
| #504 | return await self._request('DELETE', '/api/v3/openOrders', {'symbol': symbol}, signed=True) |
| #505 | |
| #506 | async def spot_get_order( |
| #507 | self, |
| #508 | symbol: str, |
| #509 | order_id: Optional[int] = None, |
| #510 | orig_client_order_id: Optional[str] = None |
| #511 | ) -> Dict[str, Any]: |
| #512 | """Query spot order""" |
| #513 | params = {'symbol': symbol} |
| #514 | if order_id: |
| #515 | params['orderId'] = order_id |
| #516 | if orig_client_order_id: |
| #517 | params['origClientOrderId'] = orig_client_order_id |
| #518 | |
| #519 | return await self._request('GET', '/api/v3/order', params, signed=True) |
| #520 | |
| #521 | async def spot_get_open_orders(self, symbol: Optional[str] = None) -> List[Dict[str, Any]]: |
| #522 | """Get all open spot orders""" |
| #523 | params = {} |
| #524 | if symbol: |
| #525 | params['symbol'] = symbol |
| #526 | return await self._request('GET', '/api/v3/openOrders', params, signed=True) |
| #527 | |
| #528 | async def spot_get_all_orders( |
| #529 | self, |
| #530 | symbol: str, |
| #531 | order_id: Optional[int] = None, |
| #532 | start_time: Optional[int] = None, |
| #533 | end_time: Optional[int] = None, |
| #534 | limit: int = 500 |
| #535 | ) -> List[Dict[str, Any]]: |
| #536 | """Get all spot orders""" |
| #537 | params = {'symbol': symbol, 'limit': limit} |
| #538 | if order_id: |
| #539 | params['orderId'] = order_id |
| #540 | if start_time: |
| #541 | params['startTime'] = start_time |
| #542 | if end_time: |
| #543 | params['endTime'] = end_time |
| #544 | |
| #545 | return await self._request('GET', '/api/v3/allOrders', params, signed=True) |
| #546 | |
| #547 | async def spot_get_account(self) -> Dict[str, Any]: |
| #548 | """Get spot account information""" |
| #549 | return await self._request('GET', '/api/v3/account', {}, signed=True) |
| #550 | |
| #551 | async def spot_get_my_trades( |
| #552 | self, |
| #553 | symbol: str, |
| #554 | start_time: Optional[int] = None, |
| #555 | end_time: Optional[int] = None, |
| #556 | from_id: Optional[int] = None, |
| #557 | limit: int = 500 |
| #558 | ) -> List[Dict[str, Any]]: |
| #559 | """Get spot trade history""" |
| #560 | params = {'symbol': symbol, 'limit': limit} |
| #561 | if start_time: |
| #562 | params['startTime'] = start_time |
| #563 | if end_time: |
| #564 | params['endTime'] = end_time |
| #565 | if from_id: |
| #566 | params['fromId'] = from_id |
| #567 | |
| #568 | return await self._request('GET', '/api/v3/myTrades', params, signed=True) |
| #569 | |
| #570 | # ================== |
| #571 | # Trade History |
| #572 | # ================== |
| #573 | |
| #574 | async def get_trade_history( |
| #575 | self, |
| #576 | symbol: str, |
| #577 | start_time: Optional[int] = None, |
| #578 | end_time: Optional[int] = None, |
| #579 | from_id: Optional[int] = None, |
| #580 | limit: int = 500 |
| #581 | ) -> List[Dict[str, Any]]: |
| #582 | """Get account trade list""" |
| #583 | params = {'symbol': symbol, 'limit': limit} |
| #584 | if start_time: |
| #585 | params['startTime'] = start_time |
| #586 | if end_time: |
| #587 | params['endTime'] = end_time |
| #588 | if from_id: |
| #589 | params['fromId'] = from_id |
| #590 | |
| #591 | return await self._request('GET', '/fapi/v3/userTrades', params, signed=True) |
| #592 | |
| #593 | async def get_income_history( |
| #594 | self, |
| #595 | symbol: Optional[str] = None, |
| #596 | income_type: Optional[str] = None, |
| #597 | start_time: Optional[int] = None, |
| #598 | end_time: Optional[int] = None, |
| #599 | limit: int = 100 |
| #600 | ) -> List[Dict[str, Any]]: |
| #601 | """Get income history""" |
| #602 | params = {'limit': limit} |
| #603 | if symbol: |
| #604 | params['symbol'] = symbol |
| #605 | if income_type: |
| #606 | params['incomeType'] = income_type |
| #607 | if start_time: |
| #608 | params['startTime'] = start_time |
| #609 | if end_time: |
| #610 | params['endTime'] = end_time |
| #611 | |
| #612 | return await self._request('GET', '/fapi/v3/income', params, signed=True) |
| #613 | |
| #614 | async def close(self): |
| #615 | """Close the HTTP client""" |
| #616 | await self._client.aclose() |
| #617 | |
| #618 | async def __aenter__(self): |
| #619 | return self |
| #620 | |
| #621 | async def __aexit__(self, exc_type, exc_val, exc_tb): |
| #622 | await self.close() |
| #623 |