diff --git a/binance/client.py b/binance/client.py index 09b6652d6..d9b61f959 100755 --- a/binance/client.py +++ b/binance/client.py @@ -1,8417 +1,8419 @@ -from typing import Dict, Optional, List, Tuple - -import aiohttp -import asyncio -import hashlib -import hmac -import requests -import time -from operator import itemgetter -from urllib.parse import urlencode - - -from .helpers import interval_to_milliseconds, convert_ts_str -from .exceptions import BinanceAPIException, BinanceRequestException, NotImplementedException -from .enums import HistoricalKlinesType - - -class BaseClient: - - API_URL = 'https://api.binance.{}/api' - API_TESTNET_URL = 'https://testnet.binance.vision/api' - MARGIN_API_URL = 'https://api.binance.{}/sapi' - WEBSITE_URL = 'https://www.binance.{}' - FUTURES_URL = 'https://fapi.binance.{}/fapi' - FUTURES_TESTNET_URL = 'https://testnet.binancefuture.com/fapi' - FUTURES_DATA_URL = 'https://fapi.binance.{}/futures/data' - FUTURES_DATA_TESTNET_URL = 'https://testnet.binancefuture.com/futures/data' - FUTURES_COIN_URL = "https://dapi.binance.{}/dapi" - FUTURES_COIN_TESTNET_URL = 'https://testnet.binancefuture.com/dapi' - FUTURES_COIN_DATA_URL = "https://dapi.binance.{}/futures/data" - FUTURES_COIN_DATA_TESTNET_URL = 'https://testnet.binancefuture.com/futures/data' - OPTIONS_URL = 'https://vapi.binance.{}/vapi' - OPTIONS_TESTNET_URL = 'https://testnet.binanceops.{}/vapi' - PUBLIC_API_VERSION = 'v1' - PRIVATE_API_VERSION = 'v3' - MARGIN_API_VERSION = 'v1' - FUTURES_API_VERSION = 'v1' - FUTURES_API_VERSION2 = "v2" - OPTIONS_API_VERSION = 'v1' - - REQUEST_TIMEOUT: float = 10 - - SYMBOL_TYPE_SPOT = 'SPOT' - - ORDER_STATUS_NEW = 'NEW' - ORDER_STATUS_PARTIALLY_FILLED = 'PARTIALLY_FILLED' - ORDER_STATUS_FILLED = 'FILLED' - ORDER_STATUS_CANCELED = 'CANCELED' - ORDER_STATUS_PENDING_CANCEL = 'PENDING_CANCEL' - ORDER_STATUS_REJECTED = 'REJECTED' - ORDER_STATUS_EXPIRED = 'EXPIRED' - - KLINE_INTERVAL_1MINUTE = '1m' - KLINE_INTERVAL_3MINUTE = '3m' - KLINE_INTERVAL_5MINUTE = '5m' - KLINE_INTERVAL_15MINUTE = '15m' - KLINE_INTERVAL_30MINUTE = '30m' - KLINE_INTERVAL_1HOUR = '1h' - KLINE_INTERVAL_2HOUR = '2h' - KLINE_INTERVAL_4HOUR = '4h' - KLINE_INTERVAL_6HOUR = '6h' - KLINE_INTERVAL_8HOUR = '8h' - KLINE_INTERVAL_12HOUR = '12h' - KLINE_INTERVAL_1DAY = '1d' - KLINE_INTERVAL_3DAY = '3d' - KLINE_INTERVAL_1WEEK = '1w' - KLINE_INTERVAL_1MONTH = '1M' - - SIDE_BUY = 'BUY' - SIDE_SELL = 'SELL' - - ORDER_TYPE_LIMIT = 'LIMIT' - ORDER_TYPE_MARKET = 'MARKET' - ORDER_TYPE_STOP_LOSS = 'STOP_LOSS' - ORDER_TYPE_STOP_LOSS_LIMIT = 'STOP_LOSS_LIMIT' - ORDER_TYPE_TAKE_PROFIT = 'TAKE_PROFIT' - ORDER_TYPE_TAKE_PROFIT_LIMIT = 'TAKE_PROFIT_LIMIT' - ORDER_TYPE_LIMIT_MAKER = 'LIMIT_MAKER' - - FUTURE_ORDER_TYPE_LIMIT = 'LIMIT' - FUTURE_ORDER_TYPE_MARKET = 'MARKET' - FUTURE_ORDER_TYPE_STOP = 'STOP' - FUTURE_ORDER_TYPE_STOP_MARKET = 'STOP_MARKET' - FUTURE_ORDER_TYPE_TAKE_PROFIT = 'TAKE_PROFIT' - FUTURE_ORDER_TYPE_TAKE_PROFIT_MARKET = 'TAKE_PROFIT_MARKET' - FUTURE_ORDER_TYPE_LIMIT_MAKER = 'LIMIT_MAKER' - - TIME_IN_FORCE_GTC = 'GTC' # Good till cancelled - TIME_IN_FORCE_IOC = 'IOC' # Immediate or cancel - TIME_IN_FORCE_FOK = 'FOK' # Fill or kill - - ORDER_RESP_TYPE_ACK = 'ACK' - ORDER_RESP_TYPE_RESULT = 'RESULT' - ORDER_RESP_TYPE_FULL = 'FULL' - - # For accessing the data returned by Client.aggregate_trades(). - AGG_ID = 'a' - AGG_PRICE = 'p' - AGG_QUANTITY = 'q' - AGG_FIRST_TRADE_ID = 'f' - AGG_LAST_TRADE_ID = 'l' - AGG_TIME = 'T' - AGG_BUYER_MAKES = 'm' - AGG_BEST_MATCH = 'M' - - # new asset transfer api enum - SPOT_TO_FIAT = "MAIN_C2C" - SPOT_TO_USDT_FUTURE = "MAIN_UMFUTURE" - SPOT_TO_COIN_FUTURE = "MAIN_CMFUTURE" - SPOT_TO_MARGIN_CROSS = "MAIN_MARGIN" - SPOT_TO_MINING = "MAIN_MINING" - FIAT_TO_SPOT = "C2C_MAIN" - FIAT_TO_USDT_FUTURE = "C2C_UMFUTURE" - FIAT_TO_MINING = "C2C_MINING" - USDT_FUTURE_TO_SPOT = "UMFUTURE_MAIN" - USDT_FUTURE_TO_FIAT = "UMFUTURE_C2C" - USDT_FUTURE_TO_MARGIN_CROSS = "UMFUTURE_MARGIN" - COIN_FUTURE_TO_SPOT = "CMFUTURE_MAIN" - MARGIN_CROSS_TO_SPOT = "MARGIN_MAIN" - MARGIN_CROSS_TO_USDT_FUTURE = "MARGIN_UMFUTURE" - MINING_TO_SPOT = "MINING_MAIN" - MINING_TO_USDT_FUTURE = "MINING_UMFUTURE" - MINING_TO_FIAT = "MINING_C2C" - - def __init__( - self, api_key: Optional[str] = None, api_secret: Optional[str] = None, - requests_params: Dict[str, str] = None, tld: str = 'com', - testnet: bool = False - ): - """Binance API Client constructor - - :param api_key: Api Key - :type api_key: str. - :param api_secret: Api Secret - :type api_secret: str. - :param requests_params: optional - Dictionary of requests params to use for all calls - :type requests_params: dict. - :param testnet: Use testnet environment - only available for vanilla options at the moment - :type testnet: bool - - """ - - self.tld = tld - self.API_URL = self.API_URL.format(tld) - self.MARGIN_API_URL = self.MARGIN_API_URL.format(tld) - self.WEBSITE_URL = self.WEBSITE_URL.format(tld) - self.FUTURES_URL = self.FUTURES_URL.format(tld) - self.FUTURES_DATA_URL = self.FUTURES_DATA_URL.format(tld) - self.FUTURES_COIN_URL = self.FUTURES_COIN_URL.format(tld) - self.FUTURES_COIN_DATA_URL = self.FUTURES_COIN_DATA_URL.format(tld) - self.OPTIONS_URL = self.OPTIONS_URL.format(tld) - self.OPTIONS_TESTNET_URL = self.OPTIONS_TESTNET_URL.format(tld) - - self.API_KEY = api_key - self.API_SECRET = api_secret - self.session = self._init_session() - self._requests_params = requests_params - self.response = None - self.testnet = testnet - self.timestamp_offset = 0 - - def _get_headers(self) -> Dict: - headers = { - 'Accept': 'application/json', - 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36', # noqa - } - if self.API_KEY: - assert self.API_KEY - headers['X-MBX-APIKEY'] = self.API_KEY - return headers - - def _init_session(self): - raise NotImplementedError - - def _create_api_uri(self, path: str, signed: bool = True, version: str = PUBLIC_API_VERSION) -> str: - url = self.API_URL - if self.testnet: - url = self.API_TESTNET_URL - v = self.PRIVATE_API_VERSION if signed else version - return url + '/' + v + '/' + path - - def _create_margin_api_uri(self, path: str, version: str = MARGIN_API_VERSION) -> str: - return self.MARGIN_API_URL + '/' + version + '/' + path - - def _create_website_uri(self, path: str) -> str: - return self.WEBSITE_URL + '/' + path - - def _create_futures_api_uri(self, path: str) -> str: - url = self.FUTURES_URL - if self.testnet: - url = self.FUTURES_TESTNET_URL - return url + '/' + self.FUTURES_API_VERSION + '/' + path - - def _create_futures_data_api_uri(self, path: str) -> str: - url = self.FUTURES_DATA_URL - if self.testnet: - url = self.FUTURES_DATA_TESTNET_URL - return url + '/' + path - - def _create_futures_coin_api_url(self, path: str, version=1) -> str: - url = self.FUTURES_COIN_URL - if self.testnet: - url = self.FUTURES_COIN_TESTNET_URL - options = {1: self.FUTURES_API_VERSION, 2: self.FUTURES_API_VERSION2} - return url + "/" + options[version] + "/" + path - - def _create_futures_coin_data_api_url(self, path: str, version=1) -> str: - url = self.FUTURES_COIN_DATA_URL - if self.testnet: - url = self.FUTURES_COIN_DATA_TESTNET_URL - return url + "/" + path - - def _create_options_api_uri(self, path: str) -> str: - url = self.OPTIONS_URL - if self.testnet: - url = self.OPTIONS_TESTNET_URL - return url + '/' + self.OPTIONS_API_VERSION + '/' + path - - def _generate_signature(self, data: Dict) -> str: - - ordered_data = self._order_params(data) - query_string = '&'.join([f"{d[0]}={d[1]}" for d in ordered_data]) - m = hmac.new(self.API_SECRET.encode('utf-8'), query_string.encode('utf-8'), hashlib.sha256) - return m.hexdigest() - - @staticmethod - def _order_params(data: Dict) -> List[Tuple[str, str]]: - """Convert params to list with signature as last element - - :param data: - :return: - - """ - data = dict(filter(lambda el: el[1] is not None, data.items())) - has_signature = False - params = [] - for key, value in data.items(): - if key == 'signature': - has_signature = True - else: - params.append((key, str(value))) - # sort parameters by key - params.sort(key=itemgetter(0)) - if has_signature: - params.append(('signature', data['signature'])) - return params - - def _get_request_kwargs(self, method, signed: bool, force_params: bool = False, **kwargs) -> Dict: - - # set default requests timeout - kwargs['timeout'] = self.REQUEST_TIMEOUT - - # add our global requests params - if self._requests_params: - kwargs.update(self._requests_params) - - data = kwargs.get('data', None) - if data and isinstance(data, dict): - kwargs['data'] = data - - # find any requests params passed and apply them - if 'requests_params' in kwargs['data']: - # merge requests params into kwargs - kwargs.update(kwargs['data']['requests_params']) - del(kwargs['data']['requests_params']) - - if signed: - # generate signature - kwargs['data']['timestamp'] = int(time.time() * 1000 + self.timestamp_offset) - kwargs['data']['signature'] = self._generate_signature(kwargs['data']) - - # sort get and post params to match signature order - if data: - # sort post params and remove any arguments with values of None - kwargs['data'] = self._order_params(kwargs['data']) - # Remove any arguments with values of None. - null_args = [i for i, (key, value) in enumerate(kwargs['data']) if value is None] - for i in reversed(null_args): - del kwargs['data'][i] - - # if get request assign data array to params value for requests lib - if data and (method == 'get' or force_params): - kwargs['params'] = '&'.join('%s=%s' % (data[0], data[1]) for data in kwargs['data']) - del(kwargs['data']) - - return kwargs - - -class Client(BaseClient): - - def __init__( - self, api_key: Optional[str] = None, api_secret: Optional[str] = None, - requests_params: Dict[str, str] = None, tld: str = 'com', - testnet: bool = False - ): - - super().__init__(api_key, api_secret, requests_params, tld, testnet) - - # init DNS and SSL cert - self.ping() - - def _init_session(self) -> requests.Session: - - headers = self._get_headers() - - session = requests.session() - session.headers.update(headers) - return session - - def _request(self, method, uri: str, signed: bool, force_params: bool = False, **kwargs): - - kwargs = self._get_request_kwargs(method, signed, force_params, **kwargs) - - self.response = getattr(self.session, method)(uri, **kwargs) - return self._handle_response(self.response) - - @staticmethod - def _handle_response(response: requests.Response): - """Internal helper for handling API responses from the Binance server. - Raises the appropriate exceptions when necessary; otherwise, returns the - response. - """ - if not (200 <= response.status_code < 300): - raise BinanceAPIException(response, response.status_code, response.text) - try: - return response.json() - except ValueError: - raise BinanceRequestException('Invalid Response: %s' % response.text) - - def _request_api( - self, method, path: str, signed: bool = False, version=BaseClient.PUBLIC_API_VERSION, **kwargs - ): - uri = self._create_api_uri(path, signed, version) - return self._request(method, uri, signed, **kwargs) - - def _request_futures_api(self, method, path, signed=False, **kwargs) -> Dict: - uri = self._create_futures_api_uri(path) - - return self._request(method, uri, signed, True, **kwargs) - - def _request_futures_data_api(self, method, path, signed=False, **kwargs) -> Dict: - uri = self._create_futures_data_api_uri(path) - - return self._request(method, uri, signed, True, **kwargs) - - def _request_futures_coin_api(self, method, path, signed=False, version=1, **kwargs) -> Dict: - uri = self._create_futures_coin_api_url(path, version=version) - - return self._request(method, uri, signed, True, **kwargs) - - def _request_futures_coin_data_api(self, method, path, signed=False, version=1, **kwargs) -> Dict: - uri = self._create_futures_coin_data_api_url(path, version=version) - - return self._request(method, uri, signed, True, **kwargs) - - def _request_options_api(self, method, path, signed=False, **kwargs) -> Dict: - uri = self._create_options_api_uri(path) - - return self._request(method, uri, signed, True, **kwargs) - - def _request_margin_api(self, method, path, signed=False, **kwargs) -> Dict: - uri = self._create_margin_api_uri(path) - - return self._request(method, uri, signed, **kwargs) - - def _request_website(self, method, path, signed=False, **kwargs) -> Dict: - uri = self._create_website_uri(path) - return self._request(method, uri, signed, **kwargs) - - def _get(self, path, signed=False, version=BaseClient.PUBLIC_API_VERSION, **kwargs): - return self._request_api('get', path, signed, version, **kwargs) - - def _post(self, path, signed=False, version=BaseClient.PUBLIC_API_VERSION, **kwargs) -> Dict: - return self._request_api('post', path, signed, version, **kwargs) - - def _put(self, path, signed=False, version=BaseClient.PUBLIC_API_VERSION, **kwargs) -> Dict: - return self._request_api('put', path, signed, version, **kwargs) - - def _delete(self, path, signed=False, version=BaseClient.PUBLIC_API_VERSION, **kwargs) -> Dict: - return self._request_api('delete', path, signed, version, **kwargs) - - # Exchange Endpoints - - def get_products(self) -> Dict: - """Return list of products currently listed on Binance - - Use get_exchange_info() call instead - - :returns: list - List of product dictionaries - - :raises: BinanceRequestException, BinanceAPIException - - """ - products = self._request_website('get', 'exchange-api/v1/public/asset-service/product/get-products') - return products - - def get_exchange_info(self) -> Dict: - """Return rate limits and list of symbols - - :returns: list - List of product dictionaries - - .. code-block:: python - - { - "timezone": "UTC", - "serverTime": 1508631584636, - "rateLimits": [ - { - "rateLimitType": "REQUESTS", - "interval": "MINUTE", - "limit": 1200 - }, - { - "rateLimitType": "ORDERS", - "interval": "SECOND", - "limit": 10 - }, - { - "rateLimitType": "ORDERS", - "interval": "DAY", - "limit": 100000 - } - ], - "exchangeFilters": [], - "symbols": [ - { - "symbol": "ETHBTC", - "status": "TRADING", - "baseAsset": "ETH", - "baseAssetPrecision": 8, - "quoteAsset": "BTC", - "quotePrecision": 8, - "orderTypes": ["LIMIT", "MARKET"], - "icebergAllowed": false, - "filters": [ - { - "filterType": "PRICE_FILTER", - "minPrice": "0.00000100", - "maxPrice": "100000.00000000", - "tickSize": "0.00000100" - }, { - "filterType": "LOT_SIZE", - "minQty": "0.00100000", - "maxQty": "100000.00000000", - "stepSize": "0.00100000" - }, { - "filterType": "MIN_NOTIONAL", - "minNotional": "0.00100000" - } - ] - } - ] - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - - return self._get('exchangeInfo', version=self.PRIVATE_API_VERSION) - - def get_symbol_info(self, symbol) -> Optional[Dict]: - """Return information about a symbol - - :param symbol: required e.g BNBBTC - :type symbol: str - - :returns: Dict if found, None if not - - .. code-block:: python - - { - "symbol": "ETHBTC", - "status": "TRADING", - "baseAsset": "ETH", - "baseAssetPrecision": 8, - "quoteAsset": "BTC", - "quotePrecision": 8, - "orderTypes": ["LIMIT", "MARKET"], - "icebergAllowed": false, - "filters": [ - { - "filterType": "PRICE_FILTER", - "minPrice": "0.00000100", - "maxPrice": "100000.00000000", - "tickSize": "0.00000100" - }, { - "filterType": "LOT_SIZE", - "minQty": "0.00100000", - "maxQty": "100000.00000000", - "stepSize": "0.00100000" - }, { - "filterType": "MIN_NOTIONAL", - "minNotional": "0.00100000" - } - ] - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - - res = self.get_exchange_info() - - for item in res['symbols']: - if item['symbol'] == symbol.upper(): - return item - - return None - - # General Endpoints - - def ping(self) -> Dict: - """Test connectivity to the Rest API. - - https://binance-docs.github.io/apidocs/spot/en/#test-connectivity - - :returns: Empty array - - .. code-block:: python - - {} - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._get('ping', version=self.PRIVATE_API_VERSION) - - def get_server_time(self) -> Dict: - """Test connectivity to the Rest API and get the current server time. - - https://binance-docs.github.io/apidocs/spot/en/#check-server-time - - :returns: Current server time - - .. code-block:: python - - { - "serverTime": 1499827319559 - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._get('time', version=self.PRIVATE_API_VERSION) - - # Market Data Endpoints - - def get_all_tickers(self) -> List[Dict[str, str]]: - """Latest price for all symbols. - - https://binance-docs.github.io/apidocs/spot/en/#symbol-price-ticker - - :returns: List of market tickers - - .. code-block:: python - - [ - { - "symbol": "LTCBTC", - "price": "4.00000200" - }, - { - "symbol": "ETHBTC", - "price": "0.07946600" - } - ] - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._get('ticker/price', version=self.PRIVATE_API_VERSION) - - def get_orderbook_tickers(self) -> Dict: - """Best price/qty on the order book for all symbols. - - https://binance-docs.github.io/apidocs/spot/en/#symbol-order-book-ticker - - :param symbol: optional - :type symbol: str - - :returns: List of order book market entries - - .. code-block:: python - - [ - { - "symbol": "LTCBTC", - "bidPrice": "4.00000000", - "bidQty": "431.00000000", - "askPrice": "4.00000200", - "askQty": "9.00000000" - }, - { - "symbol": "ETHBTC", - "bidPrice": "0.07946700", - "bidQty": "9.00000000", - "askPrice": "100000.00000000", - "askQty": "1000.00000000" - } - ] - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._get('ticker/bookTicker', version=self.PRIVATE_API_VERSION) - - def get_order_book(self, **params) -> Dict: - """Get the Order Book for the market - - https://binance-docs.github.io/apidocs/spot/en/#order-book - - :param symbol: required - :type symbol: str - :param limit: Default 100; max 1000 - :type limit: int - - :returns: API response - - .. code-block:: python - - { - "lastUpdateId": 1027024, - "bids": [ - [ - "4.00000000", # PRICE - "431.00000000", # QTY - [] # Can be ignored - ] - ], - "asks": [ - [ - "4.00000200", - "12.00000000", - [] - ] - ] - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._get('depth', data=params, version=self.PRIVATE_API_VERSION) - - def get_recent_trades(self, **params) -> Dict: - """Get recent trades (up to last 500). - - https://binance-docs.github.io/apidocs/spot/en/#recent-trades-list - - :param symbol: required - :type symbol: str - :param limit: Default 500; max 1000. - :type limit: int - - :returns: API response - - .. code-block:: python - - [ - { - "id": 28457, - "price": "4.00000100", - "qty": "12.00000000", - "time": 1499865549590, - "isBuyerMaker": true, - "isBestMatch": true - } - ] - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._get('trades', data=params) - - def get_historical_trades(self, **params) -> Dict: - """Get older trades. - - https://binance-docs.github.io/apidocs/spot/en/#old-trade-lookup - - :param symbol: required - :type symbol: str - :param limit: Default 500; max 1000. - :type limit: int - :param fromId: TradeId to fetch from. Default gets most recent trades. - :type fromId: str - - :returns: API response - - .. code-block:: python - - [ - { - "id": 28457, - "price": "4.00000100", - "qty": "12.00000000", - "time": 1499865549590, - "isBuyerMaker": true, - "isBestMatch": true - } - ] - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._get('historicalTrades', data=params, version=self.PRIVATE_API_VERSION) - - def get_aggregate_trades(self, **params) -> Dict: - """Get compressed, aggregate trades. Trades that fill at the time, - from the same order, with the same price will have the quantity aggregated. - - https://binance-docs.github.io/apidocs/spot/en/#compressed-aggregate-trades-list - - :param symbol: required - :type symbol: str - :param fromId: ID to get aggregate trades from INCLUSIVE. - :type fromId: str - :param startTime: Timestamp in ms to get aggregate trades from INCLUSIVE. - :type startTime: int - :param endTime: Timestamp in ms to get aggregate trades until INCLUSIVE. - :type endTime: int - :param limit: Default 500; max 1000. - :type limit: int - - :returns: API response - - .. code-block:: python - - [ - { - "a": 26129, # Aggregate tradeId - "p": "0.01633102", # Price - "q": "4.70443515", # Quantity - "f": 27781, # First tradeId - "l": 27781, # Last tradeId - "T": 1498793709153, # Timestamp - "m": true, # Was the buyer the maker? - "M": true # Was the trade the best price match? - } - ] - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._get('aggTrades', data=params, version=self.PRIVATE_API_VERSION) - - def aggregate_trade_iter(self, symbol: str, start_str=None, last_id=None): - """Iterate over aggregate trade data from (start_time or last_id) to - the end of the history so far. - - If start_time is specified, start with the first trade after - start_time. Meant to initialise a local cache of trade data. - - If last_id is specified, start with the trade after it. This is meant - for updating a pre-existing local trade data cache. - - Only allows start_str or last_id—not both. Not guaranteed to work - right if you're running more than one of these simultaneously. You - will probably hit your rate limit. - - See dateparser docs for valid start and end string formats http://dateparser.readthedocs.io/en/latest/ - - If using offset strings for dates add "UTC" to date string e.g. "now UTC", "11 hours ago UTC" - - :param symbol: Symbol string e.g. ETHBTC - :type symbol: str - :param start_str: Start date string in UTC format or timestamp in milliseconds. The iterator will - return the first trade occurring later than this time. - :type start_str: str|int - :param last_id: aggregate trade ID of the last known aggregate trade. - Not a regular trade ID. See https://binance-docs.github.io/apidocs/spot/en/#compressed-aggregate-trades-list - - :returns: an iterator of JSON objects, one per trade. The format of - each object is identical to Client.aggregate_trades(). - - :type last_id: int - """ - if start_str is not None and last_id is not None: - raise ValueError( - 'start_time and last_id may not be simultaneously specified.') - - # If there's no last_id, get one. - if last_id is None: - # Without a last_id, we actually need the first trade. Normally, - # we'd get rid of it. See the next loop. - if start_str is None: - trades = self.get_aggregate_trades(symbol=symbol, fromId=0) - else: - # The difference between startTime and endTime should be less - # or equal than an hour and the result set should contain at - # least one trade. - start_ts = convert_ts_str(start_str) - # If the resulting set is empty (i.e. no trades in that interval) - # then we just move forward hour by hour until we find at least one - # trade or reach present moment - while True: - end_ts = start_ts + (60 * 60 * 1000) - trades = self.get_aggregate_trades( - symbol=symbol, - startTime=start_ts, - endTime=end_ts) - if len(trades) > 0: - break - # If we reach present moment and find no trades then there is - # nothing to iterate, so we're done - if end_ts > int(time.time() * 1000): - return - start_ts = end_ts - for t in trades: - yield t - last_id = trades[-1][self.AGG_ID] - - while True: - # There is no need to wait between queries, to avoid hitting the - # rate limit. We're using blocking IO, and as long as we're the - # only thread running calls like this, Binance will automatically - # add the right delay time on their end, forcing us to wait for - # data. That really simplifies this function's job. Binance is - # fucking awesome. - trades = self.get_aggregate_trades(symbol=symbol, fromId=last_id) - # fromId=n returns a set starting with id n, but we already have - # that one. So get rid of the first item in the result set. - trades = trades[1:] - if len(trades) == 0: - return - for t in trades: - yield t - last_id = trades[-1][self.AGG_ID] - - def get_klines(self, **params) -> Dict: - """Kline/candlestick bars for a symbol. Klines are uniquely identified by their open time. - - https://binance-docs.github.io/apidocs/spot/en/#kline-candlestick-data - - :param symbol: required - :type symbol: str - :param interval: - - :type interval: str - :param limit: - Default 500; max 1000. - :type limit: int - :param startTime: - :type startTime: int - :param endTime: - :type endTime: int - - :returns: API response - - .. code-block:: python - - [ - [ - 1499040000000, # Open time - "0.01634790", # Open - "0.80000000", # High - "0.01575800", # Low - "0.01577100", # Close - "148976.11427815", # Volume - 1499644799999, # Close time - "2434.19055334", # Quote asset volume - 308, # Number of trades - "1756.87402397", # Taker buy base asset volume - "28.46694368", # Taker buy quote asset volume - "17928899.62484339" # Can be ignored - ] - ] - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._get('klines', data=params, version=self.PRIVATE_API_VERSION) - - def _klines(self, klines_type: HistoricalKlinesType = HistoricalKlinesType.SPOT, **params) -> Dict: - """Get klines of spot (get_klines) or futures (futures_klines) endpoints. - - :param klines_type: Historical klines type: SPOT or FUTURES - :type klines_type: HistoricalKlinesType - - :return: klines, see get_klines - - """ - if 'endTime' in params and not params['endTime']: - del params['endTime'] - - if HistoricalKlinesType.SPOT == klines_type: - return self.get_klines(**params) - elif HistoricalKlinesType.FUTURES == klines_type: - return self.futures_klines(**params) - else: - raise NotImplementedException(klines_type) - - def _get_earliest_valid_timestamp(self, symbol, interval, klines_type: HistoricalKlinesType = HistoricalKlinesType.SPOT): - """Get earliest valid open timestamp from Binance - - :param symbol: Name of symbol pair e.g BNBBTC - :type symbol: str - :param interval: Binance Kline interval - :type interval: str - :param klines_type: Historical klines type: SPOT or FUTURES - :type klines_type: HistoricalKlinesType - - :return: first valid timestamp - - """ - kline = self._klines( - klines_type=klines_type, - symbol=symbol, - interval=interval, - limit=1, - startTime=0, - endTime=int(time.time() * 1000) - ) - return kline[0][0] - - def get_historical_klines(self, symbol, interval, start_str, end_str=None, limit=500, - klines_type: HistoricalKlinesType = HistoricalKlinesType.SPOT): - """Get Historical Klines from Binance - - :param symbol: Name of symbol pair e.g BNBBTC - :type symbol: str - :param interval: Binance Kline interval - :type interval: str - :param start_str: Start date string in UTC format or timestamp in milliseconds - :type start_str: str|int - :param end_str: optional - end date string in UTC format or timestamp in milliseconds (default will fetch everything up to now) - :type end_str: str|int - :param limit: Default 500; max 1000. - :type limit: int - :param klines_type: Historical klines type: SPOT or FUTURES - :type klines_type: HistoricalKlinesType - - :return: list of OHLCV values - - """ - return self._historical_klines(symbol, interval, start_str, end_str=end_str, limit=limit, klines_type=klines_type) - - def _historical_klines(self, symbol, interval, start_str, end_str=None, limit=500, - klines_type: HistoricalKlinesType = HistoricalKlinesType.SPOT): - """Get Historical Klines from Binance (spot or futures) - - See dateparser docs for valid start and end string formats http://dateparser.readthedocs.io/en/latest/ - - If using offset strings for dates add "UTC" to date string e.g. "now UTC", "11 hours ago UTC" - - :param symbol: Name of symbol pair e.g BNBBTC - :type symbol: str - :param interval: Binance Kline interval - :type interval: str - :param start_str: Start date string in UTC format or timestamp in milliseconds - :type start_str: str|int - :param end_str: optional - end date string in UTC format or timestamp in milliseconds (default will fetch everything up to now) - :type end_str: None|str|int - :param limit: Default 500; max 1000. - :type limit: int - :param klines_type: Historical klines type: SPOT or FUTURES - :type klines_type: HistoricalKlinesType - - :return: list of OHLCV values - - """ - # init our list - output_data = [] - - # convert interval to useful value in seconds - timeframe = interval_to_milliseconds(interval) - - start_ts = convert_ts_str(start_str) - - # establish first available start timestamp - first_valid_ts = self._get_earliest_valid_timestamp(symbol, interval, klines_type) - start_ts = max(start_ts, first_valid_ts) - - # if an end time was passed convert it - end_ts = convert_ts_str(end_str) - - idx = 0 - while True: - # fetch the klines from start_ts up to max 500 entries or the end_ts if set - temp_data = self._klines( - klines_type=klines_type, - symbol=symbol, - interval=interval, - limit=limit, - startTime=start_ts, - endTime=end_ts - ) - - # handle the case where exactly the limit amount of data was returned last loop - if not len(temp_data): - break - - # append this loops data to our output data - output_data += temp_data - - # set our start timestamp using the last value in the array - start_ts = temp_data[-1][0] - - idx += 1 - # check if we received less than the required limit and exit the loop - if len(temp_data) < limit: - # exit the while loop - break - - # increment next call by our timeframe - start_ts += timeframe - - # sleep after every 3rd call to be kind to the API - if idx % 3 == 0: - time.sleep(1) - - return output_data - - def get_historical_klines_generator(self, symbol, interval, start_str, end_str=None, - klines_type: HistoricalKlinesType = HistoricalKlinesType.SPOT): - """Get Historical Klines generator from Binance - - :param symbol: Name of symbol pair e.g BNBBTC - :type symbol: str - :param interval: Binance Kline interval - :type interval: str - :param start_str: Start date string in UTC format or timestamp in milliseconds - :type start_str: str|int - :param end_str: optional - end date string in UTC format or timestamp in milliseconds (default will fetch everything up to now) - :type end_str: str|int - :param klines_type: Historical klines type: SPOT or FUTURES - :type klines_type: HistoricalKlinesType - - :return: generator of OHLCV values - - """ - - return self._historical_klines_generator(symbol, interval, start_str, end_str=end_str, klines_type=klines_type) - - def _historical_klines_generator(self, symbol, interval, start_str, end_str=None, - klines_type: HistoricalKlinesType = HistoricalKlinesType.SPOT): - """Get Historical Klines generator from Binance (spot or futures) - - See dateparser docs for valid start and end string formats http://dateparser.readthedocs.io/en/latest/ - - If using offset strings for dates add "UTC" to date string e.g. "now UTC", "11 hours ago UTC" - - :param symbol: Name of symbol pair e.g BNBBTC - :type symbol: str - :param interval: Binance Kline interval - :type interval: str - :param start_str: Start date string in UTC format or timestamp in milliseconds - :type start_str: str|int - :param end_str: optional - end date string in UTC format or timestamp in milliseconds (default will fetch everything up to now) - :type end_str: str|int - :param klines_type: Historical klines type: SPOT or FUTURES - :type klines_type: HistoricalKlinesType - - :return: generator of OHLCV values - - """ - # setup the max limit - limit = 500 - - # convert interval to useful value in seconds - timeframe = interval_to_milliseconds(interval) - - # convert our date strings to milliseconds - start_ts = convert_ts_str(start_str) - - # establish first available start timestamp - first_valid_ts = self._get_earliest_valid_timestamp(symbol, interval, klines_type) - start_ts = max(start_ts, first_valid_ts) - - # if an end time was passed convert it - end_ts = convert_ts_str(end_str) - - idx = 0 - while True: - # fetch the klines from start_ts up to max 500 entries or the end_ts if set - output_data = self._klines( - klines_type=klines_type, - symbol=symbol, - interval=interval, - limit=limit, - startTime=start_ts, - endTime=end_ts - ) - - # handle the case where exactly the limit amount of data was returned last loop - if not len(output_data): - break - - # yield data - for o in output_data: - yield o - - # set our start timestamp using the last value in the array - start_ts = output_data[-1][0] - - idx += 1 - # check if we received less than the required limit and exit the loop - if len(output_data) < limit: - # exit the while loop - break - - # increment next call by our timeframe - start_ts += timeframe - - # sleep after every 3rd call to be kind to the API - if idx % 3 == 0: - time.sleep(1) - - def get_avg_price(self, **params): - """Current average price for a symbol. - - https://binance-docs.github.io/apidocs/spot/en/#current-average-price - - :param symbol: - :type symbol: str - - :returns: API response - - .. code-block:: python - - { - "mins": 5, - "price": "9.35751834" - } - """ - return self._get('avgPrice', data=params, version=self.PRIVATE_API_VERSION) - - def get_ticker(self, **params): - """24 hour price change statistics. - - https://binance-docs.github.io/apidocs/spot/en/#24hr-ticker-price-change-statistics - - :param symbol: - :type symbol: str - - :returns: API response - - .. code-block:: python - - { - "priceChange": "-94.99999800", - "priceChangePercent": "-95.960", - "weightedAvgPrice": "0.29628482", - "prevClosePrice": "0.10002000", - "lastPrice": "4.00000200", - "bidPrice": "4.00000000", - "askPrice": "4.00000200", - "openPrice": "99.00000000", - "highPrice": "100.00000000", - "lowPrice": "0.10000000", - "volume": "8913.30000000", - "openTime": 1499783499040, - "closeTime": 1499869899040, - "fristId": 28385, # First tradeId - "lastId": 28460, # Last tradeId - "count": 76 # Trade count - } - - OR - - .. code-block:: python - - [ - { - "priceChange": "-94.99999800", - "priceChangePercent": "-95.960", - "weightedAvgPrice": "0.29628482", - "prevClosePrice": "0.10002000", - "lastPrice": "4.00000200", - "bidPrice": "4.00000000", - "askPrice": "4.00000200", - "openPrice": "99.00000000", - "highPrice": "100.00000000", - "lowPrice": "0.10000000", - "volume": "8913.30000000", - "openTime": 1499783499040, - "closeTime": 1499869899040, - "fristId": 28385, # First tradeId - "lastId": 28460, # Last tradeId - "count": 76 # Trade count - } - ] - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._get('ticker/24hr', data=params, version=self.PRIVATE_API_VERSION) - - def get_symbol_ticker(self, **params): - """Latest price for a symbol or symbols. - - https://binance-docs.github.io/apidocs/spot/en/#symbol-price-ticker - - :param symbol: - :type symbol: str - - :returns: API response - - .. code-block:: python - - { - "symbol": "LTCBTC", - "price": "4.00000200" - } - - OR - - .. code-block:: python - - [ - { - "symbol": "LTCBTC", - "price": "4.00000200" - }, - { - "symbol": "ETHBTC", - "price": "0.07946600" - } - ] - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._get('ticker/price', data=params, version=self.PRIVATE_API_VERSION) - - def get_orderbook_ticker(self, **params): - """Latest price for a symbol or symbols. - - https://binance-docs.github.io/apidocs/spot/en/#symbol-order-book-ticker - - :param symbol: - :type symbol: str - - :returns: API response - - .. code-block:: python - - { - "symbol": "LTCBTC", - "bidPrice": "4.00000000", - "bidQty": "431.00000000", - "askPrice": "4.00000200", - "askQty": "9.00000000" - } - - OR - - .. code-block:: python - - [ - { - "symbol": "LTCBTC", - "bidPrice": "4.00000000", - "bidQty": "431.00000000", - "askPrice": "4.00000200", - "askQty": "9.00000000" - }, - { - "symbol": "ETHBTC", - "bidPrice": "0.07946700", - "bidQty": "9.00000000", - "askPrice": "100000.00000000", - "askQty": "1000.00000000" - } - ] - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._get('ticker/bookTicker', data=params, version=self.PRIVATE_API_VERSION) - - # Account Endpoints - - def create_order(self, **params): - """Send in a new order - - Any order with an icebergQty MUST have timeInForce set to GTC. - - https://binance-docs.github.io/apidocs/spot/en/#new-order-trade - - :param symbol: required - :type symbol: str - :param side: required - :type side: str - :param type: required - :type type: str - :param timeInForce: required if limit order - :type timeInForce: str - :param quantity: required - :type quantity: decimal - :param quoteOrderQty: amount the user wants to spend (when buying) or receive (when selling) - of the quote asset, applicable to MARKET orders - :type quoteOrderQty: decimal - :param price: required - :type price: str - :param newClientOrderId: A unique id for the order. Automatically generated if not sent. - :type newClientOrderId: str - :param icebergQty: Used with LIMIT, STOP_LOSS_LIMIT, and TAKE_PROFIT_LIMIT to create an iceberg order. - :type icebergQty: decimal - :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; default: RESULT. - :type newOrderRespType: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - Response ACK: - - .. code-block:: python - - { - "symbol":"LTCBTC", - "orderId": 1, - "clientOrderId": "myOrder1" # Will be newClientOrderId - "transactTime": 1499827319559 - } - - Response RESULT: - - .. code-block:: python - - { - "symbol": "BTCUSDT", - "orderId": 28, - "clientOrderId": "6gCrw2kRUAF9CvJDGP16IP", - "transactTime": 1507725176595, - "price": "0.00000000", - "origQty": "10.00000000", - "executedQty": "10.00000000", - "cummulativeQuoteQty": "10.00000000", - "status": "FILLED", - "timeInForce": "GTC", - "type": "MARKET", - "side": "SELL" - } - - Response FULL: - - .. code-block:: python - - { - "symbol": "BTCUSDT", - "orderId": 28, - "clientOrderId": "6gCrw2kRUAF9CvJDGP16IP", - "transactTime": 1507725176595, - "price": "0.00000000", - "origQty": "10.00000000", - "executedQty": "10.00000000", - "cummulativeQuoteQty": "10.00000000", - "status": "FILLED", - "timeInForce": "GTC", - "type": "MARKET", - "side": "SELL", - "fills": [ - { - "price": "4000.00000000", - "qty": "1.00000000", - "commission": "4.00000000", - "commissionAsset": "USDT" - }, - { - "price": "3999.00000000", - "qty": "5.00000000", - "commission": "19.99500000", - "commissionAsset": "USDT" - }, - { - "price": "3998.00000000", - "qty": "2.00000000", - "commission": "7.99600000", - "commissionAsset": "USDT" - }, - { - "price": "3997.00000000", - "qty": "1.00000000", - "commission": "3.99700000", - "commissionAsset": "USDT" - }, - { - "price": "3995.00000000", - "qty": "1.00000000", - "commission": "3.99500000", - "commissionAsset": "USDT" - } - ] - } - - :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, BinanceOrderInactiveSymbolException - - """ - return self._post('order', True, data=params) - - def order_limit(self, timeInForce=BaseClient.TIME_IN_FORCE_GTC, **params): - """Send in a new limit order - - Any order with an icebergQty MUST have timeInForce set to GTC. - - :param symbol: required - :type symbol: str - :param side: required - :type side: str - :param quantity: required - :type quantity: decimal - :param price: required - :type price: str - :param timeInForce: default Good till cancelled - :type timeInForce: str - :param newClientOrderId: A unique id for the order. Automatically generated if not sent. - :type newClientOrderId: str - :param icebergQty: Used with LIMIT, STOP_LOSS_LIMIT, and TAKE_PROFIT_LIMIT to create an iceberg order. - :type icebergQty: decimal - :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; default: RESULT. - :type newOrderRespType: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - See order endpoint for full response options - - :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, BinanceOrderInactiveSymbolException - - """ - params.update({ - 'type': self.ORDER_TYPE_LIMIT, - 'timeInForce': timeInForce - }) - return self.create_order(**params) - - def order_limit_buy(self, timeInForce=BaseClient.TIME_IN_FORCE_GTC, **params): - """Send in a new limit buy order - - Any order with an icebergQty MUST have timeInForce set to GTC. - - :param symbol: required - :type symbol: str - :param quantity: required - :type quantity: decimal - :param price: required - :type price: str - :param timeInForce: default Good till cancelled - :type timeInForce: str - :param newClientOrderId: A unique id for the order. Automatically generated if not sent. - :type newClientOrderId: str - :param stopPrice: Used with stop orders - :type stopPrice: decimal - :param icebergQty: Used with iceberg orders - :type icebergQty: decimal - :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; default: RESULT. - :type newOrderRespType: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - See order endpoint for full response options - - :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, BinanceOrderInactiveSymbolException - - """ - params.update({ - 'side': self.SIDE_BUY, - }) - return self.order_limit(timeInForce=timeInForce, **params) - - def order_limit_sell(self, timeInForce=BaseClient.TIME_IN_FORCE_GTC, **params): - """Send in a new limit sell order - - :param symbol: required - :type symbol: str - :param quantity: required - :type quantity: decimal - :param price: required - :type price: str - :param timeInForce: default Good till cancelled - :type timeInForce: str - :param newClientOrderId: A unique id for the order. Automatically generated if not sent. - :type newClientOrderId: str - :param stopPrice: Used with stop orders - :type stopPrice: decimal - :param icebergQty: Used with iceberg orders - :type icebergQty: decimal - :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; default: RESULT. - :type newOrderRespType: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - See order endpoint for full response options - - :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, BinanceOrderInactiveSymbolException - - """ - params.update({ - 'side': self.SIDE_SELL - }) - return self.order_limit(timeInForce=timeInForce, **params) - - def order_market(self, **params): - """Send in a new market order - - :param symbol: required - :type symbol: str - :param side: required - :type side: str - :param quantity: required - :type quantity: decimal - :param quoteOrderQty: amount the user wants to spend (when buying) or receive (when selling) - of the quote asset - :type quoteOrderQty: decimal - :param newClientOrderId: A unique id for the order. Automatically generated if not sent. - :type newClientOrderId: str - :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; default: RESULT. - :type newOrderRespType: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - See order endpoint for full response options - - :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, BinanceOrderInactiveSymbolException - - """ - params.update({ - 'type': self.ORDER_TYPE_MARKET - }) - return self.create_order(**params) - - def order_market_buy(self, **params): - """Send in a new market buy order - - :param symbol: required - :type symbol: str - :param quantity: required - :type quantity: decimal - :param quoteOrderQty: the amount the user wants to spend of the quote asset - :type quoteOrderQty: decimal - :param newClientOrderId: A unique id for the order. Automatically generated if not sent. - :type newClientOrderId: str - :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; default: RESULT. - :type newOrderRespType: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - See order endpoint for full response options - - :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, BinanceOrderInactiveSymbolException - - """ - params.update({ - 'side': self.SIDE_BUY - }) - return self.order_market(**params) - - def order_market_sell(self, **params): - """Send in a new market sell order - - :param symbol: required - :type symbol: str - :param quantity: required - :type quantity: decimal - :param quoteOrderQty: the amount the user wants to receive of the quote asset - :type quoteOrderQty: decimal - :param newClientOrderId: A unique id for the order. Automatically generated if not sent. - :type newClientOrderId: str - :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; default: RESULT. - :type newOrderRespType: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - See order endpoint for full response options - - :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, BinanceOrderInactiveSymbolException - - """ - params.update({ - 'side': self.SIDE_SELL - }) - return self.order_market(**params) - - def create_oco_order(self, **params): - """Send in a new OCO order - - https://binance-docs.github.io/apidocs/spot/en/#new-oco-trade - - :param symbol: required - :type symbol: str - :param listClientOrderId: A unique id for the list order. Automatically generated if not sent. - :type listClientOrderId: str - :param side: required - :type side: str - :param quantity: required - :type quantity: decimal - :param limitClientOrderId: A unique id for the limit order. Automatically generated if not sent. - :type limitClientOrderId: str - :param price: required - :type price: str - :param limitIcebergQty: Used to make the LIMIT_MAKER leg an iceberg order. - :type limitIcebergQty: decimal - :param stopClientOrderId: A unique id for the stop order. Automatically generated if not sent. - :type stopClientOrderId: str - :param stopPrice: required - :type stopPrice: str - :param stopLimitPrice: If provided, stopLimitTimeInForce is required. - :type stopLimitPrice: str - :param stopIcebergQty: Used with STOP_LOSS_LIMIT leg to make an iceberg order. - :type stopIcebergQty: decimal - :param stopLimitTimeInForce: Valid values are GTC/FOK/IOC. - :type stopLimitTimeInForce: str - :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; default: RESULT. - :type newOrderRespType: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - Response ACK: - - .. code-block:: python - - { - } - - Response RESULT: - - .. code-block:: python - - { - } - - Response FULL: - - .. code-block:: python - - { - } - - :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, BinanceOrderInactiveSymbolException - - """ - return self._post('order/oco', True, data=params) - - def order_oco_buy(self, **params): - """Send in a new OCO buy order - - :param symbol: required - :type symbol: str - :param listClientOrderId: A unique id for the list order. Automatically generated if not sent. - :type listClientOrderId: str - :param quantity: required - :type quantity: decimal - :param limitClientOrderId: A unique id for the limit order. Automatically generated if not sent. - :type limitClientOrderId: str - :param price: required - :type price: str - :param limitIcebergQty: Used to make the LIMIT_MAKER leg an iceberg order. - :type limitIcebergQty: decimal - :param stopClientOrderId: A unique id for the stop order. Automatically generated if not sent. - :type stopClientOrderId: str - :param stopPrice: required - :type stopPrice: str - :param stopLimitPrice: If provided, stopLimitTimeInForce is required. - :type stopLimitPrice: str - :param stopIcebergQty: Used with STOP_LOSS_LIMIT leg to make an iceberg order. - :type stopIcebergQty: decimal - :param stopLimitTimeInForce: Valid values are GTC/FOK/IOC. - :type stopLimitTimeInForce: str - :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; default: RESULT. - :type newOrderRespType: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - See OCO order endpoint for full response options - - :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, BinanceOrderInactiveSymbolException - - """ - params.update({ - 'side': self.SIDE_BUY - }) - return self.create_oco_order(**params) - - def order_oco_sell(self, **params): - """Send in a new OCO sell order - - :param symbol: required - :type symbol: str - :param listClientOrderId: A unique id for the list order. Automatically generated if not sent. - :type listClientOrderId: str - :param quantity: required - :type quantity: decimal - :param limitClientOrderId: A unique id for the limit order. Automatically generated if not sent. - :type limitClientOrderId: str - :param price: required - :type price: str - :param limitIcebergQty: Used to make the LIMIT_MAKER leg an iceberg order. - :type limitIcebergQty: decimal - :param stopClientOrderId: A unique id for the stop order. Automatically generated if not sent. - :type stopClientOrderId: str - :param stopPrice: required - :type stopPrice: str - :param stopLimitPrice: If provided, stopLimitTimeInForce is required. - :type stopLimitPrice: str - :param stopIcebergQty: Used with STOP_LOSS_LIMIT leg to make an iceberg order. - :type stopIcebergQty: decimal - :param stopLimitTimeInForce: Valid values are GTC/FOK/IOC. - :type stopLimitTimeInForce: str - :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; default: RESULT. - :type newOrderRespType: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - See OCO order endpoint for full response options - - :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, BinanceOrderInactiveSymbolException - - """ - params.update({ - 'side': self.SIDE_SELL - }) - return self.create_oco_order(**params) - - def create_test_order(self, **params): - """Test new order creation and signature/recvWindow long. Creates and validates a new order but does not send it into the matching engine. - - https://binance-docs.github.io/apidocs/spot/en/#test-new-order-trade - - :param symbol: required - :type symbol: str - :param side: required - :type side: str - :param type: required - :type type: str - :param timeInForce: required if limit order - :type timeInForce: str - :param quantity: required - :type quantity: decimal - :param price: required - :type price: str - :param newClientOrderId: A unique id for the order. Automatically generated if not sent. - :type newClientOrderId: str - :param icebergQty: Used with iceberg orders - :type icebergQty: decimal - :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; default: RESULT. - :type newOrderRespType: str - :param recvWindow: The number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - {} - - :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, BinanceOrderInactiveSymbolException - - - """ - return self._post('order/test', True, data=params) - - def get_order(self, **params): - """Check an order's status. Either orderId or origClientOrderId must be sent. - - https://binance-docs.github.io/apidocs/spot/en/#query-order-user_data - - :param symbol: required - :type symbol: str - :param orderId: The unique order id - :type orderId: int - :param origClientOrderId: optional - :type origClientOrderId: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "symbol": "LTCBTC", - "orderId": 1, - "clientOrderId": "myOrder1", - "price": "0.1", - "origQty": "1.0", - "executedQty": "0.0", - "status": "NEW", - "timeInForce": "GTC", - "type": "LIMIT", - "side": "BUY", - "stopPrice": "0.0", - "icebergQty": "0.0", - "time": 1499827319559 - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._get('order', True, data=params) - - def get_all_orders(self, **params): - """Get all account orders; active, canceled, or filled. - - https://binance-docs.github.io/apidocs/spot/en/#all-orders-user_data - - :param symbol: required - :type symbol: str - :param orderId: The unique order id - :type orderId: int - :param startTime: optional - :type startTime: int - :param endTime: optional - :type endTime: int - :param limit: Default 500; max 1000. - :type limit: int - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - [ - { - "symbol": "LTCBTC", - "orderId": 1, - "clientOrderId": "myOrder1", - "price": "0.1", - "origQty": "1.0", - "executedQty": "0.0", - "status": "NEW", - "timeInForce": "GTC", - "type": "LIMIT", - "side": "BUY", - "stopPrice": "0.0", - "icebergQty": "0.0", - "time": 1499827319559 - } - ] - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._get('allOrders', True, data=params) - - def cancel_order(self, **params): - """Cancel an active order. Either orderId or origClientOrderId must be sent. - - https://binance-docs.github.io/apidocs/spot/en/#cancel-order-trade - - :param symbol: required - :type symbol: str - :param orderId: The unique order id - :type orderId: int - :param origClientOrderId: optional - :type origClientOrderId: str - :param newClientOrderId: Used to uniquely identify this cancel. Automatically generated by default. - :type newClientOrderId: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "symbol": "LTCBTC", - "origClientOrderId": "myOrder1", - "orderId": 1, - "clientOrderId": "cancelMyOrder1" - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._delete('order', True, data=params) - - def get_open_orders(self, **params): - """Get all open orders on a symbol. - - https://binance-docs.github.io/apidocs/spot/en/#current-open-orders-user_data - - :param symbol: optional - :type symbol: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - [ - { - "symbol": "LTCBTC", - "orderId": 1, - "clientOrderId": "myOrder1", - "price": "0.1", - "origQty": "1.0", - "executedQty": "0.0", - "status": "NEW", - "timeInForce": "GTC", - "type": "LIMIT", - "side": "BUY", - "stopPrice": "0.0", - "icebergQty": "0.0", - "time": 1499827319559 - } - ] - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._get('openOrders', True, data=params) - - # User Stream Endpoints - def get_account(self, **params): - """Get current account information. - - https://binance-docs.github.io/apidocs/spot/en/#account-information-user_data - - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "makerCommission": 15, - "takerCommission": 15, - "buyerCommission": 0, - "sellerCommission": 0, - "canTrade": true, - "canWithdraw": true, - "canDeposit": true, - "balances": [ - { - "asset": "BTC", - "free": "4723846.89208129", - "locked": "0.00000000" - }, - { - "asset": "LTC", - "free": "4763368.68006011", - "locked": "0.00000000" - } - ] - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._get('account', True, data=params) - - def get_asset_balance(self, asset, **params): - """Get current asset balance. - - :param asset: required - :type asset: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: dictionary or None if not found - - .. code-block:: python - - { - "asset": "BTC", - "free": "4723846.89208129", - "locked": "0.00000000" - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - res = self.get_account(**params) - # find asset balance in list of balances - if "balances" in res: - for bal in res['balances']: - if bal['asset'].lower() == asset.lower(): - return bal - return None - - def get_my_trades(self, **params): - """Get trades for a specific symbol. - - https://binance-docs.github.io/apidocs/spot/en/#account-trade-list-user_data - - :param symbol: required - :type symbol: str - :param startTime: optional - :type startTime: int - :param endTime: optional - :type endTime: int - :param limit: Default 500; max 1000. - :type limit: int - :param fromId: TradeId to fetch from. Default gets most recent trades. - :type fromId: int - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - [ - { - "id": 28457, - "price": "4.00000100", - "qty": "12.00000000", - "commission": "10.10000000", - "commissionAsset": "BNB", - "time": 1499865549590, - "isBuyer": true, - "isMaker": false, - "isBestMatch": true - } - ] - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._get('myTrades', True, data=params) - - def get_system_status(self): - """Get system status detail. - - https://binance-docs.github.io/apidocs/spot/en/#system-status-sapi-system - - :returns: API response - - .. code-block:: python - - { - "status": 0, # 0: normal,1:system maintenance - "msg": "normal" # normal or System maintenance. - } - - :raises: BinanceAPIException - - """ - return self._request_margin_api('get', 'system/status') - - def get_account_status(self, **params): - """Get account status detail. - - https://binance-docs.github.io/apidocs/spot/en/#account-status-sapi-user_data - - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "data": "Normal" - } - - """ - return self._request_margin_api('get', 'account/status', True, data=params) - - def get_account_api_trading_status(self, **params): - """Fetch account api trading status detail. - - https://binance-docs.github.io/apidocs/spot/en/#account-api-trading-status-sapi-user_data - - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "data": { // API trading status detail - "isLocked": false, // API trading function is locked or not - "plannedRecoverTime": 0, // If API trading function is locked, this is the planned recover time - "triggerCondition": { - "GCR": 150, // Number of GTC orders - "IFER": 150, // Number of FOK/IOC orders - "UFR": 300 // Number of orders - }, - "indicators": { // The indicators updated every 30 seconds - "BTCUSDT": [ // The symbol - { - "i": "UFR", // Unfilled Ratio (UFR) - "c": 20, // Count of all orders - "v": 0.05, // Current UFR value - "t": 0.995 // Trigger UFR value - }, - { - "i": "IFER", // IOC/FOK Expiration Ratio (IFER) - "c": 20, // Count of FOK/IOC orders - "v": 0.99, // Current IFER value - "t": 0.99 // Trigger IFER value - }, - { - "i": "GCR", // GTC Cancellation Ratio (GCR) - "c": 20, // Count of GTC orders - "v": 0.99, // Current GCR value - "t": 0.99 // Trigger GCR value - } - ], - "ETHUSDT": [ - { - "i": "UFR", - "c": 20, - "v": 0.05, - "t": 0.995 - }, - { - "i": "IFER", - "c": 20, - "v": 0.99, - "t": 0.99 - }, - { - "i": "GCR", - "c": 20, - "v": 0.99, - "t": 0.99 - } - ] - }, - "updateTime": 1547630471725 - } - } - - """ - return self._request_margin_api('get', 'account/apiTradingStatus', True, data=params) - - def get_account_api_permissions(self, **params): - """Fetch api key permissions. - - https://binance-docs.github.io/apidocs/spot/en/#get-api-key-permission-user_data - - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "ipRestrict": false, - "createTime": 1623840271000, - "enableWithdrawals": false, // This option allows you to withdraw via API. You must apply the IP Access Restriction filter in order to enable withdrawals - "enableInternalTransfer": true, // This option authorizes this key to transfer funds between your master account and your sub account instantly - "permitsUniversalTransfer": true, // Authorizes this key to be used for a dedicated universal transfer API to transfer multiple supported currencies. Each business's own transfer API rights are not affected by this authorization - "enableVanillaOptions": false, // Authorizes this key to Vanilla options trading - "enableReading": true, - "enableFutures": false, // API Key created before your futures account opened does not support futures API service - "enableMargin": false, // This option can be adjusted after the Cross Margin account transfer is completed - "enableSpotAndMarginTrading": false, // Spot and margin trading - "tradingAuthorityExpirationTime": 1628985600000 // Expiration time for spot and margin trading permission - } - - """ - return self._request_margin_api('get', 'account/apiRestrictions', True, data=params) - - def get_dust_log(self, **params): - """Get log of small amounts exchanged for BNB. - - https://binance-docs.github.io/apidocs/spot/en/#dustlog-sapi-user_data - - :param startTime: optional - :type startTime: int - :param endTime: optional - :type endTime: int - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "total": 8, //Total counts of exchange - "userAssetDribblets": [ - { - "totalTransferedAmount": "0.00132256", // Total transfered BNB amount for this exchange. - "totalServiceChargeAmount": "0.00002699", //Total service charge amount for this exchange. - "transId": 45178372831, - "userAssetDribbletDetails": [ //Details of this exchange. - { - "transId": 4359321, - "serviceChargeAmount": "0.000009", - "amount": "0.0009", - "operateTime": 1615985535000, - "transferedAmount": "0.000441", - "fromAsset": "USDT" - }, - { - "transId": 4359321, - "serviceChargeAmount": "0.00001799", - "amount": "0.0009", - "operateTime": "2018-05-03 17:07:04", - "transferedAmount": "0.00088156", - "fromAsset": "ETH" - } - ] - }, - { - "operateTime":1616203180000, - "totalTransferedAmount": "0.00058795", - "totalServiceChargeAmount": "0.000012", - "transId": 4357015, - "userAssetDribbletDetails": [ - { - "transId": 4357015, - "serviceChargeAmount": "0.00001" - "amount": "0.001", - "operateTime": 1616203180000, - "transferedAmount": "0.00049", - "fromAsset": "USDT" - }, - { - "transId": 4357015, - "serviceChargeAmount": "0.000002" - "amount": "0.0001", - "operateTime": 1616203180000, - "transferedAmount": "0.00009795", - "fromAsset": "ETH" - } - ] - } - ] - } - - """ - return self._request_margin_api('get', 'asset/dribblet', True, data=params) - - def transfer_dust(self, **params): - """Convert dust assets to BNB. - - https://binance-docs.github.io/apidocs/spot/en/#dust-transfer-user_data - - :param asset: The asset being converted. e.g: 'ONE' - :type asset: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - .. code:: python - - result = client.transfer_dust(asset='ONE') - - :returns: API response - - .. code-block:: python - - { - "totalServiceCharge":"0.02102542", - "totalTransfered":"1.05127099", - "transferResult":[ - { - "amount":"0.03000000", - "fromAsset":"ETH", - "operateTime":1563368549307, - "serviceChargeAmount":"0.00500000", - "tranId":2970932918, - "transferedAmount":"0.25000000" - } - ] - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('post', 'asset/dust', True, data=params) - - def get_asset_dividend_history(self, **params): - """Query asset dividend record. - - https://binance-docs.github.io/apidocs/spot/en/#asset-dividend-record-user_data - - :param asset: optional - :type asset: str - :param startTime: optional - :type startTime: long - :param endTime: optional - :type endTime: long - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - .. code:: python - - result = client.get_asset_dividend_history() - - :returns: API response - - .. code-block:: python - - { - "rows":[ - { - "amount":"10.00000000", - "asset":"BHFT", - "divTime":1563189166000, - "enInfo":"BHFT distribution", - "tranId":2968885920 - }, - { - "amount":"10.00000000", - "asset":"BHFT", - "divTime":1563189165000, - "enInfo":"BHFT distribution", - "tranId":2968885920 - } - ], - "total":2 - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'asset/assetDividend', True, data=params) - - def make_universal_transfer(self, **params): - """User Universal Transfer - - https://binance-docs.github.io/apidocs/spot/en/#user-universal-transfer - - :param type: required - :type type: str (ENUM) - :param asset: required - :type asset: str - :param amount: required - :type amount: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - .. code:: python - - transfer_status = client.make_universal_transfer(params) - - :returns: API response - - .. code-block:: python - - { - "tranId":13526853623 - } - - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('post', 'asset/transfer', signed=True, data=params) - - def query_universal_transfer_history(self, **params): - """Query User Universal Transfer History - - https://binance-docs.github.io/apidocs/spot/en/#query-user-universal-transfer-history - - :param type: required - :type type: str (ENUM) - :param startTime: optional - :type startTime: int - :param endTime: optional - :type endTime: int - :param current: optional - Default 1 - :type current: int - :param size: required - Default 10, Max 100 - :type size: int - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - .. code:: python - - transfer_status = client.query_universal_transfer_history(params) - - :returns: API response - - .. code-block:: python - - { - "total":2, - "rows":[ - { - "asset":"USDT", - "amount":"1", - "type":"MAIN_UMFUTURE" - "status": "CONFIRMED", - "tranId": 11415955596, - "timestamp":1544433328000 - }, - { - "asset":"USDT", - "amount":"2", - "type":"MAIN_UMFUTURE", - "status": "CONFIRMED", - "tranId": 11366865406, - "timestamp":1544433328000 - } - ] - } - - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'asset/transfer', signed=True, data=params) - - def get_trade_fee(self, **params): - """Get trade fee. - - https://binance-docs.github.io/apidocs/spot/en/#trade-fee-sapi-user_data - - :param symbol: optional - :type symbol: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - [ - { - "symbol": "ADABNB", - "makerCommission": "0.001", - "takerCommission": "0.001" - }, - { - "symbol": "BNBBTC", - "makerCommission": "0.001", - "takerCommission": "0.001" - } - ] - - """ - return self._request_margin_api('get', 'asset/tradeFee', True, data=params) - - def get_asset_details(self, **params): - """Fetch details on assets. - - https://binance-docs.github.io/apidocs/spot/en/#asset-detail-sapi-user_data - - :param asset: optional - :type asset: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "CTR": { - "minWithdrawAmount": "70.00000000", //min withdraw amount - "depositStatus": false,//deposit status (false if ALL of networks' are false) - "withdrawFee": 35, // withdraw fee - "withdrawStatus": true, //withdraw status (false if ALL of networks' are false) - "depositTip": "Delisted, Deposit Suspended" //reason - }, - "SKY": { - "minWithdrawAmount": "0.02000000", - "depositStatus": true, - "withdrawFee": 0.01, - "withdrawStatus": true - } - } - - """ - return self._request_margin_api('get', 'asset/assetDetail', True, data=params) - - # Withdraw Endpoints - - def withdraw(self, **params): - """Submit a withdraw request. - - https://binance-docs.github.io/apidocs/spot/en/#withdraw-sapi - - Assumptions: - - - You must have Withdraw permissions enabled on your API key - - You must have withdrawn to the address specified through the website and approved the transaction via email - - :param coin: required - :type coin: str - :param withdrawOrderId: optional - client id for withdraw - :type withdrawOrderId: str - :param network: optional - :type network: str - :param address: optional - :type address: str - :type addressTag: optional - Secondary address identifier for coins like XRP,XMR etc. - :param amount: required - :type amount: decimal - :param transactionFeeFlag: required - When making internal transfer, true for returning the fee to the destination account; false for returning the fee back to the departure account. Default false. - :type transactionFeeFlag: bool - :param name: optional - Description of the address, default asset value passed will be used - :type name: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "id":"7213fea8e94b4a5593d507237e5a555b" - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - # force a name for the withdrawal if one not set - if 'coin' in params and 'name' not in params: - params['name'] = params['coin'] - return self._request_margin_api('post', 'capital/withdraw/apply', True, data=params) - - def get_deposit_history(self, **params): - """Fetch deposit history. - - https://binance-docs.github.io/apidocs/spot/en/#deposit-history-supporting-network-user_data - - :param coin: optional - :type coin: str - :type status: optional - 0(0:pending,1:success) optional - :type status: int - :param startTime: optional - :type startTime: long - :param endTime: optional - :type endTime: long - :param offset: optional - default:0 - :type offset: long - :param limit: optional - :type limit: long - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - [ - { - "amount":"0.00999800", - "coin":"PAXG", - "network":"ETH", - "status":1, - "address":"0x788cabe9236ce061e5a892e1a59395a81fc8d62c", - "addressTag":"", - "txId":"0xaad4654a3234aa6118af9b4b335f5ae81c360b2394721c019b5d1e75328b09f3", - "insertTime":1599621997000, - "transferType":0, - "confirmTimes":"12/12" - }, - { - "amount":"0.50000000", - "coin":"IOTA", - "network":"IOTA", - "status":1, - "address":"SIZ9VLMHWATXKV99LH99CIGFJFUMLEHGWVZVNNZXRJJVWBPHYWPPBOSDORZ9EQSHCZAMPVAPGFYQAUUV9DROOXJLNW", - "addressTag":"", - "txId":"ESBFVQUTPIWQNJSPXFNHNYHSQNTGKRVKPRABQWTAXCDWOAKDKYWPTVG9BGXNVNKTLEJGESAVXIKIZ9999", - "insertTime":1599620082000, - "transferType":0, - "confirmTimes":"1/1" - } - ] - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'capital/deposit/hisrec', True, data=params) - - def get_withdraw_history(self, **params): - """Fetch withdraw history. - - https://binance-docs.github.io/apidocs/spot/en/#withdraw-history-supporting-network-user_data - - :param coin: optional - :type coin: str - :type status: 0(0:Email Sent,1:Cancelled 2:Awaiting Approval 3:Rejected 4:Processing 5:Failure 6Completed) optional - :type status: int - :param offset: optional - default:0 - :type offset: int - :param limit: optional - :type limit: int - :param startTime: optional - Default: 90 days from current timestamp - :type startTime: int - :param endTime: optional - Default: present timestamp - :type endTime: int - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - [ - { - "address": "0x94df8b352de7f46f64b01d3666bf6e936e44ce60", - "amount": "8.91000000", - "applyTime": "2019-10-12 11:12:02", - "coin": "USDT", - "id": "b6ae22b3aa844210a7041aee7589627c", - "withdrawOrderId": "WITHDRAWtest123", // will not be returned if there's no withdrawOrderId for this withdraw. - "network": "ETH", - "transferType": 0, // 1 for internal transfer, 0 for external transfer - "status": 6, - "txId": "0xb5ef8c13b968a406cc62a93a8bd80f9e9a906ef1b3fcf20a2e48573c17659268" - }, - { - "address": "1FZdVHtiBqMrWdjPyRPULCUceZPJ2WLCsB", - "amount": "0.00150000", - "applyTime": "2019-09-24 12:43:45", - "coin": "BTC", - "id": "156ec387f49b41df8724fa744fa82719", - "network": "BTC", - "status": 6, - "txId": "60fd9007ebfddc753455f95fafa808c4302c836e4d1eebc5a132c36c1d8ac354" - } - ] - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'capital/withdraw/history', True, data=params) - - def get_withdraw_history_id(self, withdraw_id, **params): - """Fetch withdraw history. - - https://binance-docs.github.io/apidocs/spot/en/#withdraw-history-supporting-network-user_data - - :param withdraw_id: required - :type withdraw_id: str - :param asset: optional - :type asset: str - :type status: 0(0:Email Sent,1:Cancelled 2:Awaiting Approval 3:Rejected 4:Processing 5:Failure 6Completed) optional - :type status: int - :param startTime: optional - :type startTime: long - :param endTime: optional - :type endTime: long - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "id":"7213fea8e94b4a5593d507237e5a555b", - "withdrawOrderId": None, - "amount": 0.99, - "transactionFee": 0.01, - "address": "0x6915f16f8791d0a1cc2bf47c13a6b2a92000504b", - "asset": "ETH", - "txId": "0xdf33b22bdb2b28b1f75ccd201a4a4m6e7g83jy5fc5d5a9d1340961598cfcb0a1", - "applyTime": 1508198532000, - "status": 4 - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - result = self.get_withdraw_history(**params) - - for entry in result: - if 'id' in entry and entry['id'] == withdraw_id: - return entry - - raise Exception("There is no entry with withdraw id", result) - - def get_deposit_address(self, coin: str, network: Optional[str] = None, **params): - """Fetch a deposit address for a symbol - - https://binance-docs.github.io/apidocs/spot/en/#deposit-address-supporting-network-user_data - - :param coin: required - :type coin: str - :param network: optional - :type network: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "address": "1HPn8Rx2y6nNSfagQBKy27GB99Vbzg89wv", - "coin": "BTC", - "tag": "", - "url": "https://btc.com/1HPn8Rx2y6nNSfagQBKy27GB99Vbzg89wv" - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - params['coin'] = coin - if network: - params['network'] = network - return self._request_margin_api('get', 'capital/deposit/address', True, data=params) - - # User Stream Endpoints - - def stream_get_listen_key(self): - """Start a new user data stream and return the listen key - If a stream already exists it should return the same key. - If the stream becomes invalid a new key is returned. - - Can be used to keep the user stream alive. - - https://binance-docs.github.io/apidocs/spot/en/#listen-key-spot - - :returns: API response - - .. code-block:: python - - { - "listenKey": "pqia91ma19a5s61cv6a81va65sdf19v8a65a1a5s61cv6a81va65sdf19v8a65a1" - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - res = self._post('userDataStream', False, data={}, version=self.PRIVATE_API_VERSION) - return res['listenKey'] - - def stream_keepalive(self, listenKey): - """PING a user data stream to prevent a time out. - - https://binance-docs.github.io/apidocs/spot/en/#listen-key-spot - - :param listenKey: required - :type listenKey: str - - :returns: API response - - .. code-block:: python - - {} - - :raises: BinanceRequestException, BinanceAPIException - - """ - params = { - 'listenKey': listenKey - } - return self._put('userDataStream', False, data=params, version=self.PRIVATE_API_VERSION) - - def stream_close(self, listenKey): - """Close out a user data stream. - - https://binance-docs.github.io/apidocs/spot/en/#listen-key-spot - - :param listenKey: required - :type listenKey: str - - :returns: API response - - .. code-block:: python - - {} - - :raises: BinanceRequestException, BinanceAPIException - - """ - params = { - 'listenKey': listenKey - } - return self._delete('userDataStream', False, data=params, version=self.PRIVATE_API_VERSION) - - # Margin Trading Endpoints - - def get_margin_account(self, **params): - """Query cross-margin account details - - https://binance-docs.github.io/apidocs/spot/en/#query-cross-margin-account-details-user_data - - :returns: API response - - .. code-block:: python - - { - "borrowEnabled": true, - "marginLevel": "11.64405625", - "totalAssetOfBtc": "6.82728457", - "totalLiabilityOfBtc": "0.58633215", - "totalNetAssetOfBtc": "6.24095242", - "tradeEnabled": true, - "transferEnabled": true, - "userAssets": [ - { - "asset": "BTC", - "borrowed": "0.00000000", - "free": "0.00499500", - "interest": "0.00000000", - "locked": "0.00000000", - "netAsset": "0.00499500" - }, - { - "asset": "BNB", - "borrowed": "201.66666672", - "free": "2346.50000000", - "interest": "0.00000000", - "locked": "0.00000000", - "netAsset": "2144.83333328" - }, - { - "asset": "ETH", - "borrowed": "0.00000000", - "free": "0.00000000", - "interest": "0.00000000", - "locked": "0.00000000", - "netAsset": "0.00000000" - }, - { - "asset": "USDT", - "borrowed": "0.00000000", - "free": "0.00000000", - "interest": "0.00000000", - "locked": "0.00000000", - "netAsset": "0.00000000" - } - ] - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'margin/account', True, data=params) - - def get_isolated_margin_account(self, **params): - """Query isolated margin account details - - https://binance-docs.github.io/apidocs/spot/en/#query-isolated-margin-account-info-user_data - - :param symbols: optional up to 5 margin pairs as a comma separated string - :type asset: str - - .. code:: python - - account_info = client.get_isolated_margin_account() - account_info = client.get_isolated_margin_account(symbols="BTCUSDT,ETHUSDT") - - :returns: API response - - .. code-block:: python - - If "symbols" is not sent: - - { - "assets":[ - { - "baseAsset": - { - "asset": "BTC", - "borrowEnabled": true, - "borrowed": "0.00000000", - "free": "0.00000000", - "interest": "0.00000000", - "locked": "0.00000000", - "netAsset": "0.00000000", - "netAssetOfBtc": "0.00000000", - "repayEnabled": true, - "totalAsset": "0.00000000" - }, - "quoteAsset": - { - "asset": "USDT", - "borrowEnabled": true, - "borrowed": "0.00000000", - "free": "0.00000000", - "interest": "0.00000000", - "locked": "0.00000000", - "netAsset": "0.00000000", - "netAssetOfBtc": "0.00000000", - "repayEnabled": true, - "totalAsset": "0.00000000" - }, - "symbol": "BTCUSDT" - "isolatedCreated": true, - "marginLevel": "0.00000000", - "marginLevelStatus": "EXCESSIVE", // "EXCESSIVE", "NORMAL", "MARGIN_CALL", "PRE_LIQUIDATION", "FORCE_LIQUIDATION" - "marginRatio": "0.00000000", - "indexPrice": "10000.00000000" - "liquidatePrice": "1000.00000000", - "liquidateRate": "1.00000000" - "tradeEnabled": true - } - ], - "totalAssetOfBtc": "0.00000000", - "totalLiabilityOfBtc": "0.00000000", - "totalNetAssetOfBtc": "0.00000000" - } - - If "symbols" is sent: - - { - "assets":[ - { - "baseAsset": - { - "asset": "BTC", - "borrowEnabled": true, - "borrowed": "0.00000000", - "free": "0.00000000", - "interest": "0.00000000", - "locked": "0.00000000", - "netAsset": "0.00000000", - "netAssetOfBtc": "0.00000000", - "repayEnabled": true, - "totalAsset": "0.00000000" - }, - "quoteAsset": - { - "asset": "USDT", - "borrowEnabled": true, - "borrowed": "0.00000000", - "free": "0.00000000", - "interest": "0.00000000", - "locked": "0.00000000", - "netAsset": "0.00000000", - "netAssetOfBtc": "0.00000000", - "repayEnabled": true, - "totalAsset": "0.00000000" - }, - "symbol": "BTCUSDT" - "isolatedCreated": true, - "marginLevel": "0.00000000", - "marginLevelStatus": "EXCESSIVE", // "EXCESSIVE", "NORMAL", "MARGIN_CALL", "PRE_LIQUIDATION", "FORCE_LIQUIDATION" - "marginRatio": "0.00000000", - "indexPrice": "10000.00000000" - "liquidatePrice": "1000.00000000", - "liquidateRate": "1.00000000" - "tradeEnabled": true - } - ] - } - - """ - return self._request_margin_api('get', 'margin/isolated/account', True, data=params) - - def enable_isolated_margin_account(self, **params): - """Enable isolated margin account for a specific symbol. - - https://binance-docs.github.io/apidocs/spot/en/#enable-isolated-margin-account-trade - - :param symbol: - :type asset: str - - :returns: API response - - .. code-block:: python - - { - "success": true, - "symbol": "BTCUSDT" - } - - - """ - return self._request_margin_api('post', 'margin/isolated/account', True, data=params) - - def disable_isolated_margin_account(self, **params): - """Disable isolated margin account for a specific symbol. Each trading pair can only - be deactivated once every 24 hours. - - https://binance-docs.github.io/apidocs/spot/en/#disable-isolated-margin-account-trade - - :param symbol: - :type asset: str - - :returns: API response - - .. code-block:: python - - { - "success": true, - "symbol": "BTCUSDT" - } - - - """ - return self._request_margin_api('delete', 'margin/isolated/account', True, data=params) - - def get_margin_asset(self, **params): - """Query cross-margin asset - - https://binance-docs.github.io/apidocs/spot/en/#query-margin-asset-market_data - - :param asset: name of the asset - :type asset: str - - .. code:: python - - asset_details = client.get_margin_asset(asset='BNB') - - :returns: API response - - .. code-block:: python - - { - "assetFullName": "Binance Coin", - "assetName": "BNB", - "isBorrowable": false, - "isMortgageable": true, - "userMinBorrow": "0.00000000", - "userMinRepay": "0.00000000" - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'margin/asset', data=params) - - def get_margin_symbol(self, **params): - """Query cross-margin symbol info - - https://binance-docs.github.io/apidocs/spot/en/#query-cross-margin-pair-market_data - - :param symbol: name of the symbol pair - :type symbol: str - - .. code:: python - - pair_details = client.get_margin_symbol(symbol='BTCUSDT') - - :returns: API response - - .. code-block:: python - - { - "id":323355778339572400, - "symbol":"BTCUSDT", - "base":"BTC", - "quote":"USDT", - "isMarginTrade":true, - "isBuyAllowed":true, - "isSellAllowed":true - } - - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'margin/pair', data=params) - - def get_margin_all_assets(self, **params): - """Get All Margin Assets (MARKET_DATA) - - https://binance-docs.github.io/apidocs/spot/en/#get-all-margin-assets-market_data - - .. code:: python - - margin_assets = client.get_margin_all_assets() - - :returns: API response - - .. code-block:: python - - [ - { - "assetFullName": "USD coin", - "assetName": "USDC", - "isBorrowable": true, - "isMortgageable": true, - "userMinBorrow": "0.00000000", - "userMinRepay": "0.00000000" - }, - { - "assetFullName": "BNB-coin", - "assetName": "BNB", - "isBorrowable": true, - "isMortgageable": true, - "userMinBorrow": "1.00000000", - "userMinRepay": "0.00000000" - } - ] - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'margin/allAssets', data=params) - - def get_margin_all_pairs(self, **params): - """Get All Cross Margin Pairs (MARKET_DATA) - - https://binance-docs.github.io/apidocs/spot/en/#get-all-cross-margin-pairs-market_data - - .. code:: python - - margin_pairs = client.get_margin_all_pairs() - - :returns: API response - - .. code-block:: python - - [ - { - "base": "BNB", - "id": 351637150141315861, - "isBuyAllowed": true, - "isMarginTrade": true, - "isSellAllowed": true, - "quote": "BTC", - "symbol": "BNBBTC" - }, - { - "base": "TRX", - "id": 351637923235429141, - "isBuyAllowed": true, - "isMarginTrade": true, - "isSellAllowed": true, - "quote": "BTC", - "symbol": "TRXBTC" - } - ] - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'margin/allPairs', data=params) - - def create_isolated_margin_account(self, **params): - """Create isolated margin account for symbol - - https://binance-docs.github.io/apidocs/spot/en/#create-isolated-margin-account-margin - - :param base: Base asset of symbol - :type base: str - :param quote: Quote asset of symbol - :type quote: str - - .. code:: python - - pair_details = client.create_isolated_margin_account(base='USDT', quote='BTC') - - :returns: API response - - .. code-block:: python - - { - "success": true, - "symbol": "BTCUSDT" - } - - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('post', 'margin/isolated/create', signed=True, data=params) - - def get_isolated_margin_symbol(self, **params): - """Query isolated margin symbol info - - https://binance-docs.github.io/apidocs/spot/en/#query-isolated-margin-symbol-user_data - - :param symbol: name of the symbol pair - :type symbol: str - - .. code:: python - - pair_details = client.get_isolated_margin_symbol(symbol='BTCUSDT') - - :returns: API response - - .. code-block:: python - - { - "symbol":"BTCUSDT", - "base":"BTC", - "quote":"USDT", - "isMarginTrade":true, - "isBuyAllowed":true, - "isSellAllowed":true - } - - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'margin/isolated/pair', signed=True, data=params) - - def get_all_isolated_margin_symbols(self, **params): - """Query isolated margin symbol info for all pairs - - https://binance-docs.github.io/apidocs/spot/en/#get-all-isolated-margin-symbol-user_data - - .. code:: python - - pair_details = client.get_all_isolated_margin_symbols() - - :returns: API response - - .. code-block:: python - - [ - { - "base": "BNB", - "isBuyAllowed": true, - "isMarginTrade": true, - "isSellAllowed": true, - "quote": "BTC", - "symbol": "BNBBTC" - }, - { - "base": "TRX", - "isBuyAllowed": true, - "isMarginTrade": true, - "isSellAllowed": true, - "quote": "BTC", - "symbol": "TRXBTC" - } - ] - - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'margin/isolated/allPairs', signed=True, data=params) - - def toggle_bnb_burn_spot_margin(self, **params): - """Toggle BNB Burn On Spot Trade And Margin Interest - - https://binance-docs.github.io/apidocs/spot/en/#toggle-bnb-burn-on-spot-trade-and-margin-interest-user_data - - :param spotBNBBurn: Determines whether to use BNB to pay for trading fees on SPOT - :type spotBNBBurn: bool - :param interestBNBBurn: Determines whether to use BNB to pay for margin loan's interest - :type interestBNBBurn: bool - - .. code:: python - - response = client.toggle_bnb_burn_spot_margin() - - :returns: API response - - .. code-block:: python - - { - "spotBNBBurn":true, - "interestBNBBurn": false - } - - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('post', 'bnbBurn', signed=True, data=params) - - def get_bnb_burn_spot_margin(self, **params): - """Get BNB Burn Status - - https://binance-docs.github.io/apidocs/spot/en/#get-bnb-burn-status-user_data - - .. code:: python - - status = client.get_bnb_burn_spot_margin() - - :returns: API response - - .. code-block:: python - - { - "spotBNBBurn":true, - "interestBNBBurn": false - } - - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'bnbBurn', signed=True, data=params) - - def get_margin_price_index(self, **params): - """Query margin priceIndex - - https://binance-docs.github.io/apidocs/spot/en/#query-margin-priceindex-market_data - - :param symbol: name of the symbol pair - :type symbol: str - - .. code:: python - - price_index_details = client.get_margin_price_index(symbol='BTCUSDT') - - :returns: API response - - .. code-block:: python - - { - "calcTime": 1562046418000, - "price": "0.00333930", - "symbol": "BNBBTC" - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'margin/priceIndex', data=params) - - def transfer_margin_to_spot(self, **params): - """Execute transfer between cross-margin account and spot account. - - https://binance-docs.github.io/apidocs/spot/en/#cross-margin-account-transfer-margin - - :param asset: name of the asset - :type asset: str - :param amount: amount to transfer - :type amount: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - .. code:: python - - transfer = client.transfer_margin_to_spot(asset='BTC', amount='1.1') - - :returns: API response - - .. code-block:: python - - { - "tranId": 100000001 - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - params['type'] = 2 - return self._request_margin_api('post', 'margin/transfer', signed=True, data=params) - - def transfer_spot_to_margin(self, **params): - """Execute transfer between spot account and cross-margin account. - - https://binance-docs.github.io/apidocs/spot/en/#cross-margin-account-transfer-margin - - :param asset: name of the asset - :type asset: str - :param amount: amount to transfer - :type amount: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - .. code:: python - - transfer = client.transfer_spot_to_margin(asset='BTC', amount='1.1') - - :returns: API response - - .. code-block:: python - - { - "tranId": 100000001 - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - params['type'] = 1 - return self._request_margin_api('post', 'margin/transfer', signed=True, data=params) - - def transfer_isolated_margin_to_spot(self, **params): - """Execute transfer between isolated margin account and spot account. - - https://binance-docs.github.io/apidocs/spot/en/#isolated-margin-account-transfer-margin - - :param asset: name of the asset - :type asset: str - :param symbol: pair symbol - :type symbol: str - :param amount: amount to transfer - :type amount: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - .. code:: python - - transfer = client.transfer_isolated_margin_to_spot(asset='BTC', - symbol='ETHBTC', amount='1.1') - - :returns: API response - - .. code-block:: python - - { - "tranId": 100000001 - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - params['transFrom'] = "ISOLATED_MARGIN" - params['transTo'] = "SPOT" - return self._request_margin_api('post', 'margin/isolated/transfer', signed=True, data=params) - - def transfer_spot_to_isolated_margin(self, **params): - """Execute transfer between spot account and isolated margin account. - - https://binance-docs.github.io/apidocs/spot/en/#isolated-margin-account-transfer-margin - - :param asset: name of the asset - :type asset: str - :param symbol: pair symbol - :type symbol: str - :param amount: amount to transfer - :type amount: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - .. code:: python - - transfer = client.transfer_spot_to_isolated_margin(asset='BTC', - symbol='ETHBTC', amount='1.1') - - :returns: API response - - .. code-block:: python - - { - "tranId": 100000001 - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - params['transFrom'] = "SPOT" - params['transTo'] = "ISOLATED_MARGIN" - return self._request_margin_api('post', 'margin/isolated/transfer', signed=True, data=params) - - def create_margin_loan(self, **params): - """Apply for a loan in cross-margin or isolated-margin account. - - https://binance-docs.github.io/apidocs/spot/en/#margin-account-borrow-margin - - :param asset: name of the asset - :type asset: str - :param amount: amount to transfer - :type amount: str - :param isIsolated: set to 'TRUE' for isolated margin (default 'FALSE') - :type isIsolated: str - :param symbol: Isolated margin symbol (default blank for cross-margin) - :type symbol: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - .. code:: python - - transaction = client.margin_create_loan(asset='BTC', amount='1.1') - - transaction = client.margin_create_loan(asset='BTC', amount='1.1', - isIsolated='TRUE', symbol='ETHBTC') - - :returns: API response - - .. code-block:: python - - { - "tranId": 100000001 - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('post', 'margin/loan', signed=True, data=params) - - def repay_margin_loan(self, **params): - """Repay loan in cross-margin or isolated-margin account. - - If amount is more than the amount borrowed, the full loan will be repaid. - - https://binance-docs.github.io/apidocs/spot/en/#margin-account-repay-margin - - :param asset: name of the asset - :type asset: str - :param amount: amount to transfer - :type amount: str - :param isIsolated: set to 'TRUE' for isolated margin (default 'FALSE') - :type isIsolated: str - :param symbol: Isolated margin symbol (default blank for cross-margin) - :type symbol: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - .. code:: python - - transaction = client.margin_repay_loan(asset='BTC', amount='1.1') - - transaction = client.margin_repay_loan(asset='BTC', amount='1.1', - isIsolated='TRUE', symbol='ETHBTC') - - :returns: API response - - .. code-block:: python - - { - "tranId": 100000001 - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('post', 'margin/repay', signed=True, data=params) - - def create_margin_order(self, **params): - """Post a new order for margin account. - - https://binance-docs.github.io/apidocs/spot/en/#margin-account-new-order-trade - - :param symbol: required - :type symbol: str - :param isIsolated: set to 'TRUE' for isolated margin (default 'FALSE') - :type isIsolated: str - :param side: required - :type side: str - :param type: required - :type type: str - :param quantity: required - :type quantity: decimal - :param price: required - :type price: str - :param stopPrice: Used with STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, and TAKE_PROFIT_LIMIT orders. - :type stopPrice: str - :param timeInForce: required if limit order GTC,IOC,FOK - :type timeInForce: str - :param newClientOrderId: A unique id for the order. Automatically generated if not sent. - :type newClientOrderId: str - :param icebergQty: Used with LIMIT, STOP_LOSS_LIMIT, and TAKE_PROFIT_LIMIT to create an iceberg order. - :type icebergQty: str - :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; MARKET and LIMIT order types default to - FULL, all other orders default to ACK. - :type newOrderRespType: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - Response ACK: - - .. code-block:: python - - { - "symbol": "BTCUSDT", - "orderId": 28, - "clientOrderId": "6gCrw2kRUAF9CvJDGP16IP", - "transactTime": 1507725176595 - } - - Response RESULT: - - .. code-block:: python - - { - "symbol": "BTCUSDT", - "orderId": 28, - "clientOrderId": "6gCrw2kRUAF9CvJDGP16IP", - "transactTime": 1507725176595, - "price": "1.00000000", - "origQty": "10.00000000", - "executedQty": "10.00000000", - "cummulativeQuoteQty": "10.00000000", - "status": "FILLED", - "timeInForce": "GTC", - "type": "MARKET", - "side": "SELL" - } - - Response FULL: - - .. code-block:: python - - { - "symbol": "BTCUSDT", - "orderId": 28, - "clientOrderId": "6gCrw2kRUAF9CvJDGP16IP", - "transactTime": 1507725176595, - "price": "1.00000000", - "origQty": "10.00000000", - "executedQty": "10.00000000", - "cummulativeQuoteQty": "10.00000000", - "status": "FILLED", - "timeInForce": "GTC", - "type": "MARKET", - "side": "SELL", - "fills": [ - { - "price": "4000.00000000", - "qty": "1.00000000", - "commission": "4.00000000", - "commissionAsset": "USDT" - }, - { - "price": "3999.00000000", - "qty": "5.00000000", - "commission": "19.99500000", - "commissionAsset": "USDT" - }, - { - "price": "3998.00000000", - "qty": "2.00000000", - "commission": "7.99600000", - "commissionAsset": "USDT" - }, - { - "price": "3997.00000000", - "qty": "1.00000000", - "commission": "3.99700000", - "commissionAsset": "USDT" - }, - { - "price": "3995.00000000", - "qty": "1.00000000", - "commission": "3.99500000", - "commissionAsset": "USDT" - } - ] - } - - :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, - BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, - BinanceOrderInactiveSymbolException - - """ - return self._request_margin_api('post', 'margin/order', signed=True, data=params) - - def cancel_margin_order(self, **params): - """Cancel an active order for margin account. - - Either orderId or origClientOrderId must be sent. - - https://binance-docs.github.io/apidocs/spot/en/#margin-account-cancel-order-trade - - :param symbol: required - :type symbol: str - :param isIsolated: set to 'TRUE' for isolated margin (default 'FALSE') - :type isIsolated: str - :param orderId: - :type orderId: str - :param origClientOrderId: - :type origClientOrderId: str - :param newClientOrderId: Used to uniquely identify this cancel. Automatically generated by default. - :type newClientOrderId: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - { - "symbol": "LTCBTC", - "orderId": 28, - "origClientOrderId": "myOrder1", - "clientOrderId": "cancelMyOrder1", - "transactTime": 1507725176595, - "price": "1.00000000", - "origQty": "10.00000000", - "executedQty": "8.00000000", - "cummulativeQuoteQty": "8.00000000", - "status": "CANCELED", - "timeInForce": "GTC", - "type": "LIMIT", - "side": "SELL" - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('delete', 'margin/order', signed=True, data=params) - - def get_margin_loan_details(self, **params): - """Query loan record - - txId or startTime must be sent. txId takes precedence. - - https://binance-docs.github.io/apidocs/spot/en/#query-loan-record-user_data - - :param asset: required - :type asset: str - :param isolatedSymbol: isolated symbol (if querying isolated margin) - :type isolatedSymbol: str - :param txId: the tranId in of the created loan - :type txId: str - :param startTime: earliest timestamp to filter transactions - :type startTime: str - :param endTime: Used to uniquely identify this cancel. Automatically generated by default. - :type endTime: str - :param current: Currently querying page. Start from 1. Default:1 - :type current: str - :param size: Default:10 Max:100 - :type size: int - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - { - "rows": [ - { - "asset": "BNB", - "principal": "0.84624403", - "timestamp": 1555056425000, - //one of PENDING (pending to execution), CONFIRMED (successfully loaned), FAILED (execution failed, nothing happened to your account); - "status": "CONFIRMED" - } - ], - "total": 1 - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'margin/loan', signed=True, data=params) - - def get_margin_repay_details(self, **params): - """Query repay record - - txId or startTime must be sent. txId takes precedence. - - https://binance-docs.github.io/apidocs/spot/en/#query-repay-record-user_data - - :param asset: required - :type asset: str - :param isolatedSymbol: isolated symbol (if querying isolated margin) - :type isolatedSymbol: str - :param txId: the tranId in of the created loan - :type txId: str - :param startTime: - :type startTime: str - :param endTime: Used to uniquely identify this cancel. Automatically generated by default. - :type endTime: str - :param current: Currently querying page. Start from 1. Default:1 - :type current: str - :param size: Default:10 Max:100 - :type size: int - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - { - "rows": [ - { - //Total amount repaid - "amount": "14.00000000", - "asset": "BNB", - //Interest repaid - "interest": "0.01866667", - //Principal repaid - "principal": "13.98133333", - //one of PENDING (pending to execution), CONFIRMED (successfully loaned), FAILED (execution failed, nothing happened to your account); - "status": "CONFIRMED", - "timestamp": 1563438204000, - "txId": 2970933056 - } - ], - "total": 1 - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'margin/repay', signed=True, data=params) - - def get_margin_interest_history(self, **params): - """Get Interest History (USER_DATA) - - https://binance-docs.github.io/apidocs/spot/en/#get-interest-history-user_data - - :param asset: - :type asset: str - :param isolatedSymbol: isolated symbol (if querying isolated margin) - :type isolatedSymbol: str - :param startTime: - :type startTime: str - :param endTime: - :type endTime: str - :param current: Currently querying page. Start from 1. Default:1 - :type current: str - :param size: Default:10 Max:100 - :type size: int - :param archived: Default: false. Set to true for archived data from 6 months ago - :type archived: bool - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - { - "rows":[ - { - "isolatedSymbol": "BNBUSDT", // isolated symbol, will not be returned for crossed margin - "asset": "BNB", - "interest": "0.02414667", - "interestAccuredTime": 1566813600000, - "interestRate": "0.01600000", - "principal": "36.22000000", - "type": "ON_BORROW" - } - ], - "total": 1 - } - - - """ - return self._request_margin_api('get', 'margin/interestHistory', signed=True, data=params) - - def get_margin_force_liquidation_rec(self, **params): - """Get Force Liquidation Record (USER_DATA) - - https://binance-docs.github.io/apidocs/spot/en/#get-force-liquidation-record-user_data - - :param startTime: - :type startTime: str - :param endTime: - :type endTime: str - :param isolatedSymbol: isolated symbol (if querying isolated margin) - :type isolatedSymbol: str - :param current: Currently querying page. Start from 1. Default:1 - :type current: str - :param size: Default:10 Max:100 - :type size: int - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - { - "rows": [ - { - "avgPrice": "0.00388359", - "executedQty": "31.39000000", - "orderId": 180015097, - "price": "0.00388110", - "qty": "31.39000000", - "side": "SELL", - "symbol": "BNBBTC", - "timeInForce": "GTC", - "isIsolated": true, - "updatedTime": 1558941374745 - } - ], - "total": 1 - } - - """ - return self._request_margin_api('get', 'margin/forceLiquidationRec', signed=True, data=params) - - def get_margin_order(self, **params): - """Query margin accounts order - - Either orderId or origClientOrderId must be sent. - - For some historical orders cummulativeQuoteQty will be < 0, meaning the data is not available at this time. - - https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-order-user_data - - :param symbol: required - :type symbol: str - :param isIsolated: set to 'TRUE' for isolated margin (default 'FALSE') - :type isIsolated: str - :param orderId: - :type orderId: str - :param origClientOrderId: - :type origClientOrderId: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - { - "clientOrderId": "ZwfQzuDIGpceVhKW5DvCmO", - "cummulativeQuoteQty": "0.00000000", - "executedQty": "0.00000000", - "icebergQty": "0.00000000", - "isWorking": true, - "orderId": 213205622, - "origQty": "0.30000000", - "price": "0.00493630", - "side": "SELL", - "status": "NEW", - "stopPrice": "0.00000000", - "symbol": "BNBBTC", - "time": 1562133008725, - "timeInForce": "GTC", - "type": "LIMIT", - "updateTime": 1562133008725 - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'margin/order', signed=True, data=params) - - def get_open_margin_orders(self, **params): - """Query margin accounts open orders - - If the symbol is not sent, orders for all symbols will be returned in an array (cross-margin only). - - If querying isolated margin orders, both the isIsolated='TRUE' and symbol=symbol_name must be set. - - When all symbols are returned, the number of requests counted against the rate limiter is equal to the number - of symbols currently trading on the exchange. - - https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-open-order-user_data - - :param symbol: optional - :type symbol: str - :param isIsolated: set to 'TRUE' for isolated margin (default 'FALSE') - :type isIsolated: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - [ - { - "clientOrderId": "qhcZw71gAkCCTv0t0k8LUK", - "cummulativeQuoteQty": "0.00000000", - "executedQty": "0.00000000", - "icebergQty": "0.00000000", - "isWorking": true, - "orderId": 211842552, - "origQty": "0.30000000", - "price": "0.00475010", - "side": "SELL", - "status": "NEW", - "stopPrice": "0.00000000", - "symbol": "BNBBTC", - "time": 1562040170089, - "timeInForce": "GTC", - "type": "LIMIT", - "updateTime": 1562040170089 - } - ] - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'margin/openOrders', signed=True, data=params) - - def get_all_margin_orders(self, **params): - """Query all margin accounts orders - - If orderId is set, it will get orders >= that orderId. Otherwise most recent orders are returned. - - For some historical orders cummulativeQuoteQty will be < 0, meaning the data is not available at this time. - - https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-all-order-user_data - - :param symbol: required - :type symbol: str - :param isIsolated: set to 'TRUE' for isolated margin (default 'FALSE') - :type isIsolated: str - :param orderId: optional - :type orderId: str - :param startTime: optional - :type startTime: str - :param endTime: optional - :type endTime: str - :param limit: Default 500; max 1000 - :type limit: int - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - [ - { - "id": 43123876, - "price": "0.00395740", - "qty": "4.06000000", - "quoteQty": "0.01606704", - "symbol": "BNBBTC", - "time": 1556089977693 - }, - { - "id": 43123877, - "price": "0.00395740", - "qty": "0.77000000", - "quoteQty": "0.00304719", - "symbol": "BNBBTC", - "time": 1556089977693 - }, - { - "id": 43253549, - "price": "0.00428930", - "qty": "23.30000000", - "quoteQty": "0.09994069", - "symbol": "BNBBTC", - "time": 1556163963504 - } - ] - - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'margin/allOrders', signed=True, data=params) - - def get_margin_trades(self, **params): - """Query margin accounts trades - - If fromId is set, it will get orders >= that fromId. Otherwise most recent orders are returned. - - https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-trade-list-user_data - - :param symbol: required - :type symbol: str - :param isIsolated: set to 'TRUE' for isolated margin (default 'FALSE') - :type isIsolated: str - :param fromId: optional - :type fromId: str - :param startTime: optional - :type startTime: str - :param endTime: optional - :type endTime: str - :param limit: Default 500; max 1000 - :type limit: int - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - [ - { - "commission": "0.00006000", - "commissionAsset": "BTC", - "id": 34, - "isBestMatch": true, - "isBuyer": false, - "isMaker": false, - "orderId": 39324, - "price": "0.02000000", - "qty": "3.00000000", - "symbol": "BNBBTC", - "time": 1561973357171 - }, { - "commission": "0.00002950", - "commissionAsset": "BTC", - "id": 32, - "isBestMatch": true, - "isBuyer": false, - "isMaker": true, - "orderId": 39319, - "price": "0.00590000", - "qty": "5.00000000", - "symbol": "BNBBTC", - "time": 1561964645345 - } - ] - - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'margin/myTrades', signed=True, data=params) - - def get_max_margin_loan(self, **params): - """Query max borrow amount for an asset - - https://binance-docs.github.io/apidocs/spot/en/#query-max-borrow-user_data - - :param asset: required - :type asset: str - :param isolatedSymbol: isolated symbol (if querying isolated margin) - :type isolatedSymbol: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - { - "amount": "1.69248805" - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'margin/maxBorrowable', signed=True, data=params) - - def get_max_margin_transfer(self, **params): - """Query max transfer-out amount - - https://binance-docs.github.io/apidocs/spot/en/#query-max-transfer-out-amount-user_data - - :param asset: required - :type asset: str - :param isolatedSymbol: isolated symbol (if querying isolated margin) - :type isolatedSymbol: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - { - "amount": "3.59498107" - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'margin/maxTransferable', signed=True, data=params) - - # Margin OCO - - def create_margin_oco_order(self, **params): - """Post a new OCO trade for margin account. - - https://binance-docs.github.io/apidocs/spot/en/#margin-account-new-oco-trade - - - :param symbol: required - :type symbol: str - :param isIsolated: for isolated margin or not, "TRUE", "FALSE",default "FALSE" - :type symbol: str - :param listClientOrderId: A unique id for the list order. Automatically generated if not sent. - :type listClientOrderId: str - :param side: required - :type side: str - :param quantity: required - :type quantity: decimal - :param limitClientOrderId: A unique id for the limit order. Automatically generated if not sent. - :type limitClientOrderId: str - :param price: required - :type price: str - :param limitIcebergQty: Used to make the LIMIT_MAKER leg an iceberg order. - :type limitIcebergQty: decimal - :param stopClientOrderId: A unique Id for the stop loss/stop loss limit leg. Automatically generated if not sent. - :type stopClientOrderId: str - :param stopPrice: required - :type stopPrice: str - :param stopLimitPrice: If provided, stopLimitTimeInForce is required. - :type stopLimitPrice: str - :param stopIcebergQty: Used with STOP_LOSS_LIMIT leg to make an iceberg order. - :type stopIcebergQty: decimal - :param stopLimitTimeInForce: Valid values are GTC/FOK/IOC. - :type stopLimitTimeInForce: str - :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; default: RESULT. - :type newOrderRespType: str - :param sideEffectType: NO_SIDE_EFFECT, MARGIN_BUY, AUTO_REPAY; default NO_SIDE_EFFECT. - :type sideEffectType: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "orderListId": 0, - "contingencyType": "OCO", - "listStatusType": "EXEC_STARTED", - "listOrderStatus": "EXECUTING", - "listClientOrderId": "JYVpp3F0f5CAG15DhtrqLp", - "transactionTime": 1563417480525, - "symbol": "LTCBTC", - "marginBuyBorrowAmount": "5", // will not return if no margin trade happens - "marginBuyBorrowAsset": "BTC", // will not return if no margin trade happens - "isIsolated": false, // if isolated margin - "orders": [ - { - "symbol": "LTCBTC", - "orderId": 2, - "clientOrderId": "Kk7sqHb9J6mJWTMDVW7Vos" - }, - { - "symbol": "LTCBTC", - "orderId": 3, - "clientOrderId": "xTXKaGYd4bluPVp78IVRvl" - } - ], - "orderReports": [ - { - "symbol": "LTCBTC", - "orderId": 2, - "orderListId": 0, - "clientOrderId": "Kk7sqHb9J6mJWTMDVW7Vos", - "transactTime": 1563417480525, - "price": "0.000000", - "origQty": "0.624363", - "executedQty": "0.000000", - "cummulativeQuoteQty": "0.000000", - "status": "NEW", - "timeInForce": "GTC", - "type": "STOP_LOSS", - "side": "BUY", - "stopPrice": "0.960664" - }, - { - "symbol": "LTCBTC", - "orderId": 3, - "orderListId": 0, - "clientOrderId": "xTXKaGYd4bluPVp78IVRvl", - "transactTime": 1563417480525, - "price": "0.036435", - "origQty": "0.624363", - "executedQty": "0.000000", - "cummulativeQuoteQty": "0.000000", - "status": "NEW", - "timeInForce": "GTC", - "type": "LIMIT_MAKER", - "side": "BUY" - } - ] - } - - :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, - BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, - BinanceOrderInactiveSymbolException - - """ - return self._request_margin_api('post', 'margin/order/oco', signed=True, data=params) - - def cancel_margin_oco_order(self, **params): - """Cancel an entire Order List for a margin account. - - https://binance-docs.github.io/apidocs/spot/en/#margin-account-cancel-oco-trade - - :param symbol: required - :type symbol: str - :param isIsolated: for isolated margin or not, "TRUE", "FALSE",default "FALSE" - :type symbol: str - :param orderListId: Either orderListId or listClientOrderId must be provided - :type orderListId: int - :param listClientOrderId: Either orderListId or listClientOrderId must be provided - :type listClientOrderId: str - :param newClientOrderId: Used to uniquely identify this cancel. Automatically generated by default. - :type newClientOrderId: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "orderListId": 0, - "contingencyType": "OCO", - "listStatusType": "ALL_DONE", - "listOrderStatus": "ALL_DONE", - "listClientOrderId": "C3wyj4WVEktd7u9aVBRXcN", - "transactionTime": 1574040868128, - "symbol": "LTCBTC", - "isIsolated": false, // if isolated margin - "orders": [ - { - "symbol": "LTCBTC", - "orderId": 2, - "clientOrderId": "pO9ufTiFGg3nw2fOdgeOXa" - }, - { - "symbol": "LTCBTC", - "orderId": 3, - "clientOrderId": "TXOvglzXuaubXAaENpaRCB" - } - ], - "orderReports": [ - { - "symbol": "LTCBTC", - "origClientOrderId": "pO9ufTiFGg3nw2fOdgeOXa", - "orderId": 2, - "orderListId": 0, - "clientOrderId": "unfWT8ig8i0uj6lPuYLez6", - "price": "1.00000000", - "origQty": "10.00000000", - "executedQty": "0.00000000", - "cummulativeQuoteQty": "0.00000000", - "status": "CANCELED", - "timeInForce": "GTC", - "type": "STOP_LOSS_LIMIT", - "side": "SELL", - "stopPrice": "1.00000000" - }, - { - "symbol": "LTCBTC", - "origClientOrderId": "TXOvglzXuaubXAaENpaRCB", - "orderId": 3, - "orderListId": 0, - "clientOrderId": "unfWT8ig8i0uj6lPuYLez6", - "price": "3.00000000", - "origQty": "10.00000000", - "executedQty": "0.00000000", - "cummulativeQuoteQty": "0.00000000", - "status": "CANCELED", - "timeInForce": "GTC", - "type": "LIMIT_MAKER", - "side": "SELL" - } - ] - } - - """ - return self._request_margin_api('delete', 'margin/orderList', signed=True, data=params) - - def get_margin_oco_order(self, **params): - """Retrieves a specific OCO based on provided optional parameters - - https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-oco-user_data - - :param isIsolated: for isolated margin or not, "TRUE", "FALSE",default "FALSE" - :type symbol: str - :param symbol: mandatory for isolated margin, not supported for cross margin - :type symbol: str - :param orderListId: Either orderListId or listClientOrderId must be provided - :type orderListId: int - :param listClientOrderId: Either orderListId or listClientOrderId must be provided - :type listClientOrderId: str - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - { - "orderListId": 27, - "contingencyType": "OCO", - "listStatusType": "EXEC_STARTED", - "listOrderStatus": "EXECUTING", - "listClientOrderId": "h2USkA5YQpaXHPIrkd96xE", - "transactionTime": 1565245656253, - "symbol": "LTCBTC", - "isIsolated": false, // if isolated margin - "orders": [ - { - "symbol": "LTCBTC", - "orderId": 4, - "clientOrderId": "qD1gy3kc3Gx0rihm9Y3xwS" - }, - { - "symbol": "LTCBTC", - "orderId": 5, - "clientOrderId": "ARzZ9I00CPM8i3NhmU9Ega" - } - ] - } - - """ - return self._request_margin_api('get', 'margin/orderList', signed=True, data=params) - - def get_open_margin_oco_orders(self, **params): - """Retrieves open OCO trades - - https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-open-oco-user_data - - :param isIsolated: for isolated margin or not, "TRUE", "FALSE",default "FALSE" - :type symbol: str - :param symbol: mandatory for isolated margin, not supported for cross margin - :type symbol: str - :param fromId: If supplied, neither startTime or endTime can be provided - :type fromId: int - :param startTime: optional - :type startTime: int - :param endTime: optional - :type endTime: int - :param limit: optional Default Value: 500; Max Value: 1000 - :type limit: int - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - [ - { - "orderListId": 29, - "contingencyType": "OCO", - "listStatusType": "EXEC_STARTED", - "listOrderStatus": "EXECUTING", - "listClientOrderId": "amEEAXryFzFwYF1FeRpUoZ", - "transactionTime": 1565245913483, - "symbol": "LTCBTC", - "isIsolated": true, // if isolated margin - "orders": [ - { - "symbol": "LTCBTC", - "orderId": 4, - "clientOrderId": "oD7aesZqjEGlZrbtRpy5zB" - }, - { - "symbol": "LTCBTC", - "orderId": 5, - "clientOrderId": "Jr1h6xirOxgeJOUuYQS7V3" - } - ] - }, - { - "orderListId": 28, - "contingencyType": "OCO", - "listStatusType": "EXEC_STARTED", - "listOrderStatus": "EXECUTING", - "listClientOrderId": "hG7hFNxJV6cZy3Ze4AUT4d", - "transactionTime": 1565245913407, - "symbol": "LTCBTC", - "orders": [ - { - "symbol": "LTCBTC", - "orderId": 2, - "clientOrderId": "j6lFOfbmFMRjTYA7rRJ0LP" - }, - { - "symbol": "LTCBTC", - "orderId": 3, - "clientOrderId": "z0KCjOdditiLS5ekAFtK81" - } - ] - } - ] - - """ - return self._request_margin_api('get', 'margin/allOrderList', signed=True, data=params) - - # Cross-margin - - def margin_stream_get_listen_key(self): - """Start a new cross-margin data stream and return the listen key - If a stream already exists it should return the same key. - If the stream becomes invalid a new key is returned. - - Can be used to keep the stream alive. - - https://binance-docs.github.io/apidocs/spot/en/#listen-key-margin - - :returns: API response - - .. code-block:: python - - { - "listenKey": "pqia91ma19a5s61cv6a81va65sdf19v8a65a1a5s61cv6a81va65sdf19v8a65a1" - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - res = self._request_margin_api('post', 'userDataStream', signed=False, data={}) - return res['listenKey'] - - def margin_stream_keepalive(self, listenKey): - """PING a cross-margin data stream to prevent a time out. - - https://binance-docs.github.io/apidocs/spot/en/#listen-key-margin - - :param listenKey: required - :type listenKey: str - - :returns: API response - - .. code-block:: python - - {} - - :raises: BinanceRequestException, BinanceAPIException - - """ - params = { - 'listenKey': listenKey - } - return self._request_margin_api('put', 'userDataStream', signed=False, data=params) - - def margin_stream_close(self, listenKey): - """Close out a cross-margin data stream. - - https://binance-docs.github.io/apidocs/spot/en/#listen-key-margin - - :param listenKey: required - :type listenKey: str - - :returns: API response - - .. code-block:: python - - {} - - :raises: BinanceRequestException, BinanceAPIException - - """ - params = { - 'listenKey': listenKey - } - return self._request_margin_api('delete', 'userDataStream', signed=False, data=params) - - # Isolated margin - - def isolated_margin_stream_get_listen_key(self, symbol): - """Start a new isolated margin data stream and return the listen key - If a stream already exists it should return the same key. - If the stream becomes invalid a new key is returned. - - Can be used to keep the stream alive. - - https://binance-docs.github.io/apidocs/spot/en/#listen-key-isolated-margin - - :param symbol: required - symbol for the isolated margin account - :type symbol: str - - :returns: API response - - .. code-block:: python - - { - "listenKey": "T3ee22BIYuWqmvne0HNq2A2WsFlEtLhvWCtItw6ffhhdmjifQ2tRbuKkTHhr" - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - params = { - 'symbol': symbol - } - res = self._request_margin_api('post', 'userDataStream/isolated', signed=False, data=params) - return res['listenKey'] - - def isolated_margin_stream_keepalive(self, symbol, listenKey): - """PING an isolated margin data stream to prevent a time out. - - https://binance-docs.github.io/apidocs/spot/en/#listen-key-isolated-margin - - :param symbol: required - symbol for the isolated margin account - :type symbol: str - :param listenKey: required - :type listenKey: str - - :returns: API response - - .. code-block:: python - - {} - - :raises: BinanceRequestException, BinanceAPIException - - """ - params = { - 'symbol': symbol, - 'listenKey': listenKey - } - return self._request_margin_api('put', 'userDataStream/isolated', signed=False, data=params) - - def isolated_margin_stream_close(self, symbol, listenKey): - """Close out an isolated margin data stream. - - https://binance-docs.github.io/apidocs/spot/en/#listen-key-isolated-margin - - :param symbol: required - symbol for the isolated margin account - :type symbol: str - :param listenKey: required - :type listenKey: str - - :returns: API response - - .. code-block:: python - - {} - - :raises: BinanceRequestException, BinanceAPIException - - """ - params = { - 'symbol': symbol, - 'listenKey': listenKey - } - return self._request_margin_api('delete', 'userDataStream/isolated', signed=False, data=params) - - # Lending Endpoints - - def get_lending_product_list(self, **params): - """Get Lending Product List - - https://binance-docs.github.io/apidocs/spot/en/#get-flexible-product-list-user_data - - """ - return self._request_margin_api('get', 'lending/daily/product/list', signed=True, data=params) - - def get_lending_daily_quota_left(self, **params): - """Get Left Daily Purchase Quota of Flexible Product. - - https://binance-docs.github.io/apidocs/spot/en/#get-left-daily-purchase-quota-of-flexible-product-user_data - - """ - return self._request_margin_api('get', 'lending/daily/userLeftQuota', signed=True, data=params) - - def purchase_lending_product(self, **params): - """Purchase Flexible Product - - https://binance-docs.github.io/apidocs/spot/en/#purchase-flexible-product-user_data - - """ - return self._request_margin_api('post', 'lending/daily/purchase', signed=True, data=params) - - def get_lending_daily_redemption_quota(self, **params): - """Get Left Daily Redemption Quota of Flexible Product - - https://binance-docs.github.io/apidocs/spot/en/#get-left-daily-redemption-quota-of-flexible-product-user_data - - """ - return self._request_margin_api('get', 'lending/daily/userRedemptionQuota', signed=True, data=params) - - def redeem_lending_product(self, **params): - """Redeem Flexible Product - - https://binance-docs.github.io/apidocs/spot/en/#redeem-flexible-product-user_data - - """ - return self._request_margin_api('post', 'lending/daily/redeem', signed=True, data=params) - - def get_lending_position(self, **params): - """Get Flexible Product Position - - https://binance-docs.github.io/apidocs/spot/en/#get-flexible-product-position-user_data - - """ - return self._request_margin_api('get', 'lending/daily/token/position', signed=True, data=params) - - def get_fixed_activity_project_list(self, **params): - """Get Fixed and Activity Project List - - https://binance-docs.github.io/apidocs/spot/en/#get-fixed-and-activity-project-list-user_data - - :param asset: optional - :type asset: str - :param type: required - "ACTIVITY", "CUSTOMIZED_FIXED" - :type type: str - :param status: optional - "ALL", "SUBSCRIBABLE", "UNSUBSCRIBABLE"; default "ALL" - :type status: str - :param sortBy: optional - "START_TIME", "LOT_SIZE", "INTEREST_RATE", "DURATION"; default "START_TIME" - :type sortBy: str - :param current: optional - Currently querying page. Start from 1. Default:1 - :type current: int - :param size: optional - Default:10, Max:100 - :type size: int - :param recvWindow: the number of milliseconds the request is valid for - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - [ - { - "asset": "USDT", - "displayPriority": 1, - "duration": 90, - "interestPerLot": "1.35810000", - "interestRate": "0.05510000", - "lotSize": "100.00000000", - "lotsLowLimit": 1, - "lotsPurchased": 74155, - "lotsUpLimit": 80000, - "maxLotsPerUser": 2000, - "needKyc": False, - "projectId": "CUSDT90DAYSS001", - "projectName": "USDT", - "status": "PURCHASING", - "type": "CUSTOMIZED_FIXED", - "withAreaLimitation": False - } - ] - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'lending/project/list', signed=True, data=params) - - def get_lending_account(self, **params): - """Get Lending Account Details - - https://binance-docs.github.io/apidocs/spot/en/#lending-account-user_data - - """ - return self._request_margin_api('get', 'lending/union/account', signed=True, data=params) - - def get_lending_purchase_history(self, **params): - """Get Lending Purchase History - - https://binance-docs.github.io/apidocs/spot/en/#get-purchase-record-user_data - - """ - return self._request_margin_api('get', 'lending/union/purchaseRecord', signed=True, data=params) - - def get_lending_redemption_history(self, **params): - """Get Lending Redemption History - - https://binance-docs.github.io/apidocs/spot/en/#get-redemption-record-user_data - - """ - return self._request_margin_api('get', 'lending/union/redemptionRecord', signed=True, data=params) - - def get_lending_interest_history(self, **params): - """Get Lending Interest History - - https://binance-docs.github.io/apidocs/spot/en/#get-interest-history-user_data-2 - - """ - return self._request_margin_api('get', 'lending/union/interestHistory', signed=True, data=params) - - def change_fixed_activity_to_daily_position(self, **params): - """Change Fixed/Activity Position to Daily Position - - https://binance-docs.github.io/apidocs/spot/en/#change-fixed-activity-position-to-daily-position-user_data - - """ - return self._request_margin_api('post', 'lending/positionChanged', signed=True, data=params) - - # Sub Accounts - - def get_sub_account_list(self, **params): - """Query Sub-account List. - - https://binance-docs.github.io/apidocs/spot/en/#query-sub-account-list-sapi-for-master-account - - :param email: optional - Sub-account email - :type email: str - :param isFreeze: optional - :type isFreeze: str - :param page: optional - Default value: 1 - :type page: int - :param limit: optional - Default value: 1, Max value: 200 - :type limit: int - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "subAccounts":[ - { - "email":"testsub@gmail.com", - "isFreeze":false, - "createTime":1544433328000 - }, - { - "email":"virtual@oxebmvfonoemail.com", - "isFreeze":false, - "createTime":1544433328000 - } - ] - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'sub-account/list', True, data=params) - - def get_sub_account_transfer_history(self, **params): - """Query Sub-account Transfer History. - - https://binance-docs.github.io/apidocs/spot/en/#query-sub-account-spot-asset-transfer-history-sapi-for-master-account - - :param fromEmail: optional - :type fromEmail: str - :param toEmail: optional - :type toEmail: str - :param startTime: optional - :type startTime: int - :param endTime: optional - :type endTime: int - :param page: optional - Default value: 1 - :type page: int - :param limit: optional - Default value: 500 - :type limit: int - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - [ - { - "from":"aaa@test.com", - "to":"bbb@test.com", - "asset":"BTC", - "qty":"10", - "status": "SUCCESS", - "tranId": 6489943656, - "time":1544433328000 - }, - { - "from":"bbb@test.com", - "to":"ccc@test.com", - "asset":"ETH", - "qty":"2", - "status": "SUCCESS", - "tranId": 6489938713, - "time":1544433328000 - } - ] - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'sub-account/sub/transfer/history', True, data=params) - - def get_sub_account_futures_transfer_history(self, **params): - """Query Sub-account Futures Transfer History. - - https://binance-docs.github.io/apidocs/spot/en/#query-sub-account-futures-asset-transfer-history-for-master-account - - :param email: required - :type email: str - :param futuresType: required - :type futuresType: int - :param startTime: optional - :type startTime: int - :param endTime: optional - :type endTime: int - :param page: optional - :type page: int - :param limit: optional - :type limit: int - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "success":true, - "futuresType": 2, - "transfers":[ - { - "from":"aaa@test.com", - "to":"bbb@test.com", - "asset":"BTC", - "qty":"1", - "time":1544433328000 - }, - { - "from":"bbb@test.com", - "to":"ccc@test.com", - "asset":"ETH", - "qty":"2", - "time":1544433328000 - } - ] - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'sub-account/futures/internalTransfer', True, data=params) - - def create_sub_account_futures_transfer(self, **params): - """Execute sub-account Futures transfer - - https://github.com/binance-exchange/binance-official-api-docs/blob/9dbe0e961b80557bb19708a707c7fad08842b28e/wapi-api.md#sub-account-transferfor-master-account - - :param fromEmail: required - Sender email - :type fromEmail: str - :param toEmail: required - Recipient email - :type toEmail: str - :param futuresType: required - :type futuresType: int - :param asset: required - :type asset: str - :param amount: required - :type amount: decimal - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "success":true, - "txnId":"2934662589" - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('post', 'sub-account/futures/internalTransfer', True, data=params) - - def get_sub_account_assets(self, **params): - """Fetch sub-account assets - - https://binance-docs.github.io/apidocs/spot/en/#query-sub-account-assets-sapi-for-master-account - - :param email: required - :type email: str - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "balances":[ - { - "asset":"ADA", - "free":10000, - "locked":0 - }, - { - "asset":"BNB", - "free":10003, - "locked":0 - }, - { - "asset":"BTC", - "free":11467.6399, - "locked":0 - }, - { - "asset":"ETH", - "free":10004.995, - "locked":0 - }, - { - "asset":"USDT", - "free":11652.14213, - "locked":0 - } - ] - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'sub-account/assets', True, data=params) - - def query_subaccount_spot_summary(self, **params): - """Query Sub-account Spot Assets Summary (For Master Account) - - https://binance-docs.github.io/apidocs/spot/en/#query-sub-account-spot-assets-summary-for-master-account - - :param email: optional - Sub account email - :type email: str - :param page: optional - default 1 - :type page: int - :param size: optional - default 10, max 20 - :type size: int - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "totalCount":2, - "masterAccountTotalAsset": "0.23231201", - "spotSubUserAssetBtcVoList":[ - { - "email":"sub123@test.com", - "totalAsset":"9999.00000000" - }, - { - "email":"test456@test.com", - "totalAsset":"0.00000000" - } - ] - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'sub-account/spotSummary', True, data=params) - - def get_subaccount_deposit_address(self, **params): - """Get Sub-account Deposit Address (For Master Account) - - https://binance-docs.github.io/apidocs/spot/en/#get-sub-account-deposit-address-for-master-account - - :param email: required - Sub account email - :type email: str - :param coin: required - :type coin: str - :param network: optional - :type network: str - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "address":"TDunhSa7jkTNuKrusUTU1MUHtqXoBPKETV", - "coin":"USDT", - "tag":"", - "url":"https://tronscan.org/#/address/TDunhSa7jkTNuKrusUTU1MUHtqXoBPKETV" - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'capital/deposit/subAddress', True, data=params) - - def get_subaccount_deposit_history(self, **params): - """Get Sub-account Deposit History (For Master Account) - - https://binance-docs.github.io/apidocs/spot/en/#get-sub-account-deposit-address-for-master-account - - :param email: required - Sub account email - :type email: str - :param coin: optional - :type coin: str - :param status: optional - (0:pending,6: credited but cannot withdraw, 1:success) - :type status: int - :param startTime: optional - :type startTime: int - :param endTime: optional - :type endTime: int - :param limit: optional - :type limit: int - :param offset: optional - default:0 - :type offset: int - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - [ - { - "amount":"0.00999800", - "coin":"PAXG", - "network":"ETH", - "status":1, - "address":"0x788cabe9236ce061e5a892e1a59395a81fc8d62c", - "addressTag":"", - "txId":"0xaad4654a3234aa6118af9b4b335f5ae81c360b2394721c019b5d1e75328b09f3", - "insertTime":1599621997000, - "transferType":0, - "confirmTimes":"12/12" - }, - { - "amount":"0.50000000", - "coin":"IOTA", - "network":"IOTA", - "status":1, - "address":"SIZ9VLMHWATXKV99LH99CIGFJFUMLEHGWVZVNNZXRJJVWBPHYWPPBOSDORZ9EQSHCZAMPVAPGFYQAUUV9DROOXJLNW", - "addressTag":"", - "txId":"ESBFVQUTPIWQNJSPXFNHNYHSQNTGKRVKPRABQWTAXCDWOAKDKYWPTVG9BGXNVNKTLEJGESAVXIKIZ9999", - "insertTime":1599620082000, - "transferType":0, - "confirmTimes":"1/1" - } - ] - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'capital/deposit/subHisrec', True, data=params) - - def get_subaccount_futures_margin_status(self, **params): - """Get Sub-account's Status on Margin/Futures (For Master Account) - - https://binance-docs.github.io/apidocs/spot/en/#get-sub-account-39-s-status-on-margin-futures-for-master-account - - :param email: optional - Sub account email - :type email: str - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - [ - { - "email":"123@test.com", // user email - "isSubUserEnabled": true, // true or false - "isUserActive": true, // true or false - "insertTime": 1570791523523 // sub account create time - "isMarginEnabled": true, // true or false for margin - "isFutureEnabled": true // true or false for futures. - "mobile": 1570791523523 // user mobile number - } - ] - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'sub-account/status', True, data=params) - - def enable_subaccount_margin(self, **params): - """Enable Margin for Sub-account (For Master Account) - - https://binance-docs.github.io/apidocs/spot/en/#enable-margin-for-sub-account-for-master-account - - :param email: required - Sub account email - :type email: str - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - - "email":"123@test.com", - - "isMarginEnabled": true - - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('post', 'sub-account/margin/enable', True, data=params) - - def get_subaccount_margin_details(self, **params): - """Get Detail on Sub-account's Margin Account (For Master Account) - - https://binance-docs.github.io/apidocs/spot/en/#get-detail-on-sub-account-39-s-margin-account-for-master-account - - :param email: required - Sub account email - :type email: str - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "email":"123@test.com", - "marginLevel": "11.64405625", - "totalAssetOfBtc": "6.82728457", - "totalLiabilityOfBtc": "0.58633215", - "totalNetAssetOfBtc": "6.24095242", - "marginTradeCoeffVo": - { - "forceLiquidationBar": "1.10000000", // Liquidation margin ratio - "marginCallBar": "1.50000000", // Margin call margin ratio - "normalBar": "2.00000000" // Initial margin ratio - }, - "marginUserAssetVoList": [ - { - "asset": "BTC", - "borrowed": "0.00000000", - "free": "0.00499500", - "interest": "0.00000000", - "locked": "0.00000000", - "netAsset": "0.00499500" - }, - { - "asset": "BNB", - "borrowed": "201.66666672", - "free": "2346.50000000", - "interest": "0.00000000", - "locked": "0.00000000", - "netAsset": "2144.83333328" - }, - { - "asset": "ETH", - "borrowed": "0.00000000", - "free": "0.00000000", - "interest": "0.00000000", - "locked": "0.00000000", - "netAsset": "0.00000000" - }, - { - "asset": "USDT", - "borrowed": "0.00000000", - "free": "0.00000000", - "interest": "0.00000000", - "locked": "0.00000000", - "netAsset": "0.00000000" - } - ] - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'sub-account/margin/account', True, data=params) - - def get_subaccount_margin_summary(self, **params): - """Get Summary of Sub-account's Margin Account (For Master Account) - - https://binance-docs.github.io/apidocs/spot/en/#get-summary-of-sub-account-39-s-margin-account-for-master-account - - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "totalAssetOfBtc": "4.33333333", - "totalLiabilityOfBtc": "2.11111112", - "totalNetAssetOfBtc": "2.22222221", - "subAccountList":[ - { - "email":"123@test.com", - "totalAssetOfBtc": "2.11111111", - "totalLiabilityOfBtc": "1.11111111", - "totalNetAssetOfBtc": "1.00000000" - }, - { - "email":"345@test.com", - "totalAssetOfBtc": "2.22222222", - "totalLiabilityOfBtc": "1.00000001", - "totalNetAssetOfBtc": "1.22222221" - } - ] - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'sub-account/margin/accountSummary', True, data=params) - - def enable_subaccount_futures(self, **params): - """Enable Futures for Sub-account (For Master Account) - - https://binance-docs.github.io/apidocs/spot/en/#enable-futures-for-sub-account-for-master-account - - :param email: required - Sub account email - :type email: str - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - - "email":"123@test.com", - - "isFuturesEnabled": true // true or false - - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('post', 'sub-account/futures/enable', True, data=params) - - def get_subaccount_futures_details(self, **params): - """Get Detail on Sub-account's Futures Account (For Master Account) - - https://binance-docs.github.io/apidocs/spot/en/#get-detail-on-sub-account-39-s-futures-account-for-master-account - - :param email: required - Sub account email - :type email: str - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "email": "abc@test.com", - "asset": "USDT", - "assets":[ - { - "asset": "USDT", - "initialMargin": "0.00000000", - "maintenanceMargin": "0.00000000", - "marginBalance": "0.88308000", - "maxWithdrawAmount": "0.88308000", - "openOrderInitialMargin": "0.00000000", - "positionInitialMargin": "0.00000000", - "unrealizedProfit": "0.00000000", - "walletBalance": "0.88308000" - } - ], - "canDeposit": true, - "canTrade": true, - "canWithdraw": true, - "feeTier": 2, - "maxWithdrawAmount": "0.88308000", - "totalInitialMargin": "0.00000000", - "totalMaintenanceMargin": "0.00000000", - "totalMarginBalance": "0.88308000", - "totalOpenOrderInitialMargin": "0.00000000", - "totalPositionInitialMargin": "0.00000000", - "totalUnrealizedProfit": "0.00000000", - "totalWalletBalance": "0.88308000", - "updateTime": 1576756674610 - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'sub-account/futures/account', True, data=params) - - def get_subaccount_futures_summary(self, **params): - """Get Summary of Sub-account's Futures Account (For Master Account) - - https://binance-docs.github.io/apidocs/spot/en/#get-summary-of-sub-account-39-s-futures-account-for-master-account - - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "totalInitialMargin": "9.83137400", - "totalMaintenanceMargin": "0.41568700", - "totalMarginBalance": "23.03235621", - "totalOpenOrderInitialMargin": "9.00000000", - "totalPositionInitialMargin": "0.83137400", - "totalUnrealizedProfit": "0.03219710", - "totalWalletBalance": "22.15879444", - "asset": "USDT", - "subAccountList":[ - { - "email": "123@test.com", - "totalInitialMargin": "9.00000000", - "totalMaintenanceMargin": "0.00000000", - "totalMarginBalance": "22.12659734", - "totalOpenOrderInitialMargin": "9.00000000", - "totalPositionInitialMargin": "0.00000000", - "totalUnrealizedProfit": "0.00000000", - "totalWalletBalance": "22.12659734", - "asset": "USDT" - }, - { - "email": "345@test.com", - "totalInitialMargin": "0.83137400", - "totalMaintenanceMargin": "0.41568700", - "totalMarginBalance": "0.90575887", - "totalOpenOrderInitialMargin": "0.00000000", - "totalPositionInitialMargin": "0.83137400", - "totalUnrealizedProfit": "0.03219710", - "totalWalletBalance": "0.87356177", - "asset": "USDT" - } - ] - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'sub-account/futures/accountSummary', True, data=params) - - def get_subaccount_futures_positionrisk(self, **params): - """Get Futures Position-Risk of Sub-account (For Master Account) - - https://binance-docs.github.io/apidocs/spot/en/#get-futures-position-risk-of-sub-account-for-master-account - - :param email: required - Sub account email - :type email: str - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - [ - { - "entryPrice": "9975.12000", - "leverage": "50", // current initial leverage - "maxNotional": "1000000", // notional value limit of current initial leverage - "liquidationPrice": "7963.54", - "markPrice": "9973.50770517", - "positionAmount": "0.010", - "symbol": "BTCUSDT", - "unrealizedProfit": "-0.01612295" - } - ] - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'sub-account/futures/positionRisk', True, data=params) - - def make_subaccount_futures_transfer(self, **params): - """Futures Transfer for Sub-account (For Master Account) - - https://binance-docs.github.io/apidocs/spot/en/#futures-transfer-for-sub-account-for-master-account - - :param email: required - Sub account email - :type email: str - :param asset: required - The asset being transferred, e.g., USDT - :type asset: str - :param amount: required - The amount to be transferred - :type amount: float - :param type: required - 1: transfer from subaccount's spot account to its USDT-margined futures account - 2: transfer from subaccount's USDT-margined futures account to its spot account - 3: transfer from subaccount's spot account to its COIN-margined futures account - 4: transfer from subaccount's COIN-margined futures account to its spot account - :type type: int - - :returns: API response - - .. code-block:: python - - { - "txnId":"2966662589" - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('post', 'sub-account/futures/transfer', True, data=params) - - def make_subaccount_margin_transfer(self, **params): - """Margin Transfer for Sub-account (For Master Account) - - https://binance-docs.github.io/apidocs/spot/en/#margin-transfer-for-sub-account-for-master-account - - :param email: required - Sub account email - :type email: str - :param asset: required - The asset being transferred, e.g., USDT - :type asset: str - :param amount: required - The amount to be transferred - :type amount: float - :param type: required - 1: transfer from subaccount's spot account to margin account - 2: transfer from subaccount's margin account to its spot account - :type type: int - - :returns: API response - - .. code-block:: python - - { - "txnId":"2966662589" - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('post', 'sub-account/margin/transfer', True, data=params) - - def make_subaccount_to_subaccount_transfer(self, **params): - """Transfer to Sub-account of Same Master (For Sub-account) - - https://binance-docs.github.io/apidocs/spot/en/#transfer-to-sub-account-of-same-master-for-sub-account - - :param toEmail: required - Sub account email - :type toEmail: str - :param asset: required - The asset being transferred, e.g., USDT - :type asset: str - :param amount: required - The amount to be transferred - :type amount: float - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "txnId":"2966662589" - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('post', 'sub-account/transfer/subToSub', True, data=params) - - def make_subaccount_to_master_transfer(self, **params): - """Transfer to Master (For Sub-account) - - https://binance-docs.github.io/apidocs/spot/en/#transfer-to-master-for-sub-account - - :param asset: required - The asset being transferred, e.g., USDT - :type asset: str - :param amount: required - The amount to be transferred - :type amount: float - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "txnId":"2966662589" - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('post', 'sub-account/transfer/subToMaster', True, data=params) - - def get_subaccount_transfer_history(self, **params): - """Sub-account Transfer History (For Sub-account) - - https://binance-docs.github.io/apidocs/spot/en/#transfer-to-master-for-sub-account - - :param asset: required - The asset being transferred, e.g., USDT - :type asset: str - :param type: optional - 1: transfer in, 2: transfer out - :type type: int - :param startTime: optional - :type startTime: int - :param endTime: optional - :type endTime: int - :param limit: optional - Default 500 - :type limit: int - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - [ - { - "counterParty":"master", - "email":"master@test.com", - "type":1, // 1 for transfer in, 2 for transfer out - "asset":"BTC", - "qty":"1", - "status":"SUCCESS", - "tranId":11798835829, - "time":1544433325000 - }, - { - "counterParty":"subAccount", - "email":"sub2@test.com", - "type":2, - "asset":"ETH", - "qty":"2", - "status":"SUCCESS", - "tranId":11798829519, - "time":1544433326000 - } - ] - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'sub-account/transfer/subUserHistory', True, data=params) - - def make_subaccount_universal_transfer(self, **params): - """Universal Transfer (For Master Account) - - https://binance-docs.github.io/apidocs/spot/en/#universal-transfer-for-master-account - - :param fromEmail: optional - :type fromEmail: str - :param toEmail: optional - :type toEmail: str - :param fromAccountType: required - "SPOT","USDT_FUTURE","COIN_FUTURE" - :type fromAccountType: str - :param toAccountType: required - "SPOT","USDT_FUTURE","COIN_FUTURE" - :type toAccountType: str - :param asset: required - The asset being transferred, e.g., USDT - :type asset: str - :param amount: required - :type amount: float - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "tranId":11945860693 - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('post', 'sub-account/universalTransfer', True, data=params) - - def get_universal_transfer_history(self, **params): - """Universal Transfer (For Master Account) - - https://binance-docs.github.io/apidocs/spot/en/#query-universal-transfer-history - - :param fromEmail: optional - :type fromEmail: str - :param toEmail: optional - :type toEmail: str - :param startTime: optional - :type startTime: int - :param endTime: optional - :type endTime: int - :param page: optional - :type page: int - :param limit: optional - :type limit: int - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - [ - { - "tranId":11945860693, - "fromEmail":"master@test.com", - "toEmail":"subaccount1@test.com", - "asset":"BTC", - "amount":"0.1", - "fromAccountType":"SPOT", - "toAccountType":"COIN_FUTURE", - "status":"SUCCESS", - "createTimeStamp":1544433325000 - }, - { - "tranId":11945857955, - "fromEmail":"master@test.com", - "toEmail":"subaccount2@test.com", - "asset":"ETH", - "amount":"0.2", - "fromAccountType":"SPOT", - "toAccountType":"USDT_FUTURE", - "status":"SUCCESS", - "createTimeStamp":1544433326000 - } - ] - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'sub-account/universalTransfer', True, data=params) - - # Futures API - - def futures_ping(self): - """Test connectivity to the Rest API - - https://binance-docs.github.io/apidocs/futures/en/#test-connectivity - - """ - return self._request_futures_api('get', 'ping') - - def futures_time(self): - """Test connectivity to the Rest API and get the current server time. - - https://binance-docs.github.io/apidocs/futures/en/#check-server-time - - """ - return self._request_futures_api('get', 'time') - - def futures_exchange_info(self): - """Current exchange trading rules and symbol information - - https://binance-docs.github.io/apidocs/futures/en/#exchange-information-market_data - - """ - return self._request_futures_api('get', 'exchangeInfo') - - def futures_order_book(self, **params): - """Get the Order Book for the market - - https://binance-docs.github.io/apidocs/futures/en/#order-book-market_data - - """ - return self._request_futures_api('get', 'depth', data=params) - - def futures_recent_trades(self, **params): - """Get recent trades (up to last 500). - - https://binance-docs.github.io/apidocs/futures/en/#recent-trades-list-market_data - - """ - return self._request_futures_api('get', 'trades', data=params) - - def futures_historical_trades(self, **params): - """Get older market historical trades. - - https://binance-docs.github.io/apidocs/futures/en/#old-trades-lookup-market_data - - """ - return self._request_futures_api('get', 'historicalTrades', data=params) - - def futures_aggregate_trades(self, **params): - """Get compressed, aggregate trades. Trades that fill at the time, from the same order, with the same - price will have the quantity aggregated. - - https://binance-docs.github.io/apidocs/futures/en/#compressed-aggregate-trades-list-market_data - - """ - return self._request_futures_api('get', 'aggTrades', data=params) - - def futures_klines(self, **params): - """Kline/candlestick bars for a symbol. Klines are uniquely identified by their open time. - - https://binance-docs.github.io/apidocs/futures/en/#kline-candlestick-data-market_data - - """ - return self._request_futures_api('get', 'klines', data=params) - - def futures_continous_klines(self, **params): - """Kline/candlestick bars for a specific contract type. Klines are uniquely identified by their open time. - - https://binance-docs.github.io/apidocs/futures/en/#continuous-contract-kline-candlestick-data - - """ - return self._request_futures_api('get', 'continuousKlines', data=params) - - def futures_historical_klines(self, symbol, interval, start_str, end_str=None, limit=500): - """Get historical futures klines from Binance - - :param symbol: Name of symbol pair e.g BNBBTC - :type symbol: str - :param interval: Binance Kline interval - :type interval: str - :param start_str: Start date string in UTC format or timestamp in milliseconds - :type start_str: str|int - :param end_str: optional - end date string in UTC format or timestamp in milliseconds (default will fetch everything up to now) - :type end_str: str|int - :param limit: Default 500; max 1000. - :type limit: int - - :return: list of OHLCV values - - """ - return self._historical_klines(symbol, interval, start_str, end_str=end_str, limit=limit, klines_type=HistoricalKlinesType.FUTURES) - - def futures_historical_klines_generator(self, symbol, interval, start_str, end_str=None): - """Get historical futures klines generator from Binance - - :param symbol: Name of symbol pair e.g BNBBTC - :type symbol: str - :param interval: Binance Kline interval - :type interval: str - :param start_str: Start date string in UTC format or timestamp in milliseconds - :type start_str: str|int - :param end_str: optional - end date string in UTC format or timestamp in milliseconds (default will fetch everything up to now) - :type end_str: str|int - - :return: generator of OHLCV values - - """ - - return self._historical_klines_generator(symbol, interval, start_str, end_str=end_str, klines_type=HistoricalKlinesType.FUTURES) - - def futures_mark_price(self, **params): - """Get Mark Price and Funding Rate - - https://binance-docs.github.io/apidocs/futures/en/#mark-price-market_data - - """ - return self._request_futures_api('get', 'premiumIndex', data=params) - - def futures_funding_rate(self, **params): - """Get funding rate history - - https://binance-docs.github.io/apidocs/futures/en/#get-funding-rate-history-market_data - - """ - return self._request_futures_api('get', 'fundingRate', data=params) - - def futures_top_longshort_account_ratio(self, **params): - """Get present long to short ratio for top accounts of a specific symbol. - - https://binance-docs.github.io/apidocs/futures/en/#top-trader-long-short-ratio-accounts-market_data - """ - return self._request_futures_data_api('get', 'topLongShortAccountRatio', data=params) - - def futures_top_longshort_position_ratio(self, **params): - """Get present long to short ratio for top positions of a specific symbol. - - https://binance-docs.github.io/apidocs/futures/en/#top-trader-long-short-ratio-positions - """ - return self._request_futures_data_api('get', 'topLongShortPositionRatio', data=params) - - def futures_global_longshort_ratio(self, **params): - """Get present global long to short ratio of a specific symbol. - - https://binance-docs.github.io/apidocs/futures/en/#long-short-ratio - """ - return self._request_futures_data_api('get', 'globalLongShortAccountRatio', data=params) - - def futures_ticker(self, **params): - """24 hour rolling window price change statistics. - - https://binance-docs.github.io/apidocs/futures/en/#24hr-ticker-price-change-statistics-market_data - - """ - return self._request_futures_api('get', 'ticker/24hr', data=params) - - def futures_symbol_ticker(self, **params): - """Latest price for a symbol or symbols. - - https://binance-docs.github.io/apidocs/futures/en/#symbol-price-ticker-market_data - - """ - return self._request_futures_api('get', 'ticker/price', data=params) - - def futures_orderbook_ticker(self, **params): - """Best price/qty on the order book for a symbol or symbols. - - https://binance-docs.github.io/apidocs/futures/en/#symbol-order-book-ticker-market_data - - """ - return self._request_futures_api('get', 'ticker/bookTicker', data=params) - - def futures_liquidation_orders(self, **params): - """Get all liquidation orders - - https://binance-docs.github.io/apidocs/futures/en/#get-all-liquidation-orders-market_data - - """ - return self._request_futures_api('get', 'forceOrders', signed=True, data=params) - - def futures_adl_quantile_estimate(self, **params): - """Get Position ADL Quantile Estimate - - https://binance-docs.github.io/apidocs/futures/en/#position-adl-quantile-estimation-user_data - - """ - return self._request_futures_api('get', 'adlQuantile', signed=True, data=params) - - def futures_open_interest(self, **params): - """Get present open interest of a specific symbol. - - https://binance-docs.github.io/apidocs/futures/en/#open-interest - - """ - return self._request_futures_api('get', 'openInterest', data=params) - - def futures_open_interest_hist(self, **params): - """Get open interest statistics of a specific symbol. - - https://binance-docs.github.io/apidocs/futures/en/#open-interest-statistics - - """ - return self._request_futures_data_api('get', 'openInterestHist', data=params) - - def futures_leverage_bracket(self, **params): - """Notional and Leverage Brackets - - https://binance-docs.github.io/apidocs/futures/en/#notional-and-leverage-brackets-market_data - - """ - return self._request_futures_api('get', 'leverageBracket', True, data=params) - - def futures_account_transfer(self, **params): - """Execute transfer between spot account and futures account. - - https://binance-docs.github.io/apidocs/futures/en/#new-future-account-transfer - - """ - return self._request_margin_api('post', 'futures/transfer', True, data=params) - - def transfer_history(self, **params): - """Get future account transaction history list - - https://binance-docs.github.io/apidocs/futures/en/#get-future-account-transaction-history-list-user_data - - """ - return self._request_margin_api('get', 'futures/transfer', True, data=params) - - def futures_create_order(self, **params): - """Send in a new order. - - https://binance-docs.github.io/apidocs/futures/en/#new-order-trade - - """ - return self._request_futures_api('post', 'order', True, data=params) - - def futures_place_batch_order(self, **params): - """Send in new orders. - - https://binance-docs.github.io/apidocs/futures/en/#place-multiple-orders-trade - - To avoid modifying the existing signature generation and parameter order logic, - the url encoding is done on the special query param, batchOrders, in the early stage. - - """ - query_string = urlencode(params) - query_string = query_string.replace('%27', '%22') - params['batchOrders'] = query_string[12:] - return self._request_futures_api('post', 'batchOrders', True, data=params) - - def futures_get_order(self, **params): - """Check an order's status. - - https://binance-docs.github.io/apidocs/futures/en/#query-order-user_data - - """ - return self._request_futures_api('get', 'order', True, data=params) - - def futures_get_open_orders(self, **params): - """Get all open orders on a symbol. - - https://binance-docs.github.io/apidocs/futures/en/#current-open-orders-user_data - - """ - return self._request_futures_api('get', 'openOrders', True, data=params) - - def futures_get_all_orders(self, **params): - """Get all futures account orders; active, canceled, or filled. - - https://binance-docs.github.io/apidocs/futures/en/#all-orders-user_data - - """ - return self._request_futures_api('get', 'allOrders', True, data=params) - - def futures_cancel_order(self, **params): - """Cancel an active futures order. - - https://binance-docs.github.io/apidocs/futures/en/#cancel-order-trade - - """ - return self._request_futures_api('delete', 'order', True, data=params) - - def futures_cancel_all_open_orders(self, **params): - """Cancel all open futures orders - - https://binance-docs.github.io/apidocs/futures/en/#cancel-all-open-orders-trade - - """ - return self._request_futures_api('delete', 'allOpenOrders', True, data=params) - - def futures_cancel_orders(self, **params): - """Cancel multiple futures orders - - https://binance-docs.github.io/apidocs/futures/en/#cancel-multiple-orders-trade - - """ - return self._request_futures_api('delete', 'batchOrders', True, data=params) - - def futures_account_balance(self, **params): - """Get futures account balance - - https://binance-docs.github.io/apidocs/futures/en/#future-account-balance-user_data - - """ - return self._request_futures_api('get', 'balance', True, data=params) - - def futures_account(self, **params): - """Get current account information. - - https://binance-docs.github.io/apidocs/futures/en/#account-information-user_data - - """ - return self._request_futures_api('get', 'account', True, data=params) - - def futures_change_leverage(self, **params): - """Change user's initial leverage of specific symbol market - - https://binance-docs.github.io/apidocs/futures/en/#change-initial-leverage-trade - - """ - return self._request_futures_api('post', 'leverage', True, data=params) - - def futures_change_margin_type(self, **params): - """Change the margin type for a symbol - - https://binance-docs.github.io/apidocs/futures/en/#change-margin-type-trade - - """ - return self._request_futures_api('post', 'marginType', True, data=params) - - def futures_change_position_margin(self, **params): - """Change the position margin for a symbol - - https://binance-docs.github.io/apidocs/futures/en/#modify-isolated-position-margin-trade - - """ - return self._request_futures_api('post', 'positionMargin', True, data=params) - - def futures_position_margin_history(self, **params): - """Get position margin change history - - https://binance-docs.github.io/apidocs/futures/en/#get-postion-margin-change-history-trade - - """ - return self._request_futures_api('get', 'positionMargin/history', True, data=params) - - def futures_position_information(self, **params): - """Get position information - - https://binance-docs.github.io/apidocs/futures/en/#position-information-user_data - - """ - return self._request_futures_api('get', 'positionRisk', True, data=params) - - def futures_account_trades(self, **params): - """Get trades for the authenticated account and symbol. - - https://binance-docs.github.io/apidocs/futures/en/#account-trade-list-user_data - - """ - return self._request_futures_api('get', 'userTrades', True, data=params) - - def futures_income_history(self, **params): - """Get income history for authenticated account - - https://binance-docs.github.io/apidocs/futures/en/#get-income-history-user_data - - """ - return self._request_futures_api('get', 'income', True, data=params) - - def futures_change_position_mode(self, **params): - """Change position mode for authenticated account - - https://binance-docs.github.io/apidocs/futures/en/#change-position-mode-trade - - """ - return self._request_futures_api('post', 'positionSide/dual', True, data=params) - - def futures_get_position_mode(self, **params): - """Get position mode for authenticated account - - https://binance-docs.github.io/apidocs/futures/en/#get-current-position-mode-user_data - - """ - return self._request_futures_api('get', 'positionSide/dual', True, data=params) - - def futures_change_multi_assets_mode(self, multiAssetsMargin: bool): - """Change user's Multi-Assets mode (Multi-Assets Mode or Single-Asset Mode) on Every symbol - - https://binance-docs.github.io/apidocs/futures/en/#change-multi-assets-mode-trade - - """ - params = { - 'true' if multiAssetsMargin else 'false' - } - return self._request_futures_api('post', 'multiAssetsMargin', True, data=params) - - def futures_get_multi_assets_mode(self): - """Get user's Multi-Assets mode (Multi-Assets Mode or Single-Asset Mode) on Every symbol - - https://binance-docs.github.io/apidocs/futures/en/#get-current-multi-assets-mode-user_data - - """ - return self._request_futures_api('get', 'multiAssetsMargin', True) - - def futures_stream_get_listen_key(self): - res = self._request_futures_api('post', 'listenKey', signed=False, data={}) - return res['listenKey'] - - def futures_stream_keepalive(self, listenKey): - params = { - 'listenKey': listenKey - } - return self._request_futures_api('put', 'listenKey', signed=False, data=params) - - def futures_stream_close(self, listenKey): - params = { - 'listenKey': listenKey - } - return self._request_futures_api('delete', 'listenKey', signed=False, data=params) - - # COIN Futures API - def futures_coin_ping(self): - """Test connectivity to the Rest API - - https://binance-docs.github.io/apidocs/delivery/en/#test-connectivity - - """ - return self._request_futures_coin_api("get", "ping") - - def futures_coin_time(self): - """Test connectivity to the Rest API and get the current server time. - - https://binance-docs.github.io/apidocs/delivery/en/#check-server-time - - """ - return self._request_futures_coin_api("get", "time") - - def futures_coin_exchange_info(self): - """Current exchange trading rules and symbol information - - https://binance-docs.github.io/apidocs/delivery/en/#exchange-information - - """ - return self._request_futures_coin_api("get", "exchangeInfo") - - def futures_coin_order_book(self, **params): - """Get the Order Book for the market - - https://binance-docs.github.io/apidocs/delivery/en/#order-book - - """ - return self._request_futures_coin_api("get", "depth", data=params) - - def futures_coin_recent_trades(self, **params): - """Get recent trades (up to last 500). - - https://binance-docs.github.io/apidocs/delivery/en/#recent-trades-list - - """ - return self._request_futures_coin_api("get", "trades", data=params) - - def futures_coin_historical_trades(self, **params): - """Get older market historical trades. - - https://binance-docs.github.io/apidocs/delivery/en/#old-trades-lookup-market_data - - """ - return self._request_futures_coin_api("get", "historicalTrades", data=params) - - def futures_coin_aggregate_trades(self, **params): - """Get compressed, aggregate trades. Trades that fill at the time, from the same order, with the same - price will have the quantity aggregated. - - https://binance-docs.github.io/apidocs/delivery/en/#compressed-aggregate-trades-list - - """ - return self._request_futures_coin_api("get", "aggTrades", data=params) - - def futures_coin_klines(self, **params): - """Kline/candlestick bars for a symbol. Klines are uniquely identified by their open time. - - https://binance-docs.github.io/apidocs/delivery/en/#kline-candlestick-data - - """ - return self._request_futures_coin_api("get", "klines", data=params) - - def futures_coin_continous_klines(self, **params): - """Kline/candlestick bars for a specific contract type. Klines are uniquely identified by their open time. - - https://binance-docs.github.io/apidocs/delivery/en/#continuous-contract-kline-candlestick-data - - """ - return self._request_futures_coin_api("get", "continuousKlines", data=params) - - def futures_coin_index_price_klines(self, **params): - """Kline/candlestick bars for the index price of a pair.. - - https://binance-docs.github.io/apidocs/delivery/en/#index-price-kline-candlestick-data - - """ - return self._request_futures_coin_api("get", "indexPriceKlines", data=params) - - def futures_coin_mark_price_klines(self, **params): - """Kline/candlestick bars for the index price of a pair.. - - https://binance-docs.github.io/apidocs/delivery/en/#mark-price-kline-candlestick-data - - """ - return self._request_futures_coin_api("get", "markPriceKlines", data=params) - - def futures_coin_mark_price(self, **params): - """Get Mark Price and Funding Rate - - https://binance-docs.github.io/apidocs/delivery/en/#index-price-and-mark-price - - """ - return self._request_futures_coin_api("get", "premiumIndex", data=params) - - def futures_coin_funding_rate(self, **params): - """Get funding rate history - - https://binance-docs.github.io/apidocs/delivery/en/#get-funding-rate-history-of-perpetual-futures - - """ - return self._request_futures_coin_api("get", "fundingRate", data=params) - - def futures_coin_ticker(self, **params): - """24 hour rolling window price change statistics. - - https://binance-docs.github.io/apidocs/delivery/en/#24hr-ticker-price-change-statistics - - """ - return self._request_futures_coin_api("get", "ticker/24hr", data=params) - - def futures_coin_symbol_ticker(self, **params): - """Latest price for a symbol or symbols. - - https://binance-docs.github.io/apidocs/delivery/en/#symbol-price-ticker - - """ - return self._request_futures_coin_api("get", "ticker/price", data=params) - - def futures_coin_orderbook_ticker(self, **params): - """Best price/qty on the order book for a symbol or symbols. - - https://binance-docs.github.io/apidocs/delivery/en/#symbol-order-book-ticker - - """ - return self._request_futures_coin_api("get", "ticker/bookTicker", data=params) - - def futures_coin_liquidation_orders(self, **params): - """Get all liquidation orders - - https://binance-docs.github.io/apidocs/delivery/en/#user-39-s-force-orders-user_data - - """ - return self._request_futures_coin_api("get", "forceOrders", signed=True, data=params) - - def futures_coin_open_interest(self, **params): - """Get present open interest of a specific symbol. - - https://binance-docs.github.io/apidocs/delivery/en/#open-interest - - """ - return self._request_futures_coin_api("get", "openInterest", data=params) - - def futures_coin_open_interest_hist(self, **params): - """Get open interest statistics of a specific symbol. - - https://binance-docs.github.io/apidocs/delivery/en/#open-interest-statistics-market-data - - """ - return self._request_futures_coin_data_api("get", "openInterestHist", data=params) - - def futures_coin_leverage_bracket(self, **params): - """Notional and Leverage Brackets - - https://binance-docs.github.io/apidocs/delivery/en/#notional-bracket-for-pair-user_data - - """ - return self._request_futures_coin_api( - "get", "leverageBracket", version=2, signed=True, data=params - ) - - def new_transfer_history(self, **params): - """Get future account transaction history list - - https://binance-docs.github.io/apidocs/delivery/en/#new-future-account-transfer - - """ - return self._request_margin_api("get", "asset/transfer", True, data=params) - # return self._request_margin_api("get", "futures/transfer", True, data=params) - - def universal_transfer(self, **params): - """Unviversal transfer api accross different binance account types - - https://binance-docs.github.io/apidocs/spot/en/#user-universal-transfer - """ - return self._request_margin_api( - "post", "asset/transfer", signed=True, data=params - ) - - def futures_coin_create_order(self, **params): - """Send in a new order. - - https://binance-docs.github.io/apidocs/delivery/en/#new-order-trade - - """ - return self._request_futures_coin_api("post", "order", True, data=params) - - def futures_coin_place_batch_order(self, **params): - """Send in new orders. - - https://binance-docs.github.io/apidocs/delivery/en/#place-multiple-orders-trade - - To avoid modifying the existing signature generation and parameter order logic, - the url encoding is done on the special query param, batchOrders, in the early stage. - - """ - query_string = urlencode(params) - query_string = query_string.replace('%27', '%22') - params['batchOrders'] = query_string[12:] - - return self._request_futures_coin_api('post', 'batchOrders', True, data=params) - - def futures_coin_get_order(self, **params): - """Check an order's status. - - https://binance-docs.github.io/apidocs/delivery/en/#query-order-user_data - - """ - return self._request_futures_coin_api("get", "order", True, data=params) - - def futures_coin_get_open_orders(self, **params): - """Get all open orders on a symbol. - - https://binance-docs.github.io/apidocs/delivery/en/#current-all-open-orders-user_data - - """ - return self._request_futures_coin_api("get", "openOrders", True, data=params) - - def futures_coin_get_all_orders(self, **params): - """Get all futures account orders; active, canceled, or filled. - - https://binance-docs.github.io/apidocs/delivery/en/#all-orders-user_data - - """ - return self._request_futures_coin_api( - "get", "allOrders", signed=True, data=params - ) - - def futures_coin_cancel_order(self, **params): - """Cancel an active futures order. - - https://binance-docs.github.io/apidocs/delivery/en/#cancel-order-trade - - """ - return self._request_futures_coin_api( - "delete", "order", signed=True, data=params - ) - - def futures_coin_cancel_all_open_orders(self, **params): - """Cancel all open futures orders - - https://binance-docs.github.io/apidocs/delivery/en/#cancel-all-open-orders-trade - - """ - return self._request_futures_coin_api( - "delete", "allOpenOrders", signed=True, data=params - ) - - def futures_coin_cancel_orders(self, **params): - """Cancel multiple futures orders - - https://binance-docs.github.io/apidocs/delivery/en/#cancel-multiple-orders-trade - - """ - return self._request_futures_coin_api( - "delete", "batchOrders", True, data=params - ) - - def futures_coin_account_balance(self, **params): - """Get futures account balance - - https://binance-docs.github.io/apidocs/delivery/en/#futures-account-balance-user_data - - """ - return self._request_futures_coin_api( - "get", "balance", signed=True, data=params - ) - - def futures_coin_account(self, **params): - """Get current account information. - - https://binance-docs.github.io/apidocs/delivery/en/#account-information-user_data - - """ - return self._request_futures_coin_api( - "get", "account", signed=True, data=params - ) - - def futures_coin_change_leverage(self, **params): - """Change user's initial leverage of specific symbol market - - https://binance-docs.github.io/apidocs/delivery/en/#change-initial-leverage-trade - - """ - return self._request_futures_coin_api( - "post", "leverage", signed=True, data=params - ) - - def futures_coin_change_margin_type(self, **params): - """Change the margin type for a symbol - - https://binance-docs.github.io/apidocs/delivery/en/#change-margin-type-trade - - """ - return self._request_futures_coin_api( - "post", "marginType", signed=True, data=params - ) - - def futures_coin_change_position_margin(self, **params): - """Change the position margin for a symbol - - https://binance-docs.github.io/apidocs/delivery/en/#modify-isolated-position-margin-trade - - """ - return self._request_futures_coin_api( - "post", "positionMargin", True, data=params - ) - - def futures_coin_position_margin_history(self, **params): - """Get position margin change history - - https://binance-docs.github.io/apidocs/delivery/en/#get-position-margin-change-history-trade - - """ - return self._request_futures_coin_api( - "get", "positionMargin/history", True, data=params - ) - - def futures_coin_position_information(self, **params): - """Get position information - - https://binance-docs.github.io/apidocs/delivery/en/#position-information-user_data - - """ - return self._request_futures_coin_api("get", "positionRisk", True, data=params) - - def futures_coin_account_trades(self, **params): - """Get trades for the authenticated account and symbol. - - https://binance-docs.github.io/apidocs/delivery/en/#account-trade-list-user_data - - """ - return self._request_futures_coin_api("get", "userTrades", True, data=params) - - def futures_coin_income_history(self, **params): - """Get income history for authenticated account - - https://binance-docs.github.io/apidocs/delivery/en/#get-income-history-user_data - - """ - return self._request_futures_coin_api("get", "income", True, data=params) - - def futures_coin_change_position_mode(self, **params): - """Change user's position mode (Hedge Mode or One-way Mode ) on EVERY symbol - - https://binance-docs.github.io/apidocs/delivery/en/#change-position-mode-trade - """ - return self._request_futures_coin_api("post", "positionSide/dual", True, data=params) - - def futures_coin_get_position_mode(self, **params): - """Get user's position mode (Hedge Mode or One-way Mode ) on EVERY symbol - - https://binance-docs.github.io/apidocs/delivery/en/#get-current-position-mode-user_data - - """ - return self._request_futures_coin_api("get", "positionSide/dual", True, data=params) - - def futures_coin_stream_get_listen_key(self): - res = self._request_futures_coin_api('post', 'listenKey', signed=False, data={}) - return res['listenKey'] - - def futures_coin_stream_keepalive(self, listenKey): - params = { - 'listenKey': listenKey - } - return self._request_futures_coin_api('put', 'listenKey', signed=False, data=params) - - def futures_coin_stream_close(self, listenKey): - params = { - 'listenKey': listenKey - } - return self._request_futures_coin_api('delete', 'listenKey', signed=False, data=params) - - def get_all_coins_info(self, **params): - """Get information of coins (available for deposit and withdraw) for user. - - https://binance-docs.github.io/apidocs/spot/en/#all-coins-39-information-user_data - - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "coin": "BTC", - "depositAllEnable": true, - "withdrawAllEnable": true, - "name": "Bitcoin", - "free": "0", - "locked": "0", - "freeze": "0", - "withdrawing": "0", - "ipoing": "0", - "ipoable": "0", - "storage": "0", - "isLegalMoney": false, - "trading": true, - "networkList": [ - { - "network": "BNB", - "coin": "BTC", - "withdrawIntegerMultiple": "0.00000001", - "isDefault": false, - "depositEnable": true, - "withdrawEnable": true, - "depositDesc": "", - "withdrawDesc": "", - "specialTips": "Both a MEMO and an Address are required to successfully deposit your BEP2-BTCB tokens to Binance.", - "name": "BEP2", - "resetAddressStatus": false, - "addressRegex": "^(bnb1)[0-9a-z]{38}$", - "memoRegex": "^[0-9A-Za-z-_]{1,120}$", - "withdrawFee": "0.0000026", - "withdrawMin": "0.0000052", - "withdrawMax": "0", - "minConfirm": 1, - "unLockConfirm": 0 - }, - { - "network": "BTC", - "coin": "BTC", - "withdrawIntegerMultiple": "0.00000001", - "isDefault": true, - "depositEnable": true, - "withdrawEnable": true, - "depositDesc": "", - "withdrawDesc": "", - "specialTips": "", - "name": "BTC", - "resetAddressStatus": false, - "addressRegex": "^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$|^(bc1)[0-9A-Za-z]{39,59}$", - "memoRegex": "", - "withdrawFee": "0.0005", - "withdrawMin": "0.001", - "withdrawMax": "0", - "minConfirm": 1, - "unLockConfirm": 2 - } - ] - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'capital/config/getall', True, data=params) - - def get_account_snapshot(self, **params): - """Get daily account snapshot of specific type. - - https://binance-docs.github.io/apidocs/spot/en/#daily-account-snapshot-user_data - - :param type: required. Valid values are SPOT/MARGIN/FUTURES. - :type type: string - :param startTime: optional - :type startTime: int - :param endTime: optional - :type endTime: int - :param limit: optional - :type limit: int - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - .. code-block:: python - - { - "code":200, // 200 for success; others are error codes - "msg":"", // error message - "snapshotVos":[ - { - "data":{ - "balances":[ - { - "asset":"BTC", - "free":"0.09905021", - "locked":"0.00000000" - }, - { - "asset":"USDT", - "free":"1.89109409", - "locked":"0.00000000" - } - ], - "totalAssetOfBtc":"0.09942700" - }, - "type":"spot", - "updateTime":1576281599000 - } - ] - } - - OR - - .. code-block:: python - - { - "code":200, // 200 for success; others are error codes - "msg":"", // error message - "snapshotVos":[ - { - "data":{ - "marginLevel":"2748.02909813", - "totalAssetOfBtc":"0.00274803", - "totalLiabilityOfBtc":"0.00000100", - "totalNetAssetOfBtc":"0.00274750", - "userAssets":[ - { - "asset":"XRP", - "borrowed":"0.00000000", - "free":"1.00000000", - "interest":"0.00000000", - "locked":"0.00000000", - "netAsset":"1.00000000" - } - ] - }, - "type":"margin", - "updateTime":1576281599000 - } - ] - } - - OR - - .. code-block:: python - - { - "code":200, // 200 for success; others are error codes - "msg":"", // error message - "snapshotVos":[ - { - "data":{ - "assets":[ - { - "asset":"USDT", - "marginBalance":"118.99782335", - "walletBalance":"120.23811389" - } - ], - "position":[ - { - "entryPrice":"7130.41000000", - "markPrice":"7257.66239673", - "positionAmt":"0.01000000", - "symbol":"BTCUSDT", - "unRealizedProfit":"1.24029054" - } - ] - }, - "type":"futures", - "updateTime":1576281599000 - } - ] - } - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('get', 'accountSnapshot', True, data=params) - - def disable_fast_withdraw_switch(self, **params): - """Disable Fast Withdraw Switch - - https://binance-docs.github.io/apidocs/spot/en/#disable-fast-withdraw-switch-user_data - - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('post', 'disableFastWithdrawSwitch', True, data=params) - - def enable_fast_withdraw_switch(self, **params): - """Enable Fast Withdraw Switch - - https://binance-docs.github.io/apidocs/spot/en/#enable-fast-withdraw-switch-user_data - - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - :raises: BinanceRequestException, BinanceAPIException - - """ - return self._request_margin_api('post', 'enableFastWithdrawSwitch', True, data=params) - - """ - ==================================================================================================================== - Options API - ==================================================================================================================== - """ - # Quoting interface endpoints - - def options_ping(self): - """Test connectivity - - https://binance-docs.github.io/apidocs/voptions/en/#test-connectivity - - """ - return self._request_options_api('get', 'ping') - - def options_time(self): - """Get server time - - https://binance-docs.github.io/apidocs/voptions/en/#get-server-time - - """ - return self._request_options_api('get', 'time') - - def options_info(self): - """Get current trading pair info - - https://binance-docs.github.io/apidocs/voptions/en/#get-current-trading-pair-info - - """ - return self._request_options_api('get', 'optionInfo') - - def options_exchange_info(self): - """Get current limit info and trading pair info - - https://binance-docs.github.io/apidocs/voptions/en/#get-current-limit-info-and-trading-pair-info - - """ - return self._request_options_api('get', 'exchangeInfo') - - def options_index_price(self, **params): - """Get the spot index price - - https://binance-docs.github.io/apidocs/voptions/en/#get-the-spot-index-price - - :param underlying: required - Spot pair(Option contract underlying asset)- BTCUSDT - :type underlying: str - - """ - return self._request_options_api('get', 'index', data=params) - - def options_price(self, **params): - """Get the latest price - - https://binance-docs.github.io/apidocs/voptions/en/#get-the-latest-price - - :param symbol: optional - Option trading pair - BTC-200730-9000-C - :type symbol: str - - """ - return self._request_options_api('get', 'ticker', data=params) - - def options_mark_price(self, **params): - """Get the latest mark price - - https://binance-docs.github.io/apidocs/voptions/en/#get-the-latest-mark-price - - :param symbol: optional - Option trading pair - BTC-200730-9000-C - :type symbol: str - - """ - return self._request_options_api('get', 'mark', data=params) - - def options_order_book(self, **params): - """Depth information - - https://binance-docs.github.io/apidocs/voptions/en/#depth-information - - :param symbol: required - Option trading pair - BTC-200730-9000-C - :type symbol: str - :param limit: optional - Default:100 Max:1000.Optional value:[10, 20, 50, 100, 500, 1000] - 100 - :type limit: int - - """ - return self._request_options_api('get', 'depth', data=params) - - def options_klines(self, **params): - """Candle data - - https://binance-docs.github.io/apidocs/voptions/en/#candle-data - - :param symbol: required - Option trading pair - BTC-200730-9000-C - :type symbol: str - :param interval: required - Time interval - 5m - :type interval: str - :param startTime: optional - Start Time - 1592317127349 - :type startTime: int - :param endTime: optional - End Time - 1592317127349 - :type endTime: int - :param limit: optional - Number of records Default:500 Max:1500 - 500 - :type limit: int - - """ - return self._request_options_api('get', 'klines', data=params) - - def options_recent_trades(self, **params): - """Recently completed Option trades - - https://binance-docs.github.io/apidocs/voptions/en/#recently-completed-option-trades - - :param symbol: required - Option trading pair - BTC-200730-9000-C - :type symbol: str - :param limit: optional - Number of records Default:100 Max:500 - 100 - :type limit: int - - """ - return self._request_options_api('get', 'trades', data=params) - - def options_historical_trades(self, **params): - """Query trade history - - https://binance-docs.github.io/apidocs/voptions/en/#query-trade-history - - :param symbol: required - Option trading pair - BTC-200730-9000-C - :type symbol: str - :param fromId: optional - The deal ID from which to return. The latest deal record is returned by default - 1592317127349 - :type fromId: int - :param limit: optional - Number of records Default:100 Max:500 - 100 - :type limit: int - - """ - return self._request_options_api('get', 'historicalTrades', data=params) - - # Account and trading interface endpoints - - def options_account_info(self, **params): - """Account asset info (USER_DATA) - - https://binance-docs.github.io/apidocs/voptions/en/#account-asset-info-user_data - - :param recvWindow: optional - :type recvWindow: int - - """ - return self._request_options_api('get', 'account', signed=True, data=params) - - def options_funds_transfer(self, **params): - """Funds transfer (USER_DATA) - - https://binance-docs.github.io/apidocs/voptions/en/#funds-transfer-user_data - - :param currency: required - Asset type - USDT - :type currency: str - :param type: required - IN: Transfer from spot account to option account OUT: Transfer from option account to spot account - IN - :type type: str (ENUM) - :param amount: required - Amount - 10000 - :type amount: float - :param recvWindow: optional - :type recvWindow: int - - """ - return self._request_options_api('post', 'transfer', signed=True, data=params) - - def options_positions(self, **params): - """Option holdings info (USER_DATA) - - https://binance-docs.github.io/apidocs/voptions/en/#option-holdings-info-user_data - - :param symbol: optional - Option trading pair - BTC-200730-9000-C - :type symbol: str - :param recvWindow: optional - :type recvWindow: int - - """ - return self._request_options_api('get', 'position', signed=True, data=params) - - def options_bill(self, **params): - """Account funding flow (USER_DATA) - - https://binance-docs.github.io/apidocs/voptions/en/#account-funding-flow-user_data - - :param currency: required - Asset type - USDT - :type currency: str - :param recordId: optional - Return the recordId and subsequent data, the latest data is returned by default - 100000 - :type recordId: int - :param startTime: optional - Start Time - 1593511200000 - :type startTime: int - :param endTime: optional - End Time - 1593511200000 - :type endTime: int - :param limit: optional - Number of result sets returned Default:100 Max:1000 - 100 - :type limit: int - :param recvWindow: optional - :type recvWindow: int - - """ - return self._request_options_api('post', 'bill', signed=True, data=params) - - def options_place_order(self, **params): - """Option order (TRADE) - - https://binance-docs.github.io/apidocs/voptions/en/#option-order-trade - - :param symbol: required - Option trading pair - BTC-200730-9000-C - :type symbol: str - :param side: required - Buy/sell direction: SELL, BUY - BUY - :type side: str (ENUM) - :param type: required - Order Type: LIMIT, MARKET - LIMIT - :type type: str (ENUM) - :param quantity: required - Order Quantity - 3 - :type quantity: float - :param price: optional - Order Price - 1000 - :type price: float - :param timeInForce: optional - Time in force method(Default GTC) - GTC - :type timeInForce: str (ENUM) - :param reduceOnly: optional - Reduce Only (Default false) - false - :type reduceOnly: bool - :param postOnly: optional - Post Only (Default false) - false - :type postOnly: bool - :param newOrderRespType: optional - "ACK", "RESULT", Default "ACK" - ACK - :type newOrderRespType: str (ENUM) - :param clientOrderId: optional - User-defined order ID cannot be repeated in pending orders - 10000 - :type clientOrderId: str - :param recvWindow: optional - :type recvWindow: int - - """ - return self._request_options_api('post', 'order', signed=True, data=params) - - def options_place_batch_order(self, **params): - """Place Multiple Option orders (TRADE) - - https://binance-docs.github.io/apidocs/voptions/en/#place-multiple-option-orders-trade - - :param orders: required - order list. Max 5 orders - [{"symbol":"BTC-210115-35000-C","price":"100","quantity":"0.0001","side":"BUY","type":"LIMIT"}] - :type orders: list - :param recvWindow: optional - :type recvWindow: int - - """ - return self._request_options_api('post', 'batchOrders', signed=True, data=params) - - def options_cancel_order(self, **params): - """Cancel Option order (TRADE) - - https://binance-docs.github.io/apidocs/voptions/en/#cancel-option-order-trade - - :param symbol: required - Option trading pair - BTC-200730-9000-C - :type symbol: str - :param orderId: optional - Order ID - 4611875134427365377 - :type orderId: str - :param clientOrderId: optional - User-defined order ID - 10000 - :type clientOrderId: str - :param recvWindow: optional - :type recvWindow: int - - """ - return self._request_options_api('delete', 'order', signed=True, data=params) - - def options_cancel_batch_order(self, **params): - """Cancel Multiple Option orders (TRADE) - - https://binance-docs.github.io/apidocs/voptions/en/#cancel-multiple-option-orders-trade - - :param symbol: required - Option trading pair - BTC-200730-9000-C - :type symbol: str - :param orderIds: optional - Order ID - [4611875134427365377,4611875134427365378] - :type orderId: list - :param clientOrderIds: optional - User-defined order ID - ["my_id_1","my_id_2"] - :type clientOrderIds: list - :param recvWindow: optional - :type recvWindow: int - - """ - return self._request_options_api('delete', 'batchOrders', signed=True, data=params) - - def options_cancel_all_orders(self, **params): - """Cancel all Option orders (TRADE) - - https://binance-docs.github.io/apidocs/voptions/en/#cancel-all-option-orders-trade - - :param symbol: required - Option trading pair - BTC-200730-9000-C - :type symbol: str - :param recvWindow: optional - :type recvWindow: int - - """ - return self._request_options_api('delete', 'allOpenOrders', signed=True, data=params) - - def options_query_order(self, **params): - """Query Option order (TRADE) - - https://binance-docs.github.io/apidocs/voptions/en/#query-option-order-trade - - :param symbol: required - Option trading pair - BTC-200730-9000-C - :type symbol: str - :param orderId: optional - Order ID - 4611875134427365377 - :type orderId: str - :param clientOrderId: optional - User-defined order ID - 10000 - :type clientOrderId: str - :param recvWindow: optional - :type recvWindow: int - - """ - return self._request_options_api('get', 'order', signed=True, data=params) - - def options_query_pending_orders(self, **params): - """Query current pending Option orders (TRADE) - - https://binance-docs.github.io/apidocs/voptions/en/#query-current-pending-option-orders-trade - - :param symbol: required - Option trading pair - BTC-200730-9000-C - :type symbol: str - :param orderId: optional - Returns the orderId and subsequent orders, the most recent order is returned by default - 100000 - :type orderId: str - :param startTime: optional - Start Time - 1593511200000 - :type startTime: int - :param endTime: optional - End Time - 1593511200000 - :type endTime: int - :param limit: optional - Number of result sets returned Default:100 Max:1000 - 100 - :type limit: int - :param recvWindow: optional - :type recvWindow: int - - """ - return self._request_options_api('get', 'openOrders', signed=True, data=params) - - def options_query_order_history(self, **params): - """Query Option order history (TRADE) - - https://binance-docs.github.io/apidocs/voptions/en/#query-option-order-history-trade - - :param symbol: required - Option trading pair - BTC-200730-9000-C - :type symbol: str - :param orderId: optional - Returns the orderId and subsequent orders, the most recent order is returned by default - 100000 - :type orderId: str - :param startTime: optional - Start Time - 1593511200000 - :type startTime: int - :param endTime: optional - End Time - 1593511200000 - :type endTime: int - :param limit: optional - Number of result sets returned Default:100 Max:1000 - 100 - :type limit: int - :param recvWindow: optional - :type recvWindow: int - - """ - return self._request_options_api('get', 'historyOrders', signed=True, data=params) - - def options_user_trades(self, **params): - """Option Trade List (USER_DATA) - - https://binance-docs.github.io/apidocs/voptions/en/#option-trade-list-user_data - - :param symbol: required - Option trading pair - BTC-200730-9000-C - :type symbol: str - :param fromId: optional - Trade id to fetch from. Default gets most recent trades. - 4611875134427365376 - :type fromId: int - :param startTime: optional - Start Time - 1593511200000 - :type startTime: int - :param endTime: optional - End Time - 1593511200000 - :type endTime: int - :param limit: optional - Number of result sets returned Default:100 Max:1000 - 100 - :type limit: int - :param recvWindow: optional - :type recvWindow: int - - """ - return self._request_options_api('get', 'userTrades', signed=True, data=params) - - # Fiat Endpoints - - def get_fiat_deposit_withdraw_history(self, **params): - """Get Fiat Deposit/Withdraw History - - https://binance-docs.github.io/apidocs/spot/en/#get-fiat-deposit-withdraw-history-user_data - - :param transactionType: required - 0-deposit,1-withdraw - :type transactionType: str - :param beginTime: optional - :type beginTime: int - :param endTime: optional - :type endTime: int - :param page: optional - default 1 - :type page: int - :param rows: optional - default 100, max 500 - :type rows: int - :param recvWindow: optional - :type recvWindow: int - - """ - return self._request_margin_api('get', 'fiat/orders', signed=True, data=params) - - def get_fiat_payments_history(self, **params): - """Get Fiat Payments History - - https://binance-docs.github.io/apidocs/spot/en/#get-fiat-payments-history-user_data - - :param transactionType: required - 0-buy,1-sell - :type transactionType: str - :param beginTime: optional - :type beginTime: int - :param endTime: optional - :type endTime: int - :param page: optional - default 1 - :type page: int - :param rows: optional - default 100, max 500 - :type rows: int - :param recvWindow: optional - :type recvWindow: int - - """ - return self._request_margin_api('get', 'fiat/payments', signed=True, data=params) - - # C2C Endpoints - - def get_c2c_trade_history(self, **params): - """Get C2C Trade History - - https://binance-docs.github.io/apidocs/spot/en/#get-c2c-trade-history-user_data - - :param tradeType: required - BUY, SELL - :type tradeType: str - :param startTimestamp: optional - :type startTime: int - :param endTimestamp: optional - :type endTimestamp: int - :param page: optional - default 1 - :type page: int - :param rows: optional - default 100, max 100 - :type rows: int - :param recvWindow: optional - :type recvWindow: int - - :returns: API response - - { - "code": "000000", - "message": "success", - "data": [ - { - "orderNumber":"20219644646554779648", - "advNo": "11218246497340923904", - "tradeType": "SELL", - "asset": "BUSD", - "fiat": "CNY", - "fiatSymbol": "¥", - "amount": "5000.00000000", // Quantity (in Crypto) - "totalPrice": "33400.00000000", - "unitPrice": "6.68", // Unit Price (in Fiat) - "orderStatus": "COMPLETED", // PENDING, TRADING, BUYER_PAYED, DISTRIBUTING, COMPLETED, IN_APPEAL, CANCELLED, CANCELLED_BY_SYSTEM - "createTime": 1619361369000, - "commission": "0", // Transaction Fee (in Crypto) - "counterPartNickName": "ab***", - "advertisementRole": "TAKER" - } - ], - "total": 1, - "success": true - } - - """ - return self._request_margin_api('get', 'c2c/orderMatch/listUserOrderHistory', signed=True, data=params) - - def close_connection(self): - if self.session: - self.session.close() - - def __del__(self): - self.close_connection() - - -class AsyncClient(BaseClient): - - def __init__( - self, api_key: Optional[str] = None, api_secret: Optional[str] = None, - requests_params: Dict[str, str] = None, tld: str = 'com', - testnet: bool = False, loop=None - ): - - self.loop = loop or asyncio.get_event_loop() - super().__init__(api_key, api_secret, requests_params, tld, testnet) - - @classmethod - async def create( - cls, api_key: Optional[str] = None, api_secret: Optional[str] = None, - requests_params: Dict[str, str] = None, tld: str = 'com', - testnet: bool = False, loop=None - ): - - self = cls(api_key, api_secret, requests_params, tld, testnet, loop) - - try: - await self.ping() - - # calculate timestamp offset between local and binance server - res = await self.get_server_time() - self.timestamp_offset = res['serverTime'] - int(time.time() * 1000) - - return self - except Exception: - # If ping throw an exception, the current self must be cleaned - # else, we can receive a "asyncio:Unclosed client session" - await self.close_connection() - raise - - def _init_session(self) -> aiohttp.ClientSession: - - session = aiohttp.ClientSession( - loop=self.loop, - headers=self._get_headers() - ) - return session - - async def close_connection(self): - if self.session: - assert self.session - await self.session.close() - - async def _request(self, method, uri: str, signed: bool, force_params: bool = False, **kwargs): - - kwargs = self._get_request_kwargs(method, signed, force_params, **kwargs) - - async with getattr(self.session, method)(uri, **kwargs) as response: - self.response = response - return await self._handle_response(response) - - async def _handle_response(self, response: aiohttp.ClientResponse): - """Internal helper for handling API responses from the Binance server. - Raises the appropriate exceptions when necessary; otherwise, returns the - response. - """ - if not str(response.status).startswith('2'): - raise BinanceAPIException(response, response.status, await response.text()) - try: - return await response.json() - except ValueError: - txt = await response.text() - raise BinanceRequestException(f'Invalid Response: {txt}') - - async def _request_api(self, method, path, signed=False, version=BaseClient.PUBLIC_API_VERSION, **kwargs): - uri = self._create_api_uri(path, signed, version) - return await self._request(method, uri, signed, **kwargs) - - async def _request_futures_api(self, method, path, signed=False, **kwargs) -> Dict: - uri = self._create_futures_api_uri(path) - - return await self._request(method, uri, signed, True, **kwargs) - - async def _request_futures_data_api(self, method, path, signed=False, **kwargs) -> Dict: - uri = self._create_futures_data_api_uri(path) - - return await self._request(method, uri, signed, True, **kwargs) - - async def _request_futures_coin_api(self, method, path, signed=False, version=1, **kwargs) -> Dict: - uri = self._create_futures_coin_api_url(path, version=version) - - return await self._request(method, uri, signed, True, **kwargs) - - async def _request_futures_coin_data_api(self, method, path, signed=False, version=1, **kwargs) -> Dict: - uri = self._create_futures_coin_data_api_url(path, version=version) - - return await self._request(method, uri, signed, True, **kwargs) - - async def _request_options_api(self, method, path, signed=False, **kwargs) -> Dict: - uri = self._create_options_api_uri(path) - - return await self._request(method, uri, signed, True, **kwargs) - - async def _request_margin_api(self, method, path, signed=False, **kwargs) -> Dict: - uri = self._create_margin_api_uri(path) - - return await self._request(method, uri, signed, **kwargs) - - async def _request_website(self, method, path, signed=False, **kwargs) -> Dict: - uri = self._create_website_uri(path) - return await self._request(method, uri, signed, **kwargs) - - async def _get(self, path, signed=False, version=BaseClient.PUBLIC_API_VERSION, **kwargs): - return await self._request_api('get', path, signed, version, **kwargs) - - async def _post(self, path, signed=False, version=BaseClient.PUBLIC_API_VERSION, **kwargs) -> Dict: - return await self._request_api('post', path, signed, version, **kwargs) - - async def _put(self, path, signed=False, version=BaseClient.PUBLIC_API_VERSION, **kwargs) -> Dict: - return await self._request_api('put', path, signed, version, **kwargs) - - async def _delete(self, path, signed=False, version=BaseClient.PUBLIC_API_VERSION, **kwargs) -> Dict: - return await self._request_api('delete', path, signed, version, **kwargs) - - # Exchange Endpoints - - async def get_products(self) -> Dict: - products = await self._request_website('get', 'exchange-api/v1/public/asset-service/product/get-products') - return products - get_products.__doc__ = Client.get_products.__doc__ - - async def get_exchange_info(self) -> Dict: - return await self._get('exchangeInfo', version=self.PRIVATE_API_VERSION) - get_exchange_info.__doc__ = Client.get_exchange_info.__doc__ - - async def get_symbol_info(self, symbol) -> Optional[Dict]: - res = await self.get_exchange_info() - - for item in res['symbols']: - if item['symbol'] == symbol.upper(): - return item - - return None - get_symbol_info.__doc__ = Client.get_symbol_info.__doc__ - - # General Endpoints - - async def ping(self) -> Dict: - return await self._get('ping', version=self.PRIVATE_API_VERSION) - ping.__doc__ = Client.ping.__doc__ - - async def get_server_time(self) -> Dict: - return await self._get('time', version=self.PRIVATE_API_VERSION) - get_server_time.__doc__ = Client.get_server_time.__doc__ - - # Market Data Endpoints - - async def get_all_tickers(self, symbol: Optional[str] = None) -> List[Dict[str, str]]: - params = {} - if symbol: - params['symbol'] = symbol - return await self._get('ticker/price', version=self.PRIVATE_API_VERSION, data=params) - get_all_tickers.__doc__ = Client.get_all_tickers.__doc__ - - async def get_orderbook_tickers(self) -> Dict: - return await self._get('ticker/bookTicker', version=self.PRIVATE_API_VERSION) - get_orderbook_tickers.__doc__ = Client.get_orderbook_tickers.__doc__ - - async def get_order_book(self, **params) -> Dict: - return await self._get('depth', data=params, version=self.PRIVATE_API_VERSION) - get_order_book.__doc__ = Client.get_order_book.__doc__ - - async def get_recent_trades(self, **params) -> Dict: - return await self._get('trades', data=params) - get_recent_trades.__doc__ = Client.get_recent_trades.__doc__ - - async def get_historical_trades(self, **params) -> Dict: - return await self._get('historicalTrades', data=params, version=self.PRIVATE_API_VERSION) - get_historical_trades.__doc__ = Client.get_historical_trades.__doc__ - - async def get_aggregate_trades(self, **params) -> Dict: - return await self._get('aggTrades', data=params, version=self.PRIVATE_API_VERSION) - get_aggregate_trades.__doc__ = Client.get_aggregate_trades.__doc__ - - async def aggregate_trade_iter(self, symbol, start_str=None, last_id=None): - if start_str is not None and last_id is not None: - raise ValueError( - 'start_time and last_id may not be simultaneously specified.') - - # If there's no last_id, get one. - if last_id is None: - # Without a last_id, we actually need the first trade. Normally, - # we'd get rid of it. See the next loop. - if start_str is None: - trades = await self.get_aggregate_trades(symbol=symbol, fromId=0) - else: - # The difference between startTime and endTime should be less - # or equal than an hour and the result set should contain at - # least one trade. - start_ts = convert_ts_str(start_str) - # If the resulting set is empty (i.e. no trades in that interval) - # then we just move forward hour by hour until we find at least one - # trade or reach present moment - while True: - end_ts = start_ts + (60 * 60 * 1000) - trades = await self.get_aggregate_trades( - symbol=symbol, - startTime=start_ts, - endTime=end_ts) - if len(trades) > 0: - break - # If we reach present moment and find no trades then there is - # nothing to iterate, so we're done - if end_ts > int(time.time() * 1000): - return - start_ts = end_ts - for t in trades: - yield t - last_id = trades[-1][self.AGG_ID] - - while True: - # There is no need to wait between queries, to avoid hitting the - # rate limit. We're using blocking IO, and as long as we're the - # only thread running calls like this, Binance will automatically - # add the right delay time on their end, forcing us to wait for - # data. That really simplifies this function's job. Binance is - # fucking awesome. - trades = await self.get_aggregate_trades(symbol=symbol, fromId=last_id) - # fromId=n returns a set starting with id n, but we already have - # that one. So get rid of the first item in the result set. - trades = trades[1:] - if len(trades) == 0: - return - for t in trades: - yield t - last_id = trades[-1][self.AGG_ID] - aggregate_trade_iter.__doc__ = Client.aggregate_trade_iter.__doc__ - - async def get_klines(self, **params) -> Dict: - return await self._get('klines', data=params, version=self.PRIVATE_API_VERSION) - get_klines.__doc__ = Client.get_klines.__doc__ - - async def _klines(self, klines_type: HistoricalKlinesType = HistoricalKlinesType.SPOT, **params) -> Dict: - if 'endTime' in params and not params['endTime']: - del params['endTime'] - if HistoricalKlinesType.SPOT == klines_type: - return await self.get_klines(**params) - elif HistoricalKlinesType.FUTURES == klines_type: - return await self.futures_klines(**params) - else: - raise NotImplementedException(klines_type) - _klines.__doc__ = Client._klines.__doc__ - - async def _get_earliest_valid_timestamp(self, symbol, interval, - klines_type: HistoricalKlinesType = HistoricalKlinesType.SPOT): - kline = await self._klines( - klines_type=klines_type, - symbol=symbol, - interval=interval, - limit=1, - startTime=0, - endTime=int(time.time() * 1000) - ) - return kline[0][0] - _get_earliest_valid_timestamp.__doc__ = Client._get_earliest_valid_timestamp.__doc__ - - async def get_historical_klines(self, symbol, interval, start_str, end_str=None, limit=500, - klines_type: HistoricalKlinesType = HistoricalKlinesType.SPOT): - return await self._historical_klines(symbol, interval, start_str, end_str=end_str, limit=limit, klines_type=klines_type) - get_historical_klines.__doc__ = Client.get_historical_klines.__doc__ - - async def _historical_klines(self, symbol, interval, start_str, end_str=None, limit=500, - klines_type: HistoricalKlinesType = HistoricalKlinesType.SPOT): - - # init our list - output_data = [] - - # convert interval to useful value in seconds - timeframe = interval_to_milliseconds(interval) - - # convert our date strings to milliseconds - start_ts = convert_ts_str(start_str) - - # establish first available start timestamp - first_valid_ts = await self._get_earliest_valid_timestamp(symbol, interval, klines_type) - start_ts = max(start_ts, first_valid_ts) - - # if an end time was passed convert it - end_ts = convert_ts_str(end_str) - - idx = 0 - while True: - # fetch the klines from start_ts up to max 500 entries or the end_ts if set - temp_data = await self._klines( - klines_type=klines_type, - symbol=symbol, - interval=interval, - limit=limit, - startTime=start_ts, - endTime=end_ts - ) - - # handle the case where exactly the limit amount of data was returned last loop - if not len(temp_data): - break - - # append this loops data to our output data - output_data += temp_data - - # set our start timestamp using the last value in the array - start_ts = temp_data[-1][0] - - idx += 1 - # check if we received less than the required limit and exit the loop - if len(temp_data) < limit: - # exit the while loop - break - - # increment next call by our timeframe - start_ts += timeframe - - # sleep after every 3rd call to be kind to the API - if idx % 3 == 0: - await asyncio.sleep(1) - - return output_data - _historical_klines.__doc__ = Client._historical_klines.__doc__ - - async def get_historical_klines_generator(self, symbol, interval, start_str, end_str=None, - klines_type: HistoricalKlinesType = HistoricalKlinesType.SPOT): - return self._historical_klines_generator(symbol, interval, start_str, end_str=end_str, klines_type=klines_type) - get_historical_klines_generator.__doc__ = Client.get_historical_klines_generator.__doc__ - - async def _historical_klines_generator(self, symbol, interval, start_str, end_str=None, - klines_type: HistoricalKlinesType = HistoricalKlinesType.SPOT): - - # setup the max limit - limit = 500 - - # convert interval to useful value in seconds - timeframe = interval_to_milliseconds(interval) - - # convert our date strings to milliseconds - start_ts = convert_ts_str(start_str) - - # establish first available start timestamp - first_valid_ts = await self._get_earliest_valid_timestamp(symbol, interval, klines_type) - start_ts = max(start_ts, first_valid_ts) - - # if an end time was passed convert it - end_ts = convert_ts_str(end_str) - - idx = 0 - while True: - # fetch the klines from start_ts up to max 500 entries or the end_ts if set - output_data = await self._klines( - klines_type=klines_type, - symbol=symbol, - interval=interval, - limit=limit, - startTime=start_ts, - endTime=end_ts - ) - - # handle the case where exactly the limit amount of data was returned last loop - if not len(output_data): - break - - # yield data - for o in output_data: - yield o - - # set our start timestamp using the last value in the array - start_ts = output_data[-1][0] - - idx += 1 - # check if we received less than the required limit and exit the loop - if len(output_data) < limit: - # exit the while loop - break - - # increment next call by our timeframe - start_ts += timeframe - - # sleep after every 3rd call to be kind to the API - if idx % 3 == 0: - await asyncio.sleep(1) - _historical_klines_generator.__doc__ = Client._historical_klines_generator.__doc__ - - async def get_avg_price(self, **params): - return await self._get('avgPrice', data=params, version=self.PRIVATE_API_VERSION) - get_avg_price.__doc__ = Client.get_avg_price.__doc__ - - async def get_ticker(self, **params): - return await self._get('ticker/24hr', data=params, version=self.PRIVATE_API_VERSION) - get_ticker.__doc__ = Client.get_ticker.__doc__ - - async def get_symbol_ticker(self, **params): - return await self._get('ticker/price', data=params, version=self.PRIVATE_API_VERSION) - get_symbol_ticker.__doc__ = Client.get_symbol_ticker.__doc__ - - async def get_orderbook_ticker(self, **params): - return await self._get('ticker/bookTicker', data=params, version=self.PRIVATE_API_VERSION) - get_orderbook_ticker.__doc__ = Client.get_orderbook_ticker.__doc__ - - # Account Endpoints - - async def create_order(self, **params): - return await self._post('order', True, data=params) - create_order.__doc__ = Client.create_order.__doc__ - - async def order_limit(self, timeInForce=BaseClient.TIME_IN_FORCE_GTC, **params): - params.update({ - 'type': self.ORDER_TYPE_LIMIT, - 'timeInForce': timeInForce - }) - return await self.create_order(**params) - order_limit.__doc__ = Client.order_limit.__doc__ - - async def order_limit_buy(self, timeInForce=BaseClient.TIME_IN_FORCE_GTC, **params): - params.update({ - 'side': self.SIDE_BUY, - }) - return await self.order_limit(timeInForce=timeInForce, **params) - order_limit_buy.__doc__ = Client.order_limit_buy.__doc__ - - async def order_limit_sell(self, timeInForce=BaseClient.TIME_IN_FORCE_GTC, **params): - params.update({ - 'side': self.SIDE_SELL - }) - return await self.order_limit(timeInForce=timeInForce, **params) - order_limit_sell.__doc__ = Client.order_limit_sell.__doc__ - - async def order_market(self, **params): - params.update({ - 'type': self.ORDER_TYPE_MARKET - }) - return await self.create_order(**params) - order_market.__doc__ = Client.order_market.__doc__ - - async def order_market_buy(self, **params): - params.update({ - 'side': self.SIDE_BUY - }) - return await self.order_market(**params) - order_market_buy.__doc__ = Client.order_market_buy.__doc__ - - async def order_market_sell(self, **params): - params.update({ - 'side': self.SIDE_SELL - }) - return await self.order_market(**params) - order_market_sell.__doc__ = Client.order_market_sell.__doc__ - - async def create_oco_order(self, **params): - return await self._post('order/oco', True, data=params) - create_oco_order.__doc__ = Client.create_oco_order.__doc__ - - async def order_oco_buy(self, **params): - params.update({ - 'side': self.SIDE_BUY - }) - return await self.create_oco_order(**params) - order_oco_buy.__doc__ = Client.order_oco_buy.__doc__ - - async def order_oco_sell(self, **params): - params.update({ - 'side': self.SIDE_SELL - }) - return await self.create_oco_order(**params) - order_oco_sell.__doc__ = Client.order_oco_sell.__doc__ - - async def create_test_order(self, **params): - return await self._post('order/test', True, data=params) - create_test_order.__doc__ = Client.create_test_order.__doc__ - - async def get_order(self, **params): - return await self._get('order', True, data=params) - get_order.__doc__ = Client.get_order.__doc__ - - async def get_all_orders(self, **params): - return await self._get('allOrders', True, data=params) - get_all_orders.__doc__ = Client.get_all_orders.__doc__ - - async def cancel_order(self, **params): - return await self._delete('order', True, data=params) - cancel_order.__doc__ = Client.cancel_order.__doc__ - - async def get_open_orders(self, **params): - return await self._get('openOrders', True, data=params) - get_open_orders.__doc__ = Client.get_open_orders.__doc__ - - # User Stream Endpoints - async def get_account(self, **params): - return await self._get('account', True, data=params) - get_account.__doc__ = Client.get_account.__doc__ - - async def get_asset_balance(self, asset, **params): - res = await self.get_account(**params) - # find asset balance in list of balances - if "balances" in res: - for bal in res['balances']: - if bal['asset'].lower() == asset.lower(): - return bal - return None - get_asset_balance.__doc__ = Client.get_asset_balance.__doc__ - - async def get_my_trades(self, **params): - return await self._get('myTrades', True, data=params) - get_my_trades.__doc__ = Client.get_my_trades.__doc__ - - async def get_system_status(self): - return await self._request_margin_api('get', 'system/status') - get_system_status.__doc__ = Client.get_system_status.__doc__ - - async def get_account_status(self, **params): - return await self._request_margin_api('get', 'account/status', True, data=params) - get_account_status.__doc__ = Client.get_account_status.__doc__ - - async def get_account_api_trading_status(self, **params): - return await self._request_margin_api('get', 'account/apiTradingStatus', True, data=params) - get_account_api_trading_status.__doc__ = Client.get_account_api_trading_status.__doc__ - - async def get_account_api_permissions(self, **params): - return await self._request_margin_api('get', 'account/apiRestrictions', True, data=params) - get_account_api_permissions.__doc__ = Client.get_account_api_permissions.__doc__ - - async def get_dust_log(self, **params): - return await self._request_margin_api('get', 'asset/dribblet', True, data=params) - get_dust_log.__doc__ = Client.get_dust_log.__doc__ - - async def transfer_dust(self, **params): - return await self._request_margin_api('post', 'asset/dust', True, data=params) - transfer_dust.__doc__ = Client.transfer_dust.__doc__ - - async def get_asset_dividend_history(self, **params): - return await self._request_margin_api('get', 'asset/assetDividend', True, data=params) - get_asset_dividend_history.__doc__ = Client.get_asset_dividend_history.__doc__ - - async def make_universal_transfer(self, **params): - return await self._request_margin_api('post', 'asset/transfer', signed=True, data=params) - make_universal_transfer.__doc__ = Client.make_universal_transfer.__doc__ - - async def query_universal_transfer_history(self, **params): - return await self._request_margin_api('get', 'asset/transfer', signed=True, data=params) - query_universal_transfer_history.__doc__ = Client.query_universal_transfer_history.__doc__ - - async def get_trade_fee(self, **params): - return await self._request_margin_api('get', 'asset/tradeFee', True, data=params) - get_trade_fee.__doc__ = Client.get_trade_fee.__doc__ - - async def get_asset_details(self, **params): - return await self._request_margin_api('get', 'asset/assetDetail', True, data=params) - get_asset_details.__doc__ = Client.get_asset_details.__doc__ - - # Withdraw Endpoints - - async def withdraw(self, **params): - # force a name for the withdrawal if one not set - if 'coin' in params and 'name' not in params: - params['name'] = params['coin'] - return await self._request_margin_api('post', 'capital/withdraw/apply', True, data=params) - withdraw.__doc__ = Client.withdraw.__doc__ - - async def get_deposit_history(self, **params): - return await self._request_margin_api('get', 'capital/deposit/hisrec', True, data=params) - get_deposit_history.__doc__ = Client.get_deposit_history.__doc__ - - async def get_withdraw_history(self, **params): - return await self._request_margin_api('get', 'capital/withdraw/history', True, data=params) - get_withdraw_history.__doc__ = Client.get_withdraw_history.__doc__ - - async def get_withdraw_history_id(self, withdraw_id, **params): - result = await self.get_withdraw_history(**params) - - for entry in result: - if 'id' in entry and entry['id'] == withdraw_id: - return entry - - raise Exception("There is no entry with withdraw id", result) - get_withdraw_history_id.__doc__ = Client.get_withdraw_history_id.__doc__ - - async def get_deposit_address(self, coin: str, network: Optional[str] = None, **params): - params['coin'] = coin - if network: - params['network'] = network - return await self._request_margin_api('get', 'capital/deposit/address', True, data=params) - get_deposit_address.__doc__ = Client.get_deposit_address.__doc__ - - # User Stream Endpoints - - async def stream_get_listen_key(self): - res = await self._post('userDataStream', False, data={}) - return res['listenKey'] - stream_get_listen_key.__doc__ = Client.stream_get_listen_key.__doc__ - - async def stream_keepalive(self, listenKey): - params = { - 'listenKey': listenKey - } - return await self._put('userDataStream', False, data=params) - stream_keepalive.__doc__ = Client.stream_keepalive.__doc__ - - async def stream_close(self, listenKey): - params = { - 'listenKey': listenKey - } - return await self._delete('userDataStream', False, data=params) - stream_close.__doc__ = Client.stream_close.__doc__ - - # Margin Trading Endpoints - async def get_margin_account(self, **params): - return await self._request_margin_api('get', 'margin/account', True, data=params) - get_margin_account.__doc__ = Client.get_margin_account.__doc__ - - async def get_isolated_margin_account(self, **params): - return await self._request_margin_api('get', 'margin/isolated/account', True, data=params) - - async def enable_isolated_margin_account(self, **params): - return await self._request_margin_api('post', 'margin/isolated/account', True, data=params) - - async def disable_isolated_margin_account(self, **params): - return await self._request_margin_api('delete', 'margin/isolated/account', True, data=params) - - async def get_margin_asset(self, **params): - return await self._request_margin_api('get', 'margin/asset', data=params) - - async def get_margin_symbol(self, **params): - return await self._request_margin_api('get', 'margin/pair', data=params) - - async def get_margin_all_assets(self, **params): - return await self._request_margin_api('get', 'margin/allAssets', data=params) - - async def get_margin_all_pairs(self, **params): - return await self._request_margin_api('get', 'margin/allPairs', data=params) - - async def create_isolated_margin_account(self, **params): - return await self._request_margin_api('post', 'margin/isolated/create', signed=True, data=params) - - async def get_isolated_margin_symbol(self, **params): - return await self._request_margin_api('get', 'margin/isolated/pair', signed=True, data=params) - - async def get_all_isolated_margin_symbols(self, **params): - return await self._request_margin_api('get', 'margin/isolated/allPairs', signed=True, data=params) - - async def toggle_bnb_burn_spot_margin(self, **params): - return await self._request_margin_api('post', 'bnbBurn', signed=True, data=params) - - async def get_bnb_burn_spot_margin(self, **params): - return await self._request_margin_api('get', 'bnbBurn', signed=True, data=params) - - async def get_margin_price_index(self, **params): - return await self._request_margin_api('get', 'margin/priceIndex', data=params) - - async def transfer_margin_to_spot(self, **params): - params['type'] = 2 - return await self._request_margin_api('post', 'margin/transfer', signed=True, data=params) - - async def transfer_spot_to_margin(self, **params): - params['type'] = 1 - return await self._request_margin_api('post', 'margin/transfer', signed=True, data=params) - - async def transfer_isolated_margin_to_spot(self, **params): - params['transFrom'] = "ISOLATED_MARGIN" - params['transTo'] = "SPOT" - return await self._request_margin_api('post', 'margin/isolated/transfer', signed=True, data=params) - - async def transfer_spot_to_isolated_margin(self, **params): - params['transFrom'] = "SPOT" - params['transTo'] = "ISOLATED_MARGIN" - return await self._request_margin_api('post', 'margin/isolated/transfer', signed=True, data=params) - - async def create_margin_loan(self, **params): - return await self._request_margin_api('post', 'margin/loan', signed=True, data=params) - - async def repay_margin_loan(self, **params): - return await self._request_margin_api('post', 'margin/repay', signed=True, data=params) - - async def create_margin_order(self, **params): - return await self._request_margin_api('post', 'margin/order', signed=True, data=params) - - async def cancel_margin_order(self, **params): - return await self._request_margin_api('delete', 'margin/order', signed=True, data=params) - - async def get_margin_loan_details(self, **params): - return await self._request_margin_api('get', 'margin/loan', signed=True, data=params) - - async def get_margin_repay_details(self, **params): - return await self._request_margin_api('get', 'margin/repay', signed=True, data=params) - - async def get_margin_interest_history(self, **params): - return await self._request_margin_api('get', 'margin/interestHistory', signed=True, data=params) - - async def get_margin_force_liquidation_rec(self, **params): - return await self._request_margin_api('get', 'margin/forceLiquidationRec', signed=True, data=params) - - async def get_margin_order(self, **params): - return await self._request_margin_api('get', 'margin/order', signed=True, data=params) - - async def get_open_margin_orders(self, **params): - return await self._request_margin_api('get', 'margin/openOrders', signed=True, data=params) - - async def get_all_margin_orders(self, **params): - return await self._request_margin_api('get', 'margin/allOrders', signed=True, data=params) - - async def get_margin_trades(self, **params): - return await self._request_margin_api('get', 'margin/myTrades', signed=True, data=params) - - async def get_max_margin_loan(self, **params): - return await self._request_margin_api('get', 'margin/maxBorrowable', signed=True, data=params) - - async def get_max_margin_transfer(self, **params): - return await self._request_margin_api('get', 'margin/maxTransferable', signed=True, data=params) - - # Margin OCO - - async def create_margin_oco_order(self, **params): - return await self._request_margin_api('post', 'margin/order/oco', signed=True, data=params) - - async def cancel_margin_oco_order(self, **params): - return await self._request_margin_api('delete', 'margin/orderList', signed=True, data=params) - - async def get_margin_oco_order(self, **params): - return await self._request_margin_api('get', 'margin/orderList', signed=True, data=params) - - async def get_open_margin_oco_orders(self, **params): - return await self._request_margin_api('get', 'margin/allOrderList', signed=True, data=params) - - # Cross-margin - - async def margin_stream_get_listen_key(self): - res = await self._request_margin_api('post', 'userDataStream', signed=False, data={}) - return res['listenKey'] - - async def margin_stream_keepalive(self, listenKey): - params = { - 'listenKey': listenKey - } - return await self._request_margin_api('put', 'userDataStream', signed=False, data=params) - - async def margin_stream_close(self, listenKey): - params = { - 'listenKey': listenKey - } - return await self._request_margin_api('delete', 'userDataStream', signed=False, data=params) - - # Isolated margin - - async def isolated_margin_stream_get_listen_key(self, symbol): - params = { - 'symbol': symbol - } - res = await self._request_margin_api('post', 'userDataStream/isolated', signed=False, data=params) - return res['listenKey'] - - async def isolated_margin_stream_keepalive(self, symbol, listenKey): - params = { - 'symbol': symbol, - 'listenKey': listenKey - } - return await self._request_margin_api('put', 'userDataStream/isolated', signed=False, data=params) - - async def isolated_margin_stream_close(self, symbol, listenKey): - params = { - 'symbol': symbol, - 'listenKey': listenKey - } - return await self._request_margin_api('delete', 'userDataStream/isolated', signed=False, data=params) - - # Lending Endpoints - - async def get_lending_product_list(self, **params): - return await self._request_margin_api('get', 'lending/daily/product/list', signed=True, data=params) - - async def get_lending_daily_quota_left(self, **params): - return await self._request_margin_api('get', 'lending/daily/userLeftQuota', signed=True, data=params) - - async def purchase_lending_product(self, **params): - return await self._request_margin_api('post', 'lending/daily/purchase', signed=True, data=params) - - async def get_lending_daily_redemption_quota(self, **params): - return await self._request_margin_api('get', 'lending/daily/userRedemptionQuota', signed=True, data=params) - - async def redeem_lending_product(self, **params): - return await self._request_margin_api('post', 'lending/daily/redeem', signed=True, data=params) - - async def get_lending_position(self, **params): - return await self._request_margin_api('get', 'lending/daily/token/position', signed=True, data=params) - - async def get_fixed_activity_project_list(self, **params): - return await self._request_margin_api('get', 'lending/project/list', signed=True, data=params) - - async def get_lending_account(self, **params): - return await self._request_margin_api('get', 'lending/union/account', signed=True, data=params) - - async def get_lending_purchase_history(self, **params): - return await self._request_margin_api('get', 'lending/union/purchaseRecord', signed=True, data=params) - - async def get_lending_redemption_history(self, **params): - return await self._request_margin_api('get', 'lending/union/redemptionRecord', signed=True, data=params) - - async def get_lending_interest_history(self, **params): - return await self._request_margin_api('get', 'lending/union/interestHistory', signed=True, data=params) - - async def change_fixed_activity_to_daily_position(self, **params): - return await self._request_margin_api('post', 'lending/positionChanged', signed=True, data=params) - - # Sub Accounts - - async def get_sub_account_list(self, **params): - return await self._request_margin_api('get', 'sub-account/list', True, data=params) - - async def get_sub_account_transfer_history(self, **params): - return await self._request_margin_api('get', 'sub-account/sub/transfer/history', True, data=params) - - async def get_sub_account_futures_transfer_history(self, **params): - return await self._request_margin_api('get', 'sub-account/futures/internalTransfer', True, data=params) - - async def create_sub_account_futures_transfer(self, **params): - return await self._request_margin_api('post', 'sub-account/futures/internalTransfer', True, data=params) - - async def get_sub_account_assets(self, **params): - return await self._request_margin_api('get', 'sub-account/assets', True, data=params) - - async def query_subaccount_spot_summary(self, **params): - return await self._request_margin_api('get', 'sub-account/spotSummary', True, data=params) - - async def get_subaccount_deposit_address(self, **params): - return await self._request_margin_api('get', 'capital/deposit/subAddress', True, data=params) - - async def get_subaccount_deposit_history(self, **params): - return await self._request_margin_api('get', 'capital/deposit/subHisrec', True, data=params) - - async def get_subaccount_futures_margin_status(self, **params): - return await self._request_margin_api('get', 'sub-account/status', True, data=params) - - async def enable_subaccount_margin(self, **params): - return await self._request_margin_api('post', 'sub-account/margin/enable', True, data=params) - - async def get_subaccount_margin_details(self, **params): - return await self._request_margin_api('get', 'sub-account/margin/account', True, data=params) - - async def get_subaccount_margin_summary(self, **params): - return await self._request_margin_api('get', 'sub-account/margin/accountSummary', True, data=params) - - async def enable_subaccount_futures(self, **params): - return await self._request_margin_api('post', 'sub-account/futures/enable', True, data=params) - - async def get_subaccount_futures_details(self, **params): - return await self._request_margin_api('get', 'sub-account/futures/account', True, data=params) - - async def get_subaccount_futures_summary(self, **params): - return await self._request_margin_api('get', 'sub-account/futures/accountSummary', True, data=params) - - async def get_subaccount_futures_positionrisk(self, **params): - return await self._request_margin_api('get', 'sub-account/futures/positionRisk', True, data=params) - - async def make_subaccount_futures_transfer(self, **params): - return await self._request_margin_api('post', 'sub-account/futures/transfer', True, data=params) - - async def make_subaccount_margin_transfer(self, **params): - return await self._request_margin_api('post', 'sub-account/margin/transfer', True, data=params) - - async def make_subaccount_to_subaccount_transfer(self, **params): - return await self._request_margin_api('post', 'sub-account/transfer/subToSub', True, data=params) - - async def make_subaccount_to_master_transfer(self, **params): - return await self._request_margin_api('post', 'sub-account/transfer/subToMaster', True, data=params) - - async def get_subaccount_transfer_history(self, **params): - return await self._request_margin_api('get', 'sub-account/transfer/subUserHistory', True, data=params) - - async def make_subaccount_universal_transfer(self, **params): - return await self._request_margin_api('post', 'sub-account/universalTransfer', True, data=params) - - async def get_universal_transfer_history(self, **params): - return await self._request_margin_api('get', 'sub-account/universalTransfer', True, data=params) - - # Futures API - - async def futures_ping(self): - return await self._request_futures_api('get', 'ping') - - async def futures_time(self): - return await self._request_futures_api('get', 'time') - - async def futures_exchange_info(self): - return await self._request_futures_api('get', 'exchangeInfo') - - async def futures_order_book(self, **params): - return await self._request_futures_api('get', 'depth', data=params) - - async def futures_recent_trades(self, **params): - return await self._request_futures_api('get', 'trades', data=params) - - async def futures_historical_trades(self, **params): - return await self._request_futures_api('get', 'historicalTrades', data=params) - - async def futures_aggregate_trades(self, **params): - return await self._request_futures_api('get', 'aggTrades', data=params) - - async def futures_klines(self, **params): - return await self._request_futures_api('get', 'klines', data=params) - - async def futures_continous_klines(self, **params): - return await self._request_futures_api('get', 'continuousKlines', data=params) - - async def futures_historical_klines(self, symbol, interval, start_str, end_str=None, limit=500): - return self._historical_klines(symbol, interval, start_str, end_str=end_str, limit=limit, klines_type=HistoricalKlinesType.FUTURES) - - async def futures_historical_klines_generator(self, symbol, interval, start_str, end_str=None): - return self._historical_klines_generator(symbol, interval, start_str, end_str=end_str, klines_type=HistoricalKlinesType.FUTURES) - - async def futures_mark_price(self, **params): - return await self._request_futures_api('get', 'premiumIndex', data=params) - - async def futures_funding_rate(self, **params): - return await self._request_futures_api('get', 'fundingRate', data=params) - - async def futures_top_longshort_account_ratio(self, **params): - return await self._request_futures_data_api('get', 'topLongShortAccountRatio', data=params) - - async def futures_top_longshort_position_ratio(self, **params): - return await self._request_futures_data_api('get', 'topLongShortPositionRatio', data=params) - - async def futures_global_longshort_ratio(self, **params): - return await self._request_futures_data_api('get', 'globalLongShortAccountRatio', data=params) - - async def futures_ticker(self, **params): - return await self._request_futures_api('get', 'ticker/24hr', data=params) - - async def futures_symbol_ticker(self, **params): - return await self._request_futures_api('get', 'ticker/price', data=params) - - async def futures_orderbook_ticker(self, **params): - return await self._request_futures_api('get', 'ticker/bookTicker', data=params) - - async def futures_liquidation_orders(self, **params): - return await self._request_futures_api('get', 'forceOrders', signed=True, data=params) - - async def futures_adl_quantile_estimate(self, **params): - return await self._request_futures_api('get', 'adlQuantile', signed=True, data=params) - - async def futures_open_interest(self, **params): - return await self._request_futures_api('get', 'openInterest', data=params) - - async def futures_open_interest_hist(self, **params): - return await self._request_futures_data_api('get', 'openInterestHist', data=params) - - async def futures_leverage_bracket(self, **params): - return await self._request_futures_api('get', 'leverageBracket', True, data=params) - - async def futures_account_transfer(self, **params): - return await self._request_margin_api('post', 'futures/transfer', True, data=params) - - async def transfer_history(self, **params): - return await self._request_margin_api('get', 'futures/transfer', True, data=params) - - async def futures_create_order(self, **params): - return await self._request_futures_api('post', 'order', True, data=params) - - async def futures_place_batch_order(self, **params): - query_string = urlencode(params) - query_string = query_string.replace('%27', '%22') - params['batchOrders'] = query_string[12:] - return await self._request_futures_api('post', 'batchOrders', True, data=params) - - async def futures_get_order(self, **params): - return await self._request_futures_api('get', 'order', True, data=params) - - async def futures_get_open_orders(self, **params): - return await self._request_futures_api('get', 'openOrders', True, data=params) - - async def futures_get_all_orders(self, **params): - return await self._request_futures_api('get', 'allOrders', True, data=params) - - async def futures_cancel_order(self, **params): - return await self._request_futures_api('delete', 'order', True, data=params) - - async def futures_cancel_all_open_orders(self, **params): - return await self._request_futures_api('delete', 'allOpenOrders', True, data=params) - - async def futures_cancel_orders(self, **params): - return await self._request_futures_api('delete', 'batchOrders', True, data=params) - - async def futures_account_balance(self, **params): - return await self._request_futures_api('get', 'balance', True, data=params) - - async def futures_account(self, **params): - return await self._request_futures_api('get', 'account', True, data=params) - - async def futures_change_leverage(self, **params): - return await self._request_futures_api('post', 'leverage', True, data=params) - - async def futures_change_margin_type(self, **params): - return await self._request_futures_api('post', 'marginType', True, data=params) - - async def futures_change_position_margin(self, **params): - return await self._request_futures_api('post', 'positionMargin', True, data=params) - - async def futures_position_margin_history(self, **params): - return await self._request_futures_api('get', 'positionMargin/history', True, data=params) - - async def futures_position_information(self, **params): - return await self._request_futures_api('get', 'positionRisk', True, data=params) - - async def futures_account_trades(self, **params): - return await self._request_futures_api('get', 'userTrades', True, data=params) - - async def futures_income_history(self, **params): - return await self._request_futures_api('get', 'income', True, data=params) - - async def futures_change_position_mode(self, **params): - return await self._request_futures_api('post', 'positionSide/dual', True, data=params) - - async def futures_get_position_mode(self, **params): - return await self._request_futures_api('get', 'positionSide/dual', True, data=params) - - async def futures_change_multi_assets_mode(self, multiAssetsMargin: bool): - params = { - 'true' if multiAssetsMargin else 'false' - } - return await self._request_futures_api('post', 'multiAssetsMargin', True, data=params) - - async def futures_get_multi_assets_mode(self): - return await self._request_futures_api('get', 'multiAssetsMargin', True) - - async def futures_stream_get_listen_key(self): - res = await self._request_futures_api('post', 'listenKey', signed=False, data={}) - return res['listenKey'] - - async def futures_stream_keepalive(self, listenKey): - params = { - 'listenKey': listenKey - } - return await self._request_futures_api('put', 'listenKey', signed=False, data=params) - - async def futures_stream_close(self, listenKey): - params = { - 'listenKey': listenKey - } - return await self._request_futures_api('delete', 'listenKey', signed=False, data=params) - - # COIN Futures API - - async def futures_coin_ping(self): - return await self._request_futures_coin_api("get", "ping") - - async def futures_coin_time(self): - return await self._request_futures_coin_api("get", "time") - - async def futures_coin_exchange_info(self): - return await self._request_futures_coin_api("get", "exchangeInfo") - - async def futures_coin_order_book(self, **params): - return await self._request_futures_coin_api("get", "depth", data=params) - - async def futures_coin_recent_trades(self, **params): - return await self._request_futures_coin_api("get", "trades", data=params) - - async def futures_coin_historical_trades(self, **params): - return await self._request_futures_coin_api("get", "historicalTrades", data=params) - - async def futures_coin_aggregate_trades(self, **params): - return await self._request_futures_coin_api("get", "aggTrades", data=params) - - async def futures_coin_klines(self, **params): - return await self._request_futures_coin_api("get", "klines", data=params) - - async def futures_coin_continous_klines(self, **params): - return await self._request_futures_coin_api("get", "continuousKlines", data=params) - - async def futures_coin_index_price_klines(self, **params): - return await self._request_futures_coin_api("get", "indexPriceKlines", data=params) - - async def futures_coin_mark_price_klines(self, **params): - return await self._request_futures_coin_api("get", "markPriceKlines", data=params) - - async def futures_coin_mark_price(self, **params): - return await self._request_futures_coin_api("get", "premiumIndex", data=params) - - async def futures_coin_funding_rate(self, **params): - return await self._request_futures_coin_api("get", "fundingRate", data=params) - - async def futures_coin_ticker(self, **params): - return await self._request_futures_coin_api("get", "ticker/24hr", data=params) - - async def futures_coin_symbol_ticker(self, **params): - return await self._request_futures_coin_api("get", "ticker/price", data=params) - - async def futures_coin_orderbook_ticker(self, **params): - return await self._request_futures_coin_api("get", "ticker/bookTicker", data=params) - - async def futures_coin_liquidation_orders(self, **params): - return await self._request_futures_coin_api("get", "forceOrders", signed=True, data=params) - - async def futures_coin_open_interest(self, **params): - return await self._request_futures_coin_api("get", "openInterest", data=params) - - async def futures_coin_open_interest_hist(self, **params): - return await self._request_futures_coin_data_api("get", "openInterestHist", data=params) - - async def futures_coin_leverage_bracket(self, **params): - return await self._request_futures_coin_api( - "get", "leverageBracket", version=2, signed=True, data=params - ) - - async def new_transfer_history(self, **params): - return await self._request_margin_api("get", "asset/transfer", True, data=params) - - async def universal_transfer(self, **params): - return await self._request_margin_api( - "post", "asset/transfer", signed=True, data=params - ) - - async def futures_coin_create_order(self, **params): - return await self._request_futures_coin_api("post", "order", True, data=params) - - async def futures_coin_place_batch_order(self, **params): - query_string = urlencode(params) - query_string = query_string.replace('%27', '%22') - params['batchOrders'] = query_string[12:] - - return await self._request_futures_coin_api('post', 'batchOrders', True, data=params) - - async def futures_coin_get_order(self, **params): - return await self._request_futures_coin_api("get", "order", True, data=params) - - async def futures_coin_get_open_orders(self, **params): - return await self._request_futures_coin_api("get", "openOrders", True, data=params) - - async def futures_coin_get_all_orders(self, **params): - return await self._request_futures_coin_api( - "get", "allOrders", signed=True, data=params - ) - - async def futures_coin_cancel_order(self, **params): - return await self._request_futures_coin_api( - "delete", "order", signed=True, data=params - ) - - async def futures_coin_cancel_all_open_orders(self, **params): - return await self._request_futures_coin_api( - "delete", "allOpenOrders", signed=True, data=params - ) - - async def futures_coin_cancel_orders(self, **params): - return await self._request_futures_coin_api( - "delete", "batchOrders", True, data=params - ) - - async def futures_coin_account_balance(self, **params): - return await self._request_futures_coin_api( - "get", "balance", signed=True, data=params - ) - - async def futures_coin_account(self, **params): - return await self._request_futures_coin_api( - "get", "account", signed=True, data=params - ) - - async def futures_coin_change_leverage(self, **params): - return await self._request_futures_coin_api( - "post", "leverage", signed=True, data=params - ) - - async def futures_coin_change_margin_type(self, **params): - return await self._request_futures_coin_api( - "post", "marginType", signed=True, data=params - ) - - async def futures_coin_change_position_margin(self, **params): - return await self._request_futures_coin_api( - "post", "positionMargin", True, data=params - ) - - async def futures_coin_position_margin_history(self, **params): - return await self._request_futures_coin_api( - "get", "positionMargin/history", True, data=params - ) - - async def futures_coin_position_information(self, **params): - return await self._request_futures_coin_api("get", "positionRisk", True, data=params) - - async def futures_coin_account_trades(self, **params): - return await self._request_futures_coin_api("get", "userTrades", True, data=params) - - async def futures_coin_income_history(self, **params): - return await self._request_futures_coin_api("get", "income", True, data=params) - - async def futures_coin_change_position_mode(self, **params): - return await self._request_futures_coin_api("post", "positionSide/dual", True, data=params) - - async def futures_coin_get_position_mode(self, **params): - return await self._request_futures_coin_api("get", "positionSide/dual", True, data=params) - - async def futures_coin_stream_get_listen_key(self): - res = await self._request_futures_coin_api('post', 'listenKey', signed=False, data={}) - return res['listenKey'] - - async def futures_coin_stream_keepalive(self, listenKey): - params = { - 'listenKey': listenKey - } - return await self._request_futures_coin_api('put', 'listenKey', signed=False, data=params) - - async def futures_coin_stream_close(self, listenKey): - params = { - 'listenKey': listenKey - } - return await self._request_futures_coin_api('delete', 'listenKey', signed=False, data=params) - - async def get_all_coins_info(self, **params): - return await self._request_margin_api('get', 'capital/config/getall', True, data=params) - - async def get_account_snapshot(self, **params): - return await self._request_margin_api('get', 'accountSnapshot', True, data=params) - - async def disable_fast_withdraw_switch(self, **params): - return await self._request_margin_api('post', 'disableFastWithdrawSwitch', True, data=params) - - async def enable_fast_withdraw_switch(self, **params): - return await self._request_margin_api('post', 'enableFastWithdrawSwitch', True, data=params) - - """ - ==================================================================================================================== - Options API - ==================================================================================================================== - """ - - # Quoting interface endpoints - - async def options_ping(self): - return await self._request_options_api('get', 'ping') - - async def options_time(self): - return await self._request_options_api('get', 'time') - - async def options_info(self): - return await self._request_options_api('get', 'optionInfo') - - async def options_exchange_info(self): - return await self._request_options_api('get', 'exchangeInfo') - - async def options_index_price(self, **params): - return await self._request_options_api('get', 'index', data=params) - - async def options_price(self, **params): - return await self._request_options_api('get', 'ticker', data=params) - - async def options_mark_price(self, **params): - return await self._request_options_api('get', 'mark', data=params) - - async def options_order_book(self, **params): - return await self._request_options_api('get', 'depth', data=params) - - async def options_klines(self, **params): - return await self._request_options_api('get', 'klines', data=params) - - async def options_recent_trades(self, **params): - return await self._request_options_api('get', 'trades', data=params) - - async def options_historical_trades(self, **params): - return await self._request_options_api('get', 'historicalTrades', data=params) - - # Account and trading interface endpoints - - async def options_account_info(self, **params): - return await self._request_options_api('get', 'account', signed=True, data=params) - - async def options_funds_transfer(self, **params): - return await self._request_options_api('post', 'transfer', signed=True, data=params) - - async def options_positions(self, **params): - return await self._request_options_api('get', 'position', signed=True, data=params) - - async def options_bill(self, **params): - return await self._request_options_api('post', 'bill', signed=True, data=params) - - async def options_place_order(self, **params): - return await self._request_options_api('post', 'order', signed=True, data=params) - - async def options_place_batch_order(self, **params): - return await self._request_options_api('post', 'batchOrders', signed=True, data=params) - - async def options_cancel_order(self, **params): - return await self._request_options_api('delete', 'order', signed=True, data=params) - - async def options_cancel_batch_order(self, **params): - return await self._request_options_api('delete', 'batchOrders', signed=True, data=params) - - async def options_cancel_all_orders(self, **params): - return await self._request_options_api('delete', 'allOpenOrders', signed=True, data=params) - - async def options_query_order(self, **params): - return await self._request_options_api('get', 'order', signed=True, data=params) - - async def options_query_pending_orders(self, **params): - return await self._request_options_api('get', 'openOrders', signed=True, data=params) - - async def options_query_order_history(self, **params): - return await self._request_options_api('get', 'historyOrders', signed=True, data=params) - - async def options_user_trades(self, **params): - return await self._request_options_api('get', 'userTrades', signed=True, data=params) - - # Fiat Endpoints - - async def get_fiat_deposit_withdraw_history(self, **params): - return await self._request_margin_api('get', 'fiat/orders', signed=True, data=params) - - async def get_fiat_payments_history(self, **params): - return await self._request_margin_api('get', 'fiat/payments', signed=True, data=params) - - # C2C Endpoints - - async def get_c2c_trade_history(self, **params): - return await self._request_margin_api('get', 'c2c/orderMatch/listUserOrderHistory', signed=True, data=params) +from typing import Dict, Optional, List, Tuple + +import aiohttp +import asyncio +import hashlib +import hmac +import requests +import time +from operator import itemgetter +from urllib.parse import urlencode + + +from .helpers import interval_to_milliseconds, convert_ts_str +from .exceptions import BinanceAPIException, BinanceRequestException, NotImplementedException +from .enums import HistoricalKlinesType + + +class BaseClient: + + API_URL = 'https://api.binance.{}/api' + API_TESTNET_URL = 'https://testnet.binance.vision/api' + MARGIN_API_URL = 'https://api.binance.{}/sapi' + WEBSITE_URL = 'https://www.binance.{}' + FUTURES_URL = 'https://fapi.binance.{}/fapi' + FUTURES_TESTNET_URL = 'https://testnet.binancefuture.com/fapi' + FUTURES_DATA_URL = 'https://fapi.binance.{}/futures/data' + FUTURES_DATA_TESTNET_URL = 'https://testnet.binancefuture.com/futures/data' + FUTURES_COIN_URL = "https://dapi.binance.{}/dapi" + FUTURES_COIN_TESTNET_URL = 'https://testnet.binancefuture.com/dapi' + FUTURES_COIN_DATA_URL = "https://dapi.binance.{}/futures/data" + FUTURES_COIN_DATA_TESTNET_URL = 'https://testnet.binancefuture.com/futures/data' + OPTIONS_URL = 'https://vapi.binance.{}/vapi' + OPTIONS_TESTNET_URL = 'https://testnet.binanceops.{}/vapi' + PUBLIC_API_VERSION = 'v1' + PRIVATE_API_VERSION = 'v3' + MARGIN_API_VERSION = 'v1' + FUTURES_API_VERSION = 'v1' + FUTURES_API_VERSION2 = "v2" + OPTIONS_API_VERSION = 'v1' + + REQUEST_TIMEOUT: float = 10 + + SYMBOL_TYPE_SPOT = 'SPOT' + + ORDER_STATUS_NEW = 'NEW' + ORDER_STATUS_PARTIALLY_FILLED = 'PARTIALLY_FILLED' + ORDER_STATUS_FILLED = 'FILLED' + ORDER_STATUS_CANCELED = 'CANCELED' + ORDER_STATUS_PENDING_CANCEL = 'PENDING_CANCEL' + ORDER_STATUS_REJECTED = 'REJECTED' + ORDER_STATUS_EXPIRED = 'EXPIRED' + + KLINE_INTERVAL_1MINUTE = '1m' + KLINE_INTERVAL_3MINUTE = '3m' + KLINE_INTERVAL_5MINUTE = '5m' + KLINE_INTERVAL_15MINUTE = '15m' + KLINE_INTERVAL_30MINUTE = '30m' + KLINE_INTERVAL_1HOUR = '1h' + KLINE_INTERVAL_2HOUR = '2h' + KLINE_INTERVAL_4HOUR = '4h' + KLINE_INTERVAL_6HOUR = '6h' + KLINE_INTERVAL_8HOUR = '8h' + KLINE_INTERVAL_12HOUR = '12h' + KLINE_INTERVAL_1DAY = '1d' + KLINE_INTERVAL_3DAY = '3d' + KLINE_INTERVAL_1WEEK = '1w' + KLINE_INTERVAL_1MONTH = '1M' + + SIDE_BUY = 'BUY' + SIDE_SELL = 'SELL' + + ORDER_TYPE_LIMIT = 'LIMIT' + ORDER_TYPE_MARKET = 'MARKET' + ORDER_TYPE_STOP_LOSS = 'STOP_LOSS' + ORDER_TYPE_STOP_LOSS_LIMIT = 'STOP_LOSS_LIMIT' + ORDER_TYPE_TAKE_PROFIT = 'TAKE_PROFIT' + ORDER_TYPE_TAKE_PROFIT_LIMIT = 'TAKE_PROFIT_LIMIT' + ORDER_TYPE_LIMIT_MAKER = 'LIMIT_MAKER' + + FUTURE_ORDER_TYPE_LIMIT = 'LIMIT' + FUTURE_ORDER_TYPE_MARKET = 'MARKET' + FUTURE_ORDER_TYPE_STOP = 'STOP' + FUTURE_ORDER_TYPE_STOP_MARKET = 'STOP_MARKET' + FUTURE_ORDER_TYPE_TAKE_PROFIT = 'TAKE_PROFIT' + FUTURE_ORDER_TYPE_TAKE_PROFIT_MARKET = 'TAKE_PROFIT_MARKET' + FUTURE_ORDER_TYPE_LIMIT_MAKER = 'LIMIT_MAKER' + + TIME_IN_FORCE_GTC = 'GTC' # Good till cancelled + TIME_IN_FORCE_IOC = 'IOC' # Immediate or cancel + TIME_IN_FORCE_FOK = 'FOK' # Fill or kill + + ORDER_RESP_TYPE_ACK = 'ACK' + ORDER_RESP_TYPE_RESULT = 'RESULT' + ORDER_RESP_TYPE_FULL = 'FULL' + + # For accessing the data returned by Client.aggregate_trades(). + AGG_ID = 'a' + AGG_PRICE = 'p' + AGG_QUANTITY = 'q' + AGG_FIRST_TRADE_ID = 'f' + AGG_LAST_TRADE_ID = 'l' + AGG_TIME = 'T' + AGG_BUYER_MAKES = 'm' + AGG_BEST_MATCH = 'M' + + # new asset transfer api enum + SPOT_TO_FIAT = "MAIN_C2C" + SPOT_TO_USDT_FUTURE = "MAIN_UMFUTURE" + SPOT_TO_COIN_FUTURE = "MAIN_CMFUTURE" + SPOT_TO_MARGIN_CROSS = "MAIN_MARGIN" + SPOT_TO_MINING = "MAIN_MINING" + FIAT_TO_SPOT = "C2C_MAIN" + FIAT_TO_USDT_FUTURE = "C2C_UMFUTURE" + FIAT_TO_MINING = "C2C_MINING" + USDT_FUTURE_TO_SPOT = "UMFUTURE_MAIN" + USDT_FUTURE_TO_FIAT = "UMFUTURE_C2C" + USDT_FUTURE_TO_MARGIN_CROSS = "UMFUTURE_MARGIN" + COIN_FUTURE_TO_SPOT = "CMFUTURE_MAIN" + MARGIN_CROSS_TO_SPOT = "MARGIN_MAIN" + MARGIN_CROSS_TO_USDT_FUTURE = "MARGIN_UMFUTURE" + MINING_TO_SPOT = "MINING_MAIN" + MINING_TO_USDT_FUTURE = "MINING_UMFUTURE" + MINING_TO_FIAT = "MINING_C2C" + + def __init__( + self, api_key: Optional[str] = None, api_secret: Optional[str] = None, + requests_params: Dict[str, str] = None, tld: str = 'com', + testnet: bool = False + ): + """Binance API Client constructor + + :param api_key: Api Key + :type api_key: str. + :param api_secret: Api Secret + :type api_secret: str. + :param requests_params: optional - Dictionary of requests params to use for all calls + :type requests_params: dict. + :param testnet: Use testnet environment - only available for vanilla options at the moment + :type testnet: bool + + """ + + self.tld = tld + self.API_URL = self.API_URL.format(tld) + self.MARGIN_API_URL = self.MARGIN_API_URL.format(tld) + self.WEBSITE_URL = self.WEBSITE_URL.format(tld) + self.FUTURES_URL = self.FUTURES_URL.format(tld) + self.FUTURES_DATA_URL = self.FUTURES_DATA_URL.format(tld) + self.FUTURES_COIN_URL = self.FUTURES_COIN_URL.format(tld) + self.FUTURES_COIN_DATA_URL = self.FUTURES_COIN_DATA_URL.format(tld) + self.OPTIONS_URL = self.OPTIONS_URL.format(tld) + self.OPTIONS_TESTNET_URL = self.OPTIONS_TESTNET_URL.format(tld) + + self.API_KEY = api_key + self.API_SECRET = api_secret + self.session = self._init_session() + self._requests_params = requests_params + self.response = None + self.testnet = testnet + self.timestamp_offset = 0 + + def _get_headers(self) -> Dict: + headers = { + 'Accept': 'application/json', + 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36', # noqa + } + if self.API_KEY: + assert self.API_KEY + headers['X-MBX-APIKEY'] = self.API_KEY + return headers + + def _init_session(self): + raise NotImplementedError + + def _create_api_uri(self, path: str, signed: bool = True, version: str = PUBLIC_API_VERSION) -> str: + url = self.API_URL + if self.testnet: + url = self.API_TESTNET_URL + v = self.PRIVATE_API_VERSION if signed else version + return url + '/' + v + '/' + path + + def _create_margin_api_uri(self, path: str, version: str = MARGIN_API_VERSION) -> str: + return self.MARGIN_API_URL + '/' + version + '/' + path + + def _create_website_uri(self, path: str) -> str: + return self.WEBSITE_URL + '/' + path + + def _create_futures_api_uri(self, path: str) -> str: + url = self.FUTURES_URL + if self.testnet: + url = self.FUTURES_TESTNET_URL + return url + '/' + self.FUTURES_API_VERSION + '/' + path + + def _create_futures_data_api_uri(self, path: str) -> str: + url = self.FUTURES_DATA_URL + if self.testnet: + url = self.FUTURES_DATA_TESTNET_URL + return url + '/' + path + + def _create_futures_coin_api_url(self, path: str, version=1) -> str: + url = self.FUTURES_COIN_URL + if self.testnet: + url = self.FUTURES_COIN_TESTNET_URL + options = {1: self.FUTURES_API_VERSION, 2: self.FUTURES_API_VERSION2} + return url + "/" + options[version] + "/" + path + + def _create_futures_coin_data_api_url(self, path: str, version=1) -> str: + url = self.FUTURES_COIN_DATA_URL + if self.testnet: + url = self.FUTURES_COIN_DATA_TESTNET_URL + return url + "/" + path + + def _create_options_api_uri(self, path: str) -> str: + url = self.OPTIONS_URL + if self.testnet: + url = self.OPTIONS_TESTNET_URL + return url + '/' + self.OPTIONS_API_VERSION + '/' + path + + def _generate_signature(self, data: Dict) -> str: + + ordered_data = self._order_params(data) + query_string = '&'.join([f"{d[0]}={d[1]}" for d in ordered_data]) + m = hmac.new(self.API_SECRET.encode('utf-8'), query_string.encode('utf-8'), hashlib.sha256) + return m.hexdigest() + + @staticmethod + def _order_params(data: Dict) -> List[Tuple[str, str]]: + """Convert params to list with signature as last element + + :param data: + :return: + + """ + data = dict(filter(lambda el: el[1] is not None, data.items())) + has_signature = False + params = [] + for key, value in data.items(): + if key == 'signature': + has_signature = True + else: + params.append((key, str(value))) + # sort parameters by key + params.sort(key=itemgetter(0)) + if has_signature: + params.append(('signature', data['signature'])) + return params + + def _get_request_kwargs(self, method, signed: bool, force_params: bool = False, **kwargs) -> Dict: + + # set default requests timeout + kwargs['timeout'] = self.REQUEST_TIMEOUT + + # add our global requests params + if self._requests_params: + kwargs.update(self._requests_params) + + data = kwargs.get('data', None) + if data and isinstance(data, dict): + kwargs['data'] = data + + # find any requests params passed and apply them + if 'requests_params' in kwargs['data']: + # merge requests params into kwargs + kwargs.update(kwargs['data']['requests_params']) + del(kwargs['data']['requests_params']) + + if signed: + # generate signature + kwargs['data']['timestamp'] = int(time.time() * 1000 + self.timestamp_offset) + kwargs['data']['signature'] = self._generate_signature(kwargs['data']) + + # sort get and post params to match signature order + if data: + # sort post params and remove any arguments with values of None + kwargs['data'] = self._order_params(kwargs['data']) + # Remove any arguments with values of None. + null_args = [i for i, (key, value) in enumerate(kwargs['data']) if value is None] + for i in reversed(null_args): + del kwargs['data'][i] + + # if get request assign data array to params value for requests lib + if data and (method == 'get' or force_params): + kwargs['params'] = '&'.join('%s=%s' % (data[0], data[1]) for data in kwargs['data']) + del(kwargs['data']) + + return kwargs + + +class Client(BaseClient): + + def __init__( + self, api_key: Optional[str] = None, api_secret: Optional[str] = None, + requests_params: Dict[str, str] = None, tld: str = 'com', + testnet: bool = False + ): + + super().__init__(api_key, api_secret, requests_params, tld, testnet) + + # init DNS and SSL cert + self.ping() + + def _init_session(self) -> requests.Session: + + headers = self._get_headers() + + session = requests.session() + session.headers.update(headers) + return session + + def _request(self, method, uri: str, signed: bool, force_params: bool = False, **kwargs): + + kwargs = self._get_request_kwargs(method, signed, force_params, **kwargs) + + self.response = getattr(self.session, method)(uri, **kwargs) + return self._handle_response(self.response) + + @staticmethod + def _handle_response(response: requests.Response): + """Internal helper for handling API responses from the Binance server. + Raises the appropriate exceptions when necessary; otherwise, returns the + response. + """ + if not (200 <= response.status_code < 300): + raise BinanceAPIException(response, response.status_code, response.text) + try: + return response.json() + except ValueError: + raise BinanceRequestException('Invalid Response: %s' % response.text) + + def _request_api( + self, method, path: str, signed: bool = False, version=BaseClient.PUBLIC_API_VERSION, **kwargs + ): + uri = self._create_api_uri(path, signed, version) + return self._request(method, uri, signed, **kwargs) + + def _request_futures_api(self, method, path, signed=False, **kwargs) -> Dict: + uri = self._create_futures_api_uri(path) + + return self._request(method, uri, signed, True, **kwargs) + + def _request_futures_data_api(self, method, path, signed=False, **kwargs) -> Dict: + uri = self._create_futures_data_api_uri(path) + + return self._request(method, uri, signed, True, **kwargs) + + def _request_futures_coin_api(self, method, path, signed=False, version=1, **kwargs) -> Dict: + uri = self._create_futures_coin_api_url(path, version=version) + + return self._request(method, uri, signed, True, **kwargs) + + def _request_futures_coin_data_api(self, method, path, signed=False, version=1, **kwargs) -> Dict: + uri = self._create_futures_coin_data_api_url(path, version=version) + + return self._request(method, uri, signed, True, **kwargs) + + def _request_options_api(self, method, path, signed=False, **kwargs) -> Dict: + uri = self._create_options_api_uri(path) + + return self._request(method, uri, signed, True, **kwargs) + + def _request_margin_api(self, method, path, signed=False, **kwargs) -> Dict: + uri = self._create_margin_api_uri(path) + + return self._request(method, uri, signed, **kwargs) + + def _request_website(self, method, path, signed=False, **kwargs) -> Dict: + uri = self._create_website_uri(path) + return self._request(method, uri, signed, **kwargs) + + def _get(self, path, signed=False, version=BaseClient.PUBLIC_API_VERSION, **kwargs): + return self._request_api('get', path, signed, version, **kwargs) + + def _post(self, path, signed=False, version=BaseClient.PUBLIC_API_VERSION, **kwargs) -> Dict: + return self._request_api('post', path, signed, version, **kwargs) + + def _put(self, path, signed=False, version=BaseClient.PUBLIC_API_VERSION, **kwargs) -> Dict: + return self._request_api('put', path, signed, version, **kwargs) + + def _delete(self, path, signed=False, version=BaseClient.PUBLIC_API_VERSION, **kwargs) -> Dict: + return self._request_api('delete', path, signed, version, **kwargs) + + # Exchange Endpoints + + def get_products(self) -> Dict: + """Return list of products currently listed on Binance + + Use get_exchange_info() call instead + + :returns: list - List of product dictionaries + + :raises: BinanceRequestException, BinanceAPIException + + """ + products = self._request_website('get', 'exchange-api/v1/public/asset-service/product/get-products') + return products + + def get_exchange_info(self) -> Dict: + """Return rate limits and list of symbols + + :returns: list - List of product dictionaries + + .. code-block:: python + + { + "timezone": "UTC", + "serverTime": 1508631584636, + "rateLimits": [ + { + "rateLimitType": "REQUESTS", + "interval": "MINUTE", + "limit": 1200 + }, + { + "rateLimitType": "ORDERS", + "interval": "SECOND", + "limit": 10 + }, + { + "rateLimitType": "ORDERS", + "interval": "DAY", + "limit": 100000 + } + ], + "exchangeFilters": [], + "symbols": [ + { + "symbol": "ETHBTC", + "status": "TRADING", + "baseAsset": "ETH", + "baseAssetPrecision": 8, + "quoteAsset": "BTC", + "quotePrecision": 8, + "orderTypes": ["LIMIT", "MARKET"], + "icebergAllowed": false, + "filters": [ + { + "filterType": "PRICE_FILTER", + "minPrice": "0.00000100", + "maxPrice": "100000.00000000", + "tickSize": "0.00000100" + }, { + "filterType": "LOT_SIZE", + "minQty": "0.00100000", + "maxQty": "100000.00000000", + "stepSize": "0.00100000" + }, { + "filterType": "MIN_NOTIONAL", + "minNotional": "0.00100000" + } + ] + } + ] + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + + return self._get('exchangeInfo', version=self.PRIVATE_API_VERSION) + + def get_symbol_info(self, symbol) -> Optional[Dict]: + """Return information about a symbol + + :param symbol: required e.g BNBBTC + :type symbol: str + + :returns: Dict if found, None if not + + .. code-block:: python + + { + "symbol": "ETHBTC", + "status": "TRADING", + "baseAsset": "ETH", + "baseAssetPrecision": 8, + "quoteAsset": "BTC", + "quotePrecision": 8, + "orderTypes": ["LIMIT", "MARKET"], + "icebergAllowed": false, + "filters": [ + { + "filterType": "PRICE_FILTER", + "minPrice": "0.00000100", + "maxPrice": "100000.00000000", + "tickSize": "0.00000100" + }, { + "filterType": "LOT_SIZE", + "minQty": "0.00100000", + "maxQty": "100000.00000000", + "stepSize": "0.00100000" + }, { + "filterType": "MIN_NOTIONAL", + "minNotional": "0.00100000" + } + ] + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + + res = self.get_exchange_info() + + for item in res['symbols']: + if item['symbol'] == symbol.upper(): + return item + + return None + + # General Endpoints + + def ping(self) -> Dict: + """Test connectivity to the Rest API. + + https://binance-docs.github.io/apidocs/spot/en/#test-connectivity + + :returns: Empty array + + .. code-block:: python + + {} + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._get('ping', version=self.PRIVATE_API_VERSION) + + def get_server_time(self) -> Dict: + """Test connectivity to the Rest API and get the current server time. + + https://binance-docs.github.io/apidocs/spot/en/#check-server-time + + :returns: Current server time + + .. code-block:: python + + { + "serverTime": 1499827319559 + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._get('time', version=self.PRIVATE_API_VERSION) + + # Market Data Endpoints + + def get_all_tickers(self) -> List[Dict[str, str]]: + """Latest price for all symbols. + + https://binance-docs.github.io/apidocs/spot/en/#symbol-price-ticker + + :returns: List of market tickers + + .. code-block:: python + + [ + { + "symbol": "LTCBTC", + "price": "4.00000200" + }, + { + "symbol": "ETHBTC", + "price": "0.07946600" + } + ] + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._get('ticker/price', version=self.PRIVATE_API_VERSION) + + def get_orderbook_tickers(self) -> Dict: + """Best price/qty on the order book for all symbols. + + https://binance-docs.github.io/apidocs/spot/en/#symbol-order-book-ticker + + :param symbol: optional + :type symbol: str + + :returns: List of order book market entries + + .. code-block:: python + + [ + { + "symbol": "LTCBTC", + "bidPrice": "4.00000000", + "bidQty": "431.00000000", + "askPrice": "4.00000200", + "askQty": "9.00000000" + }, + { + "symbol": "ETHBTC", + "bidPrice": "0.07946700", + "bidQty": "9.00000000", + "askPrice": "100000.00000000", + "askQty": "1000.00000000" + } + ] + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._get('ticker/bookTicker', version=self.PRIVATE_API_VERSION) + + def get_order_book(self, **params) -> Dict: + """Get the Order Book for the market + + https://binance-docs.github.io/apidocs/spot/en/#order-book + + :param symbol: required + :type symbol: str + :param limit: Default 100; max 1000 + :type limit: int + + :returns: API response + + .. code-block:: python + + { + "lastUpdateId": 1027024, + "bids": [ + [ + "4.00000000", # PRICE + "431.00000000", # QTY + [] # Can be ignored + ] + ], + "asks": [ + [ + "4.00000200", + "12.00000000", + [] + ] + ] + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._get('depth', data=params, version=self.PRIVATE_API_VERSION) + + def get_recent_trades(self, **params) -> Dict: + """Get recent trades (up to last 500). + + https://binance-docs.github.io/apidocs/spot/en/#recent-trades-list + + :param symbol: required + :type symbol: str + :param limit: Default 500; max 1000. + :type limit: int + + :returns: API response + + .. code-block:: python + + [ + { + "id": 28457, + "price": "4.00000100", + "qty": "12.00000000", + "time": 1499865549590, + "isBuyerMaker": true, + "isBestMatch": true + } + ] + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._get('trades', data=params) + + def get_historical_trades(self, **params) -> Dict: + """Get older trades. + + https://binance-docs.github.io/apidocs/spot/en/#old-trade-lookup + + :param symbol: required + :type symbol: str + :param limit: Default 500; max 1000. + :type limit: int + :param fromId: TradeId to fetch from. Default gets most recent trades. + :type fromId: str + + :returns: API response + + .. code-block:: python + + [ + { + "id": 28457, + "price": "4.00000100", + "qty": "12.00000000", + "time": 1499865549590, + "isBuyerMaker": true, + "isBestMatch": true + } + ] + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._get('historicalTrades', data=params, version=self.PRIVATE_API_VERSION) + + def get_aggregate_trades(self, **params) -> Dict: + """Get compressed, aggregate trades. Trades that fill at the time, + from the same order, with the same price will have the quantity aggregated. + + https://binance-docs.github.io/apidocs/spot/en/#compressed-aggregate-trades-list + + :param symbol: required + :type symbol: str + :param fromId: ID to get aggregate trades from INCLUSIVE. + :type fromId: str + :param startTime: Timestamp in ms to get aggregate trades from INCLUSIVE. + :type startTime: int + :param endTime: Timestamp in ms to get aggregate trades until INCLUSIVE. + :type endTime: int + :param limit: Default 500; max 1000. + :type limit: int + + :returns: API response + + .. code-block:: python + + [ + { + "a": 26129, # Aggregate tradeId + "p": "0.01633102", # Price + "q": "4.70443515", # Quantity + "f": 27781, # First tradeId + "l": 27781, # Last tradeId + "T": 1498793709153, # Timestamp + "m": true, # Was the buyer the maker? + "M": true # Was the trade the best price match? + } + ] + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._get('aggTrades', data=params, version=self.PRIVATE_API_VERSION) + + def aggregate_trade_iter(self, symbol: str, start_str=None, last_id=None): + """Iterate over aggregate trade data from (start_time or last_id) to + the end of the history so far. + + If start_time is specified, start with the first trade after + start_time. Meant to initialise a local cache of trade data. + + If last_id is specified, start with the trade after it. This is meant + for updating a pre-existing local trade data cache. + + Only allows start_str or last_id—not both. Not guaranteed to work + right if you're running more than one of these simultaneously. You + will probably hit your rate limit. + + See dateparser docs for valid start and end string formats http://dateparser.readthedocs.io/en/latest/ + + If using offset strings for dates add "UTC" to date string e.g. "now UTC", "11 hours ago UTC" + + :param symbol: Symbol string e.g. ETHBTC + :type symbol: str + :param start_str: Start date string in UTC format or timestamp in milliseconds. The iterator will + return the first trade occurring later than this time. + :type start_str: str|int + :param last_id: aggregate trade ID of the last known aggregate trade. + Not a regular trade ID. See https://binance-docs.github.io/apidocs/spot/en/#compressed-aggregate-trades-list + + :returns: an iterator of JSON objects, one per trade. The format of + each object is identical to Client.aggregate_trades(). + + :type last_id: int + """ + if start_str is not None and last_id is not None: + raise ValueError( + 'start_time and last_id may not be simultaneously specified.') + + # If there's no last_id, get one. + if last_id is None: + # Without a last_id, we actually need the first trade. Normally, + # we'd get rid of it. See the next loop. + if start_str is None: + trades = self.get_aggregate_trades(symbol=symbol, fromId=0) + else: + # The difference between startTime and endTime should be less + # or equal than an hour and the result set should contain at + # least one trade. + start_ts = convert_ts_str(start_str) + # If the resulting set is empty (i.e. no trades in that interval) + # then we just move forward hour by hour until we find at least one + # trade or reach present moment + while True: + end_ts = start_ts + (60 * 60 * 1000) + trades = self.get_aggregate_trades( + symbol=symbol, + startTime=start_ts, + endTime=end_ts) + if len(trades) > 0: + break + # If we reach present moment and find no trades then there is + # nothing to iterate, so we're done + if end_ts > int(time.time() * 1000): + return + start_ts = end_ts + for t in trades: + yield t + last_id = trades[-1][self.AGG_ID] + + while True: + # There is no need to wait between queries, to avoid hitting the + # rate limit. We're using blocking IO, and as long as we're the + # only thread running calls like this, Binance will automatically + # add the right delay time on their end, forcing us to wait for + # data. That really simplifies this function's job. Binance is + # fucking awesome. + trades = self.get_aggregate_trades(symbol=symbol, fromId=last_id) + # fromId=n returns a set starting with id n, but we already have + # that one. So get rid of the first item in the result set. + trades = trades[1:] + if len(trades) == 0: + return + for t in trades: + yield t + last_id = trades[-1][self.AGG_ID] + + def get_klines(self, **params) -> Dict: + """Kline/candlestick bars for a symbol. Klines are uniquely identified by their open time. + + https://binance-docs.github.io/apidocs/spot/en/#kline-candlestick-data + + :param symbol: required + :type symbol: str + :param interval: - + :type interval: str + :param limit: - Default 500; max 1000. + :type limit: int + :param startTime: + :type startTime: int + :param endTime: + :type endTime: int + + :returns: API response + + .. code-block:: python + + [ + [ + 1499040000000, # Open time + "0.01634790", # Open + "0.80000000", # High + "0.01575800", # Low + "0.01577100", # Close + "148976.11427815", # Volume + 1499644799999, # Close time + "2434.19055334", # Quote asset volume + 308, # Number of trades + "1756.87402397", # Taker buy base asset volume + "28.46694368", # Taker buy quote asset volume + "17928899.62484339" # Can be ignored + ] + ] + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._get('klines', data=params, version=self.PRIVATE_API_VERSION) + + def _klines(self, klines_type: HistoricalKlinesType = HistoricalKlinesType.SPOT, **params) -> Dict: + """Get klines of spot (get_klines) or futures (futures_klines) endpoints. + + :param klines_type: Historical klines type: SPOT or FUTURES + :type klines_type: HistoricalKlinesType + + :return: klines, see get_klines + + """ + if 'endTime' in params and not params['endTime']: + del params['endTime'] + + if HistoricalKlinesType.SPOT == klines_type: + return self.get_klines(**params) + elif HistoricalKlinesType.FUTURES == klines_type: + return self.futures_klines(**params) + else: + raise NotImplementedException(klines_type) + + def _get_earliest_valid_timestamp(self, symbol, interval, klines_type: HistoricalKlinesType = HistoricalKlinesType.SPOT): + """Get earliest valid open timestamp from Binance + + :param symbol: Name of symbol pair e.g BNBBTC + :type symbol: str + :param interval: Binance Kline interval + :type interval: str + :param klines_type: Historical klines type: SPOT or FUTURES + :type klines_type: HistoricalKlinesType + + :return: first valid timestamp + + """ + kline = self._klines( + klines_type=klines_type, + symbol=symbol, + interval=interval, + limit=1, + startTime=0, + endTime=int(time.time() * 1000) + ) + return kline[0][0] + + def get_historical_klines(self, symbol, interval, start_str, end_str=None, limit=500, + klines_type: HistoricalKlinesType = HistoricalKlinesType.SPOT): + """Get Historical Klines from Binance + + :param symbol: Name of symbol pair e.g BNBBTC + :type symbol: str + :param interval: Binance Kline interval + :type interval: str + :param start_str: Start date string in UTC format or timestamp in milliseconds + :type start_str: str|int + :param end_str: optional - end date string in UTC format or timestamp in milliseconds (default will fetch everything up to now) + :type end_str: str|int + :param limit: Default 500; max 1000. + :type limit: int + :param klines_type: Historical klines type: SPOT or FUTURES + :type klines_type: HistoricalKlinesType + + :return: list of OHLCV values + + """ + return self._historical_klines(symbol, interval, start_str, end_str=end_str, limit=limit, klines_type=klines_type) + + def _historical_klines(self, symbol, interval, start_str, end_str=None, limit=500, + klines_type: HistoricalKlinesType = HistoricalKlinesType.SPOT): + """Get Historical Klines from Binance (spot or futures) + + See dateparser docs for valid start and end string formats http://dateparser.readthedocs.io/en/latest/ + + If using offset strings for dates add "UTC" to date string e.g. "now UTC", "11 hours ago UTC" + + :param symbol: Name of symbol pair e.g BNBBTC + :type symbol: str + :param interval: Binance Kline interval + :type interval: str + :param start_str: Start date string in UTC format or timestamp in milliseconds + :type start_str: str|int + :param end_str: optional - end date string in UTC format or timestamp in milliseconds (default will fetch everything up to now) + :type end_str: None|str|int + :param limit: Default 500; max 1000. + :type limit: int + :param klines_type: Historical klines type: SPOT or FUTURES + :type klines_type: HistoricalKlinesType + + :return: list of OHLCV values + + """ + # init our list + output_data = [] + + # convert interval to useful value in seconds + timeframe = interval_to_milliseconds(interval) + + start_ts = convert_ts_str(start_str) + + # establish first available start timestamp + first_valid_ts = self._get_earliest_valid_timestamp(symbol, interval, klines_type) + start_ts = max(start_ts, first_valid_ts) + + # if an end time was passed convert it + end_ts = convert_ts_str(end_str) + + idx = 0 + while True: + # fetch the klines from start_ts up to max 500 entries or the end_ts if set + temp_data = self._klines( + klines_type=klines_type, + symbol=symbol, + interval=interval, + limit=limit, + startTime=start_ts, + endTime=end_ts + ) + + # handle the case where exactly the limit amount of data was returned last loop + if not len(temp_data): + break + + # append this loops data to our output data + output_data += temp_data + + # set our start timestamp using the last value in the array + start_ts = temp_data[-1][0] + + idx += 1 + # check if we received less than the required limit and exit the loop + if len(temp_data) < limit: + # exit the while loop + break + + # increment next call by our timeframe + start_ts += timeframe + + # sleep after every 3rd call to be kind to the API + if idx % 3 == 0: + time.sleep(1) + + return output_data + + def get_historical_klines_generator(self, symbol, interval, start_str, end_str=None, limit=500, + klines_type:HistoricalKlinesType=HistoricalKlinesType.SPOT): + """Get Historical Klines generator from Binance + + :param symbol: Name of symbol pair e.g BNBBTC + :type symbol: str + :param interval: Binance Kline interval + :type interval: str + :param start_str: Start date string in UTC format or timestamp in milliseconds + :type start_str: str|int + :param end_str: optional - end date string in UTC format or timestamp in milliseconds (default will fetch everything up to now) + :type end_str: str|int + :param limit: amount of candles to return per request + :type limit: int + :param klines_type: Historical klines type: SPOT or FUTURES + :type klines_type: HistoricalKlinesType + + :return: generator of OHLCV values + + """ + + return self._historical_klines_generator(symbol, interval, start_str, end_str, limit, klines_type=klines_type) + + def _historical_klines_generator(self, symbol, interval, start_str, end_str, limit, + klines_type:HistoricalKlinesType=HistoricalKlinesType.SPOT): + """Get Historical Klines generator from Binance (spot or futures) + + See dateparser docs for valid start and end string formats http://dateparser.readthedocs.io/en/latest/ + + If using offset strings for dates add "UTC" to date string e.g. "now UTC", "11 hours ago UTC" + + :param symbol: Name of symbol pair e.g BNBBTC + :type symbol: str + :param interval: Binance Kline interval + :type interval: str + :param start_str: Start date string in UTC format or timestamp in milliseconds + :type start_str: str|int + :param end_str: optional - end date string in UTC format or timestamp in milliseconds (default will fetch everything up to now) + :type end_str: str|int + :param limit: amount of candles to return per request + :type limit: int + :param klines_type: Historical klines type: SPOT or FUTURES + :type klines_type: HistoricalKlinesType + + :return: generator of OHLCV values + + """ + + # convert interval to useful value in seconds + timeframe = interval_to_milliseconds(interval) + + # convert our date strings to milliseconds + start_ts = convert_ts_str(start_str) + + # establish first available start timestamp + first_valid_ts = self._get_earliest_valid_timestamp(symbol, interval, klines_type) + start_ts = max(start_ts, first_valid_ts) + + # if an end time was passed convert it + end_ts = convert_ts_str(end_str) + + idx = 0 + while True: + # fetch the klines from start_ts up to max 1000 entries or the end_ts if set + output_data = self._klines( + klines_type=klines_type, + symbol=symbol, + interval=interval, + limit=limit, + startTime=start_ts, + endTime=end_ts + ) + + # handle the case where exactly the limit amount of data was returned last loop + if not len(output_data): + break + + # yield data + for o in output_data: + yield o + + # set our start timestamp using the last value in the array + start_ts = output_data[-1][0] + + idx += 1 + # check if we received less than the required limit and exit the loop + if len(output_data) < limit: + # exit the while loop + break + + # increment next call by our timeframe + start_ts += timeframe + + # sleep after every 3rd call to be kind to the API + if idx % 3 == 0: + time.sleep(1) + + def get_avg_price(self, **params): + """Current average price for a symbol. + + https://binance-docs.github.io/apidocs/spot/en/#current-average-price + + :param symbol: + :type symbol: str + + :returns: API response + + .. code-block:: python + + { + "mins": 5, + "price": "9.35751834" + } + """ + return self._get('avgPrice', data=params, version=self.PRIVATE_API_VERSION) + + def get_ticker(self, **params): + """24 hour price change statistics. + + https://binance-docs.github.io/apidocs/spot/en/#24hr-ticker-price-change-statistics + + :param symbol: + :type symbol: str + + :returns: API response + + .. code-block:: python + + { + "priceChange": "-94.99999800", + "priceChangePercent": "-95.960", + "weightedAvgPrice": "0.29628482", + "prevClosePrice": "0.10002000", + "lastPrice": "4.00000200", + "bidPrice": "4.00000000", + "askPrice": "4.00000200", + "openPrice": "99.00000000", + "highPrice": "100.00000000", + "lowPrice": "0.10000000", + "volume": "8913.30000000", + "openTime": 1499783499040, + "closeTime": 1499869899040, + "fristId": 28385, # First tradeId + "lastId": 28460, # Last tradeId + "count": 76 # Trade count + } + + OR + + .. code-block:: python + + [ + { + "priceChange": "-94.99999800", + "priceChangePercent": "-95.960", + "weightedAvgPrice": "0.29628482", + "prevClosePrice": "0.10002000", + "lastPrice": "4.00000200", + "bidPrice": "4.00000000", + "askPrice": "4.00000200", + "openPrice": "99.00000000", + "highPrice": "100.00000000", + "lowPrice": "0.10000000", + "volume": "8913.30000000", + "openTime": 1499783499040, + "closeTime": 1499869899040, + "fristId": 28385, # First tradeId + "lastId": 28460, # Last tradeId + "count": 76 # Trade count + } + ] + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._get('ticker/24hr', data=params, version=self.PRIVATE_API_VERSION) + + def get_symbol_ticker(self, **params): + """Latest price for a symbol or symbols. + + https://binance-docs.github.io/apidocs/spot/en/#symbol-price-ticker + + :param symbol: + :type symbol: str + + :returns: API response + + .. code-block:: python + + { + "symbol": "LTCBTC", + "price": "4.00000200" + } + + OR + + .. code-block:: python + + [ + { + "symbol": "LTCBTC", + "price": "4.00000200" + }, + { + "symbol": "ETHBTC", + "price": "0.07946600" + } + ] + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._get('ticker/price', data=params, version=self.PRIVATE_API_VERSION) + + def get_orderbook_ticker(self, **params): + """Latest price for a symbol or symbols. + + https://binance-docs.github.io/apidocs/spot/en/#symbol-order-book-ticker + + :param symbol: + :type symbol: str + + :returns: API response + + .. code-block:: python + + { + "symbol": "LTCBTC", + "bidPrice": "4.00000000", + "bidQty": "431.00000000", + "askPrice": "4.00000200", + "askQty": "9.00000000" + } + + OR + + .. code-block:: python + + [ + { + "symbol": "LTCBTC", + "bidPrice": "4.00000000", + "bidQty": "431.00000000", + "askPrice": "4.00000200", + "askQty": "9.00000000" + }, + { + "symbol": "ETHBTC", + "bidPrice": "0.07946700", + "bidQty": "9.00000000", + "askPrice": "100000.00000000", + "askQty": "1000.00000000" + } + ] + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._get('ticker/bookTicker', data=params, version=self.PRIVATE_API_VERSION) + + # Account Endpoints + + def create_order(self, **params): + """Send in a new order + + Any order with an icebergQty MUST have timeInForce set to GTC. + + https://binance-docs.github.io/apidocs/spot/en/#new-order-trade + + :param symbol: required + :type symbol: str + :param side: required + :type side: str + :param type: required + :type type: str + :param timeInForce: required if limit order + :type timeInForce: str + :param quantity: required + :type quantity: decimal + :param quoteOrderQty: amount the user wants to spend (when buying) or receive (when selling) + of the quote asset, applicable to MARKET orders + :type quoteOrderQty: decimal + :param price: required + :type price: str + :param newClientOrderId: A unique id for the order. Automatically generated if not sent. + :type newClientOrderId: str + :param icebergQty: Used with LIMIT, STOP_LOSS_LIMIT, and TAKE_PROFIT_LIMIT to create an iceberg order. + :type icebergQty: decimal + :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; default: RESULT. + :type newOrderRespType: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + Response ACK: + + .. code-block:: python + + { + "symbol":"LTCBTC", + "orderId": 1, + "clientOrderId": "myOrder1" # Will be newClientOrderId + "transactTime": 1499827319559 + } + + Response RESULT: + + .. code-block:: python + + { + "symbol": "BTCUSDT", + "orderId": 28, + "clientOrderId": "6gCrw2kRUAF9CvJDGP16IP", + "transactTime": 1507725176595, + "price": "0.00000000", + "origQty": "10.00000000", + "executedQty": "10.00000000", + "cummulativeQuoteQty": "10.00000000", + "status": "FILLED", + "timeInForce": "GTC", + "type": "MARKET", + "side": "SELL" + } + + Response FULL: + + .. code-block:: python + + { + "symbol": "BTCUSDT", + "orderId": 28, + "clientOrderId": "6gCrw2kRUAF9CvJDGP16IP", + "transactTime": 1507725176595, + "price": "0.00000000", + "origQty": "10.00000000", + "executedQty": "10.00000000", + "cummulativeQuoteQty": "10.00000000", + "status": "FILLED", + "timeInForce": "GTC", + "type": "MARKET", + "side": "SELL", + "fills": [ + { + "price": "4000.00000000", + "qty": "1.00000000", + "commission": "4.00000000", + "commissionAsset": "USDT" + }, + { + "price": "3999.00000000", + "qty": "5.00000000", + "commission": "19.99500000", + "commissionAsset": "USDT" + }, + { + "price": "3998.00000000", + "qty": "2.00000000", + "commission": "7.99600000", + "commissionAsset": "USDT" + }, + { + "price": "3997.00000000", + "qty": "1.00000000", + "commission": "3.99700000", + "commissionAsset": "USDT" + }, + { + "price": "3995.00000000", + "qty": "1.00000000", + "commission": "3.99500000", + "commissionAsset": "USDT" + } + ] + } + + :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, BinanceOrderInactiveSymbolException + + """ + return self._post('order', True, data=params) + + def order_limit(self, timeInForce=BaseClient.TIME_IN_FORCE_GTC, **params): + """Send in a new limit order + + Any order with an icebergQty MUST have timeInForce set to GTC. + + :param symbol: required + :type symbol: str + :param side: required + :type side: str + :param quantity: required + :type quantity: decimal + :param price: required + :type price: str + :param timeInForce: default Good till cancelled + :type timeInForce: str + :param newClientOrderId: A unique id for the order. Automatically generated if not sent. + :type newClientOrderId: str + :param icebergQty: Used with LIMIT, STOP_LOSS_LIMIT, and TAKE_PROFIT_LIMIT to create an iceberg order. + :type icebergQty: decimal + :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; default: RESULT. + :type newOrderRespType: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + See order endpoint for full response options + + :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, BinanceOrderInactiveSymbolException + + """ + params.update({ + 'type': self.ORDER_TYPE_LIMIT, + 'timeInForce': timeInForce + }) + return self.create_order(**params) + + def order_limit_buy(self, timeInForce=BaseClient.TIME_IN_FORCE_GTC, **params): + """Send in a new limit buy order + + Any order with an icebergQty MUST have timeInForce set to GTC. + + :param symbol: required + :type symbol: str + :param quantity: required + :type quantity: decimal + :param price: required + :type price: str + :param timeInForce: default Good till cancelled + :type timeInForce: str + :param newClientOrderId: A unique id for the order. Automatically generated if not sent. + :type newClientOrderId: str + :param stopPrice: Used with stop orders + :type stopPrice: decimal + :param icebergQty: Used with iceberg orders + :type icebergQty: decimal + :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; default: RESULT. + :type newOrderRespType: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + See order endpoint for full response options + + :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, BinanceOrderInactiveSymbolException + + """ + params.update({ + 'side': self.SIDE_BUY, + }) + return self.order_limit(timeInForce=timeInForce, **params) + + def order_limit_sell(self, timeInForce=BaseClient.TIME_IN_FORCE_GTC, **params): + """Send in a new limit sell order + + :param symbol: required + :type symbol: str + :param quantity: required + :type quantity: decimal + :param price: required + :type price: str + :param timeInForce: default Good till cancelled + :type timeInForce: str + :param newClientOrderId: A unique id for the order. Automatically generated if not sent. + :type newClientOrderId: str + :param stopPrice: Used with stop orders + :type stopPrice: decimal + :param icebergQty: Used with iceberg orders + :type icebergQty: decimal + :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; default: RESULT. + :type newOrderRespType: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + See order endpoint for full response options + + :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, BinanceOrderInactiveSymbolException + + """ + params.update({ + 'side': self.SIDE_SELL + }) + return self.order_limit(timeInForce=timeInForce, **params) + + def order_market(self, **params): + """Send in a new market order + + :param symbol: required + :type symbol: str + :param side: required + :type side: str + :param quantity: required + :type quantity: decimal + :param quoteOrderQty: amount the user wants to spend (when buying) or receive (when selling) + of the quote asset + :type quoteOrderQty: decimal + :param newClientOrderId: A unique id for the order. Automatically generated if not sent. + :type newClientOrderId: str + :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; default: RESULT. + :type newOrderRespType: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + See order endpoint for full response options + + :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, BinanceOrderInactiveSymbolException + + """ + params.update({ + 'type': self.ORDER_TYPE_MARKET + }) + return self.create_order(**params) + + def order_market_buy(self, **params): + """Send in a new market buy order + + :param symbol: required + :type symbol: str + :param quantity: required + :type quantity: decimal + :param quoteOrderQty: the amount the user wants to spend of the quote asset + :type quoteOrderQty: decimal + :param newClientOrderId: A unique id for the order. Automatically generated if not sent. + :type newClientOrderId: str + :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; default: RESULT. + :type newOrderRespType: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + See order endpoint for full response options + + :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, BinanceOrderInactiveSymbolException + + """ + params.update({ + 'side': self.SIDE_BUY + }) + return self.order_market(**params) + + def order_market_sell(self, **params): + """Send in a new market sell order + + :param symbol: required + :type symbol: str + :param quantity: required + :type quantity: decimal + :param quoteOrderQty: the amount the user wants to receive of the quote asset + :type quoteOrderQty: decimal + :param newClientOrderId: A unique id for the order. Automatically generated if not sent. + :type newClientOrderId: str + :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; default: RESULT. + :type newOrderRespType: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + See order endpoint for full response options + + :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, BinanceOrderInactiveSymbolException + + """ + params.update({ + 'side': self.SIDE_SELL + }) + return self.order_market(**params) + + def create_oco_order(self, **params): + """Send in a new OCO order + + https://binance-docs.github.io/apidocs/spot/en/#new-oco-trade + + :param symbol: required + :type symbol: str + :param listClientOrderId: A unique id for the list order. Automatically generated if not sent. + :type listClientOrderId: str + :param side: required + :type side: str + :param quantity: required + :type quantity: decimal + :param limitClientOrderId: A unique id for the limit order. Automatically generated if not sent. + :type limitClientOrderId: str + :param price: required + :type price: str + :param limitIcebergQty: Used to make the LIMIT_MAKER leg an iceberg order. + :type limitIcebergQty: decimal + :param stopClientOrderId: A unique id for the stop order. Automatically generated if not sent. + :type stopClientOrderId: str + :param stopPrice: required + :type stopPrice: str + :param stopLimitPrice: If provided, stopLimitTimeInForce is required. + :type stopLimitPrice: str + :param stopIcebergQty: Used with STOP_LOSS_LIMIT leg to make an iceberg order. + :type stopIcebergQty: decimal + :param stopLimitTimeInForce: Valid values are GTC/FOK/IOC. + :type stopLimitTimeInForce: str + :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; default: RESULT. + :type newOrderRespType: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + Response ACK: + + .. code-block:: python + + { + } + + Response RESULT: + + .. code-block:: python + + { + } + + Response FULL: + + .. code-block:: python + + { + } + + :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, BinanceOrderInactiveSymbolException + + """ + return self._post('order/oco', True, data=params) + + def order_oco_buy(self, **params): + """Send in a new OCO buy order + + :param symbol: required + :type symbol: str + :param listClientOrderId: A unique id for the list order. Automatically generated if not sent. + :type listClientOrderId: str + :param quantity: required + :type quantity: decimal + :param limitClientOrderId: A unique id for the limit order. Automatically generated if not sent. + :type limitClientOrderId: str + :param price: required + :type price: str + :param limitIcebergQty: Used to make the LIMIT_MAKER leg an iceberg order. + :type limitIcebergQty: decimal + :param stopClientOrderId: A unique id for the stop order. Automatically generated if not sent. + :type stopClientOrderId: str + :param stopPrice: required + :type stopPrice: str + :param stopLimitPrice: If provided, stopLimitTimeInForce is required. + :type stopLimitPrice: str + :param stopIcebergQty: Used with STOP_LOSS_LIMIT leg to make an iceberg order. + :type stopIcebergQty: decimal + :param stopLimitTimeInForce: Valid values are GTC/FOK/IOC. + :type stopLimitTimeInForce: str + :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; default: RESULT. + :type newOrderRespType: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + See OCO order endpoint for full response options + + :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, BinanceOrderInactiveSymbolException + + """ + params.update({ + 'side': self.SIDE_BUY + }) + return self.create_oco_order(**params) + + def order_oco_sell(self, **params): + """Send in a new OCO sell order + + :param symbol: required + :type symbol: str + :param listClientOrderId: A unique id for the list order. Automatically generated if not sent. + :type listClientOrderId: str + :param quantity: required + :type quantity: decimal + :param limitClientOrderId: A unique id for the limit order. Automatically generated if not sent. + :type limitClientOrderId: str + :param price: required + :type price: str + :param limitIcebergQty: Used to make the LIMIT_MAKER leg an iceberg order. + :type limitIcebergQty: decimal + :param stopClientOrderId: A unique id for the stop order. Automatically generated if not sent. + :type stopClientOrderId: str + :param stopPrice: required + :type stopPrice: str + :param stopLimitPrice: If provided, stopLimitTimeInForce is required. + :type stopLimitPrice: str + :param stopIcebergQty: Used with STOP_LOSS_LIMIT leg to make an iceberg order. + :type stopIcebergQty: decimal + :param stopLimitTimeInForce: Valid values are GTC/FOK/IOC. + :type stopLimitTimeInForce: str + :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; default: RESULT. + :type newOrderRespType: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + See OCO order endpoint for full response options + + :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, BinanceOrderInactiveSymbolException + + """ + params.update({ + 'side': self.SIDE_SELL + }) + return self.create_oco_order(**params) + + def create_test_order(self, **params): + """Test new order creation and signature/recvWindow long. Creates and validates a new order but does not send it into the matching engine. + + https://binance-docs.github.io/apidocs/spot/en/#test-new-order-trade + + :param symbol: required + :type symbol: str + :param side: required + :type side: str + :param type: required + :type type: str + :param timeInForce: required if limit order + :type timeInForce: str + :param quantity: required + :type quantity: decimal + :param price: required + :type price: str + :param newClientOrderId: A unique id for the order. Automatically generated if not sent. + :type newClientOrderId: str + :param icebergQty: Used with iceberg orders + :type icebergQty: decimal + :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; default: RESULT. + :type newOrderRespType: str + :param recvWindow: The number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + {} + + :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, BinanceOrderInactiveSymbolException + + + """ + return self._post('order/test', True, data=params) + + def get_order(self, **params): + """Check an order's status. Either orderId or origClientOrderId must be sent. + + https://binance-docs.github.io/apidocs/spot/en/#query-order-user_data + + :param symbol: required + :type symbol: str + :param orderId: The unique order id + :type orderId: int + :param origClientOrderId: optional + :type origClientOrderId: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "symbol": "LTCBTC", + "orderId": 1, + "clientOrderId": "myOrder1", + "price": "0.1", + "origQty": "1.0", + "executedQty": "0.0", + "status": "NEW", + "timeInForce": "GTC", + "type": "LIMIT", + "side": "BUY", + "stopPrice": "0.0", + "icebergQty": "0.0", + "time": 1499827319559 + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._get('order', True, data=params) + + def get_all_orders(self, **params): + """Get all account orders; active, canceled, or filled. + + https://binance-docs.github.io/apidocs/spot/en/#all-orders-user_data + + :param symbol: required + :type symbol: str + :param orderId: The unique order id + :type orderId: int + :param startTime: optional + :type startTime: int + :param endTime: optional + :type endTime: int + :param limit: Default 500; max 1000. + :type limit: int + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + [ + { + "symbol": "LTCBTC", + "orderId": 1, + "clientOrderId": "myOrder1", + "price": "0.1", + "origQty": "1.0", + "executedQty": "0.0", + "status": "NEW", + "timeInForce": "GTC", + "type": "LIMIT", + "side": "BUY", + "stopPrice": "0.0", + "icebergQty": "0.0", + "time": 1499827319559 + } + ] + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._get('allOrders', True, data=params) + + def cancel_order(self, **params): + """Cancel an active order. Either orderId or origClientOrderId must be sent. + + https://binance-docs.github.io/apidocs/spot/en/#cancel-order-trade + + :param symbol: required + :type symbol: str + :param orderId: The unique order id + :type orderId: int + :param origClientOrderId: optional + :type origClientOrderId: str + :param newClientOrderId: Used to uniquely identify this cancel. Automatically generated by default. + :type newClientOrderId: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "symbol": "LTCBTC", + "origClientOrderId": "myOrder1", + "orderId": 1, + "clientOrderId": "cancelMyOrder1" + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._delete('order', True, data=params) + + def get_open_orders(self, **params): + """Get all open orders on a symbol. + + https://binance-docs.github.io/apidocs/spot/en/#current-open-orders-user_data + + :param symbol: optional + :type symbol: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + [ + { + "symbol": "LTCBTC", + "orderId": 1, + "clientOrderId": "myOrder1", + "price": "0.1", + "origQty": "1.0", + "executedQty": "0.0", + "status": "NEW", + "timeInForce": "GTC", + "type": "LIMIT", + "side": "BUY", + "stopPrice": "0.0", + "icebergQty": "0.0", + "time": 1499827319559 + } + ] + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._get('openOrders', True, data=params) + + # User Stream Endpoints + def get_account(self, **params): + """Get current account information. + + https://binance-docs.github.io/apidocs/spot/en/#account-information-user_data + + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "makerCommission": 15, + "takerCommission": 15, + "buyerCommission": 0, + "sellerCommission": 0, + "canTrade": true, + "canWithdraw": true, + "canDeposit": true, + "balances": [ + { + "asset": "BTC", + "free": "4723846.89208129", + "locked": "0.00000000" + }, + { + "asset": "LTC", + "free": "4763368.68006011", + "locked": "0.00000000" + } + ] + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._get('account', True, data=params) + + def get_asset_balance(self, asset, **params): + """Get current asset balance. + + :param asset: required + :type asset: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: dictionary or None if not found + + .. code-block:: python + + { + "asset": "BTC", + "free": "4723846.89208129", + "locked": "0.00000000" + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + res = self.get_account(**params) + # find asset balance in list of balances + if "balances" in res: + for bal in res['balances']: + if bal['asset'].lower() == asset.lower(): + return bal + return None + + def get_my_trades(self, **params): + """Get trades for a specific symbol. + + https://binance-docs.github.io/apidocs/spot/en/#account-trade-list-user_data + + :param symbol: required + :type symbol: str + :param startTime: optional + :type startTime: int + :param endTime: optional + :type endTime: int + :param limit: Default 500; max 1000. + :type limit: int + :param fromId: TradeId to fetch from. Default gets most recent trades. + :type fromId: int + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + [ + { + "id": 28457, + "price": "4.00000100", + "qty": "12.00000000", + "commission": "10.10000000", + "commissionAsset": "BNB", + "time": 1499865549590, + "isBuyer": true, + "isMaker": false, + "isBestMatch": true + } + ] + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._get('myTrades', True, data=params) + + def get_system_status(self): + """Get system status detail. + + https://binance-docs.github.io/apidocs/spot/en/#system-status-sapi-system + + :returns: API response + + .. code-block:: python + + { + "status": 0, # 0: normal,1:system maintenance + "msg": "normal" # normal or System maintenance. + } + + :raises: BinanceAPIException + + """ + return self._request_margin_api('get', 'system/status') + + def get_account_status(self, **params): + """Get account status detail. + + https://binance-docs.github.io/apidocs/spot/en/#account-status-sapi-user_data + + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "data": "Normal" + } + + """ + return self._request_margin_api('get', 'account/status', True, data=params) + + def get_account_api_trading_status(self, **params): + """Fetch account api trading status detail. + + https://binance-docs.github.io/apidocs/spot/en/#account-api-trading-status-sapi-user_data + + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "data": { // API trading status detail + "isLocked": false, // API trading function is locked or not + "plannedRecoverTime": 0, // If API trading function is locked, this is the planned recover time + "triggerCondition": { + "GCR": 150, // Number of GTC orders + "IFER": 150, // Number of FOK/IOC orders + "UFR": 300 // Number of orders + }, + "indicators": { // The indicators updated every 30 seconds + "BTCUSDT": [ // The symbol + { + "i": "UFR", // Unfilled Ratio (UFR) + "c": 20, // Count of all orders + "v": 0.05, // Current UFR value + "t": 0.995 // Trigger UFR value + }, + { + "i": "IFER", // IOC/FOK Expiration Ratio (IFER) + "c": 20, // Count of FOK/IOC orders + "v": 0.99, // Current IFER value + "t": 0.99 // Trigger IFER value + }, + { + "i": "GCR", // GTC Cancellation Ratio (GCR) + "c": 20, // Count of GTC orders + "v": 0.99, // Current GCR value + "t": 0.99 // Trigger GCR value + } + ], + "ETHUSDT": [ + { + "i": "UFR", + "c": 20, + "v": 0.05, + "t": 0.995 + }, + { + "i": "IFER", + "c": 20, + "v": 0.99, + "t": 0.99 + }, + { + "i": "GCR", + "c": 20, + "v": 0.99, + "t": 0.99 + } + ] + }, + "updateTime": 1547630471725 + } + } + + """ + return self._request_margin_api('get', 'account/apiTradingStatus', True, data=params) + + def get_account_api_permissions(self, **params): + """Fetch api key permissions. + + https://binance-docs.github.io/apidocs/spot/en/#get-api-key-permission-user_data + + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "ipRestrict": false, + "createTime": 1623840271000, + "enableWithdrawals": false, // This option allows you to withdraw via API. You must apply the IP Access Restriction filter in order to enable withdrawals + "enableInternalTransfer": true, // This option authorizes this key to transfer funds between your master account and your sub account instantly + "permitsUniversalTransfer": true, // Authorizes this key to be used for a dedicated universal transfer API to transfer multiple supported currencies. Each business's own transfer API rights are not affected by this authorization + "enableVanillaOptions": false, // Authorizes this key to Vanilla options trading + "enableReading": true, + "enableFutures": false, // API Key created before your futures account opened does not support futures API service + "enableMargin": false, // This option can be adjusted after the Cross Margin account transfer is completed + "enableSpotAndMarginTrading": false, // Spot and margin trading + "tradingAuthorityExpirationTime": 1628985600000 // Expiration time for spot and margin trading permission + } + + """ + return self._request_margin_api('get', 'account/apiRestrictions', True, data=params) + + def get_dust_log(self, **params): + """Get log of small amounts exchanged for BNB. + + https://binance-docs.github.io/apidocs/spot/en/#dustlog-sapi-user_data + + :param startTime: optional + :type startTime: int + :param endTime: optional + :type endTime: int + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "total": 8, //Total counts of exchange + "userAssetDribblets": [ + { + "totalTransferedAmount": "0.00132256", // Total transfered BNB amount for this exchange. + "totalServiceChargeAmount": "0.00002699", //Total service charge amount for this exchange. + "transId": 45178372831, + "userAssetDribbletDetails": [ //Details of this exchange. + { + "transId": 4359321, + "serviceChargeAmount": "0.000009", + "amount": "0.0009", + "operateTime": 1615985535000, + "transferedAmount": "0.000441", + "fromAsset": "USDT" + }, + { + "transId": 4359321, + "serviceChargeAmount": "0.00001799", + "amount": "0.0009", + "operateTime": "2018-05-03 17:07:04", + "transferedAmount": "0.00088156", + "fromAsset": "ETH" + } + ] + }, + { + "operateTime":1616203180000, + "totalTransferedAmount": "0.00058795", + "totalServiceChargeAmount": "0.000012", + "transId": 4357015, + "userAssetDribbletDetails": [ + { + "transId": 4357015, + "serviceChargeAmount": "0.00001" + "amount": "0.001", + "operateTime": 1616203180000, + "transferedAmount": "0.00049", + "fromAsset": "USDT" + }, + { + "transId": 4357015, + "serviceChargeAmount": "0.000002" + "amount": "0.0001", + "operateTime": 1616203180000, + "transferedAmount": "0.00009795", + "fromAsset": "ETH" + } + ] + } + ] + } + + """ + return self._request_margin_api('get', 'asset/dribblet', True, data=params) + + def transfer_dust(self, **params): + """Convert dust assets to BNB. + + https://binance-docs.github.io/apidocs/spot/en/#dust-transfer-user_data + + :param asset: The asset being converted. e.g: 'ONE' + :type asset: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + .. code:: python + + result = client.transfer_dust(asset='ONE') + + :returns: API response + + .. code-block:: python + + { + "totalServiceCharge":"0.02102542", + "totalTransfered":"1.05127099", + "transferResult":[ + { + "amount":"0.03000000", + "fromAsset":"ETH", + "operateTime":1563368549307, + "serviceChargeAmount":"0.00500000", + "tranId":2970932918, + "transferedAmount":"0.25000000" + } + ] + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('post', 'asset/dust', True, data=params) + + def get_asset_dividend_history(self, **params): + """Query asset dividend record. + + https://binance-docs.github.io/apidocs/spot/en/#asset-dividend-record-user_data + + :param asset: optional + :type asset: str + :param startTime: optional + :type startTime: long + :param endTime: optional + :type endTime: long + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + .. code:: python + + result = client.get_asset_dividend_history() + + :returns: API response + + .. code-block:: python + + { + "rows":[ + { + "amount":"10.00000000", + "asset":"BHFT", + "divTime":1563189166000, + "enInfo":"BHFT distribution", + "tranId":2968885920 + }, + { + "amount":"10.00000000", + "asset":"BHFT", + "divTime":1563189165000, + "enInfo":"BHFT distribution", + "tranId":2968885920 + } + ], + "total":2 + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'asset/assetDividend', True, data=params) + + def make_universal_transfer(self, **params): + """User Universal Transfer + + https://binance-docs.github.io/apidocs/spot/en/#user-universal-transfer + + :param type: required + :type type: str (ENUM) + :param asset: required + :type asset: str + :param amount: required + :type amount: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + .. code:: python + + transfer_status = client.make_universal_transfer(params) + + :returns: API response + + .. code-block:: python + + { + "tranId":13526853623 + } + + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('post', 'asset/transfer', signed=True, data=params) + + def query_universal_transfer_history(self, **params): + """Query User Universal Transfer History + + https://binance-docs.github.io/apidocs/spot/en/#query-user-universal-transfer-history + + :param type: required + :type type: str (ENUM) + :param startTime: optional + :type startTime: int + :param endTime: optional + :type endTime: int + :param current: optional - Default 1 + :type current: int + :param size: required - Default 10, Max 100 + :type size: int + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + .. code:: python + + transfer_status = client.query_universal_transfer_history(params) + + :returns: API response + + .. code-block:: python + + { + "total":2, + "rows":[ + { + "asset":"USDT", + "amount":"1", + "type":"MAIN_UMFUTURE" + "status": "CONFIRMED", + "tranId": 11415955596, + "timestamp":1544433328000 + }, + { + "asset":"USDT", + "amount":"2", + "type":"MAIN_UMFUTURE", + "status": "CONFIRMED", + "tranId": 11366865406, + "timestamp":1544433328000 + } + ] + } + + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'asset/transfer', signed=True, data=params) + + def get_trade_fee(self, **params): + """Get trade fee. + + https://binance-docs.github.io/apidocs/spot/en/#trade-fee-sapi-user_data + + :param symbol: optional + :type symbol: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + [ + { + "symbol": "ADABNB", + "makerCommission": "0.001", + "takerCommission": "0.001" + }, + { + "symbol": "BNBBTC", + "makerCommission": "0.001", + "takerCommission": "0.001" + } + ] + + """ + return self._request_margin_api('get', 'asset/tradeFee', True, data=params) + + def get_asset_details(self, **params): + """Fetch details on assets. + + https://binance-docs.github.io/apidocs/spot/en/#asset-detail-sapi-user_data + + :param asset: optional + :type asset: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "CTR": { + "minWithdrawAmount": "70.00000000", //min withdraw amount + "depositStatus": false,//deposit status (false if ALL of networks' are false) + "withdrawFee": 35, // withdraw fee + "withdrawStatus": true, //withdraw status (false if ALL of networks' are false) + "depositTip": "Delisted, Deposit Suspended" //reason + }, + "SKY": { + "minWithdrawAmount": "0.02000000", + "depositStatus": true, + "withdrawFee": 0.01, + "withdrawStatus": true + } + } + + """ + return self._request_margin_api('get', 'asset/assetDetail', True, data=params) + + # Withdraw Endpoints + + def withdraw(self, **params): + """Submit a withdraw request. + + https://binance-docs.github.io/apidocs/spot/en/#withdraw-sapi + + Assumptions: + + - You must have Withdraw permissions enabled on your API key + - You must have withdrawn to the address specified through the website and approved the transaction via email + + :param coin: required + :type coin: str + :param withdrawOrderId: optional - client id for withdraw + :type withdrawOrderId: str + :param network: optional + :type network: str + :param address: optional + :type address: str + :type addressTag: optional - Secondary address identifier for coins like XRP,XMR etc. + :param amount: required + :type amount: decimal + :param transactionFeeFlag: required - When making internal transfer, true for returning the fee to the destination account; false for returning the fee back to the departure account. Default false. + :type transactionFeeFlag: bool + :param name: optional - Description of the address, default asset value passed will be used + :type name: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "id":"7213fea8e94b4a5593d507237e5a555b" + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + # force a name for the withdrawal if one not set + if 'coin' in params and 'name' not in params: + params['name'] = params['coin'] + return self._request_margin_api('post', 'capital/withdraw/apply', True, data=params) + + def get_deposit_history(self, **params): + """Fetch deposit history. + + https://binance-docs.github.io/apidocs/spot/en/#deposit-history-supporting-network-user_data + + :param coin: optional + :type coin: str + :type status: optional - 0(0:pending,1:success) optional + :type status: int + :param startTime: optional + :type startTime: long + :param endTime: optional + :type endTime: long + :param offset: optional - default:0 + :type offset: long + :param limit: optional + :type limit: long + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + [ + { + "amount":"0.00999800", + "coin":"PAXG", + "network":"ETH", + "status":1, + "address":"0x788cabe9236ce061e5a892e1a59395a81fc8d62c", + "addressTag":"", + "txId":"0xaad4654a3234aa6118af9b4b335f5ae81c360b2394721c019b5d1e75328b09f3", + "insertTime":1599621997000, + "transferType":0, + "confirmTimes":"12/12" + }, + { + "amount":"0.50000000", + "coin":"IOTA", + "network":"IOTA", + "status":1, + "address":"SIZ9VLMHWATXKV99LH99CIGFJFUMLEHGWVZVNNZXRJJVWBPHYWPPBOSDORZ9EQSHCZAMPVAPGFYQAUUV9DROOXJLNW", + "addressTag":"", + "txId":"ESBFVQUTPIWQNJSPXFNHNYHSQNTGKRVKPRABQWTAXCDWOAKDKYWPTVG9BGXNVNKTLEJGESAVXIKIZ9999", + "insertTime":1599620082000, + "transferType":0, + "confirmTimes":"1/1" + } + ] + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'capital/deposit/hisrec', True, data=params) + + def get_withdraw_history(self, **params): + """Fetch withdraw history. + + https://binance-docs.github.io/apidocs/spot/en/#withdraw-history-supporting-network-user_data + + :param coin: optional + :type coin: str + :type status: 0(0:Email Sent,1:Cancelled 2:Awaiting Approval 3:Rejected 4:Processing 5:Failure 6Completed) optional + :type status: int + :param offset: optional - default:0 + :type offset: int + :param limit: optional + :type limit: int + :param startTime: optional - Default: 90 days from current timestamp + :type startTime: int + :param endTime: optional - Default: present timestamp + :type endTime: int + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + [ + { + "address": "0x94df8b352de7f46f64b01d3666bf6e936e44ce60", + "amount": "8.91000000", + "applyTime": "2019-10-12 11:12:02", + "coin": "USDT", + "id": "b6ae22b3aa844210a7041aee7589627c", + "withdrawOrderId": "WITHDRAWtest123", // will not be returned if there's no withdrawOrderId for this withdraw. + "network": "ETH", + "transferType": 0, // 1 for internal transfer, 0 for external transfer + "status": 6, + "txId": "0xb5ef8c13b968a406cc62a93a8bd80f9e9a906ef1b3fcf20a2e48573c17659268" + }, + { + "address": "1FZdVHtiBqMrWdjPyRPULCUceZPJ2WLCsB", + "amount": "0.00150000", + "applyTime": "2019-09-24 12:43:45", + "coin": "BTC", + "id": "156ec387f49b41df8724fa744fa82719", + "network": "BTC", + "status": 6, + "txId": "60fd9007ebfddc753455f95fafa808c4302c836e4d1eebc5a132c36c1d8ac354" + } + ] + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'capital/withdraw/history', True, data=params) + + def get_withdraw_history_id(self, withdraw_id, **params): + """Fetch withdraw history. + + https://binance-docs.github.io/apidocs/spot/en/#withdraw-history-supporting-network-user_data + + :param withdraw_id: required + :type withdraw_id: str + :param asset: optional + :type asset: str + :type status: 0(0:Email Sent,1:Cancelled 2:Awaiting Approval 3:Rejected 4:Processing 5:Failure 6Completed) optional + :type status: int + :param startTime: optional + :type startTime: long + :param endTime: optional + :type endTime: long + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "id":"7213fea8e94b4a5593d507237e5a555b", + "withdrawOrderId": None, + "amount": 0.99, + "transactionFee": 0.01, + "address": "0x6915f16f8791d0a1cc2bf47c13a6b2a92000504b", + "asset": "ETH", + "txId": "0xdf33b22bdb2b28b1f75ccd201a4a4m6e7g83jy5fc5d5a9d1340961598cfcb0a1", + "applyTime": 1508198532000, + "status": 4 + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + result = self.get_withdraw_history(**params) + + for entry in result: + if 'id' in entry and entry['id'] == withdraw_id: + return entry + + raise Exception("There is no entry with withdraw id", result) + + def get_deposit_address(self, coin: str, network: Optional[str] = None, **params): + """Fetch a deposit address for a symbol + + https://binance-docs.github.io/apidocs/spot/en/#deposit-address-supporting-network-user_data + + :param coin: required + :type coin: str + :param network: optional + :type network: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "address": "1HPn8Rx2y6nNSfagQBKy27GB99Vbzg89wv", + "coin": "BTC", + "tag": "", + "url": "https://btc.com/1HPn8Rx2y6nNSfagQBKy27GB99Vbzg89wv" + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + params['coin'] = coin + if network: + params['network'] = network + return self._request_margin_api('get', 'capital/deposit/address', True, data=params) + + # User Stream Endpoints + + def stream_get_listen_key(self): + """Start a new user data stream and return the listen key + If a stream already exists it should return the same key. + If the stream becomes invalid a new key is returned. + + Can be used to keep the user stream alive. + + https://binance-docs.github.io/apidocs/spot/en/#listen-key-spot + + :returns: API response + + .. code-block:: python + + { + "listenKey": "pqia91ma19a5s61cv6a81va65sdf19v8a65a1a5s61cv6a81va65sdf19v8a65a1" + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + res = self._post('userDataStream', False, data={}, version=self.PRIVATE_API_VERSION) + return res['listenKey'] + + def stream_keepalive(self, listenKey): + """PING a user data stream to prevent a time out. + + https://binance-docs.github.io/apidocs/spot/en/#listen-key-spot + + :param listenKey: required + :type listenKey: str + + :returns: API response + + .. code-block:: python + + {} + + :raises: BinanceRequestException, BinanceAPIException + + """ + params = { + 'listenKey': listenKey + } + return self._put('userDataStream', False, data=params, version=self.PRIVATE_API_VERSION) + + def stream_close(self, listenKey): + """Close out a user data stream. + + https://binance-docs.github.io/apidocs/spot/en/#listen-key-spot + + :param listenKey: required + :type listenKey: str + + :returns: API response + + .. code-block:: python + + {} + + :raises: BinanceRequestException, BinanceAPIException + + """ + params = { + 'listenKey': listenKey + } + return self._delete('userDataStream', False, data=params, version=self.PRIVATE_API_VERSION) + + # Margin Trading Endpoints + + def get_margin_account(self, **params): + """Query cross-margin account details + + https://binance-docs.github.io/apidocs/spot/en/#query-cross-margin-account-details-user_data + + :returns: API response + + .. code-block:: python + + { + "borrowEnabled": true, + "marginLevel": "11.64405625", + "totalAssetOfBtc": "6.82728457", + "totalLiabilityOfBtc": "0.58633215", + "totalNetAssetOfBtc": "6.24095242", + "tradeEnabled": true, + "transferEnabled": true, + "userAssets": [ + { + "asset": "BTC", + "borrowed": "0.00000000", + "free": "0.00499500", + "interest": "0.00000000", + "locked": "0.00000000", + "netAsset": "0.00499500" + }, + { + "asset": "BNB", + "borrowed": "201.66666672", + "free": "2346.50000000", + "interest": "0.00000000", + "locked": "0.00000000", + "netAsset": "2144.83333328" + }, + { + "asset": "ETH", + "borrowed": "0.00000000", + "free": "0.00000000", + "interest": "0.00000000", + "locked": "0.00000000", + "netAsset": "0.00000000" + }, + { + "asset": "USDT", + "borrowed": "0.00000000", + "free": "0.00000000", + "interest": "0.00000000", + "locked": "0.00000000", + "netAsset": "0.00000000" + } + ] + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'margin/account', True, data=params) + + def get_isolated_margin_account(self, **params): + """Query isolated margin account details + + https://binance-docs.github.io/apidocs/spot/en/#query-isolated-margin-account-info-user_data + + :param symbols: optional up to 5 margin pairs as a comma separated string + :type asset: str + + .. code:: python + + account_info = client.get_isolated_margin_account() + account_info = client.get_isolated_margin_account(symbols="BTCUSDT,ETHUSDT") + + :returns: API response + + .. code-block:: python + + If "symbols" is not sent: + + { + "assets":[ + { + "baseAsset": + { + "asset": "BTC", + "borrowEnabled": true, + "borrowed": "0.00000000", + "free": "0.00000000", + "interest": "0.00000000", + "locked": "0.00000000", + "netAsset": "0.00000000", + "netAssetOfBtc": "0.00000000", + "repayEnabled": true, + "totalAsset": "0.00000000" + }, + "quoteAsset": + { + "asset": "USDT", + "borrowEnabled": true, + "borrowed": "0.00000000", + "free": "0.00000000", + "interest": "0.00000000", + "locked": "0.00000000", + "netAsset": "0.00000000", + "netAssetOfBtc": "0.00000000", + "repayEnabled": true, + "totalAsset": "0.00000000" + }, + "symbol": "BTCUSDT" + "isolatedCreated": true, + "marginLevel": "0.00000000", + "marginLevelStatus": "EXCESSIVE", // "EXCESSIVE", "NORMAL", "MARGIN_CALL", "PRE_LIQUIDATION", "FORCE_LIQUIDATION" + "marginRatio": "0.00000000", + "indexPrice": "10000.00000000" + "liquidatePrice": "1000.00000000", + "liquidateRate": "1.00000000" + "tradeEnabled": true + } + ], + "totalAssetOfBtc": "0.00000000", + "totalLiabilityOfBtc": "0.00000000", + "totalNetAssetOfBtc": "0.00000000" + } + + If "symbols" is sent: + + { + "assets":[ + { + "baseAsset": + { + "asset": "BTC", + "borrowEnabled": true, + "borrowed": "0.00000000", + "free": "0.00000000", + "interest": "0.00000000", + "locked": "0.00000000", + "netAsset": "0.00000000", + "netAssetOfBtc": "0.00000000", + "repayEnabled": true, + "totalAsset": "0.00000000" + }, + "quoteAsset": + { + "asset": "USDT", + "borrowEnabled": true, + "borrowed": "0.00000000", + "free": "0.00000000", + "interest": "0.00000000", + "locked": "0.00000000", + "netAsset": "0.00000000", + "netAssetOfBtc": "0.00000000", + "repayEnabled": true, + "totalAsset": "0.00000000" + }, + "symbol": "BTCUSDT" + "isolatedCreated": true, + "marginLevel": "0.00000000", + "marginLevelStatus": "EXCESSIVE", // "EXCESSIVE", "NORMAL", "MARGIN_CALL", "PRE_LIQUIDATION", "FORCE_LIQUIDATION" + "marginRatio": "0.00000000", + "indexPrice": "10000.00000000" + "liquidatePrice": "1000.00000000", + "liquidateRate": "1.00000000" + "tradeEnabled": true + } + ] + } + + """ + return self._request_margin_api('get', 'margin/isolated/account', True, data=params) + + def enable_isolated_margin_account(self, **params): + """Enable isolated margin account for a specific symbol. + + https://binance-docs.github.io/apidocs/spot/en/#enable-isolated-margin-account-trade + + :param symbol: + :type asset: str + + :returns: API response + + .. code-block:: python + + { + "success": true, + "symbol": "BTCUSDT" + } + + + """ + return self._request_margin_api('post', 'margin/isolated/account', True, data=params) + + def disable_isolated_margin_account(self, **params): + """Disable isolated margin account for a specific symbol. Each trading pair can only + be deactivated once every 24 hours. + + https://binance-docs.github.io/apidocs/spot/en/#disable-isolated-margin-account-trade + + :param symbol: + :type asset: str + + :returns: API response + + .. code-block:: python + + { + "success": true, + "symbol": "BTCUSDT" + } + + + """ + return self._request_margin_api('delete', 'margin/isolated/account', True, data=params) + + def get_margin_asset(self, **params): + """Query cross-margin asset + + https://binance-docs.github.io/apidocs/spot/en/#query-margin-asset-market_data + + :param asset: name of the asset + :type asset: str + + .. code:: python + + asset_details = client.get_margin_asset(asset='BNB') + + :returns: API response + + .. code-block:: python + + { + "assetFullName": "Binance Coin", + "assetName": "BNB", + "isBorrowable": false, + "isMortgageable": true, + "userMinBorrow": "0.00000000", + "userMinRepay": "0.00000000" + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'margin/asset', data=params) + + def get_margin_symbol(self, **params): + """Query cross-margin symbol info + + https://binance-docs.github.io/apidocs/spot/en/#query-cross-margin-pair-market_data + + :param symbol: name of the symbol pair + :type symbol: str + + .. code:: python + + pair_details = client.get_margin_symbol(symbol='BTCUSDT') + + :returns: API response + + .. code-block:: python + + { + "id":323355778339572400, + "symbol":"BTCUSDT", + "base":"BTC", + "quote":"USDT", + "isMarginTrade":true, + "isBuyAllowed":true, + "isSellAllowed":true + } + + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'margin/pair', data=params) + + def get_margin_all_assets(self, **params): + """Get All Margin Assets (MARKET_DATA) + + https://binance-docs.github.io/apidocs/spot/en/#get-all-margin-assets-market_data + + .. code:: python + + margin_assets = client.get_margin_all_assets() + + :returns: API response + + .. code-block:: python + + [ + { + "assetFullName": "USD coin", + "assetName": "USDC", + "isBorrowable": true, + "isMortgageable": true, + "userMinBorrow": "0.00000000", + "userMinRepay": "0.00000000" + }, + { + "assetFullName": "BNB-coin", + "assetName": "BNB", + "isBorrowable": true, + "isMortgageable": true, + "userMinBorrow": "1.00000000", + "userMinRepay": "0.00000000" + } + ] + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'margin/allAssets', data=params) + + def get_margin_all_pairs(self, **params): + """Get All Cross Margin Pairs (MARKET_DATA) + + https://binance-docs.github.io/apidocs/spot/en/#get-all-cross-margin-pairs-market_data + + .. code:: python + + margin_pairs = client.get_margin_all_pairs() + + :returns: API response + + .. code-block:: python + + [ + { + "base": "BNB", + "id": 351637150141315861, + "isBuyAllowed": true, + "isMarginTrade": true, + "isSellAllowed": true, + "quote": "BTC", + "symbol": "BNBBTC" + }, + { + "base": "TRX", + "id": 351637923235429141, + "isBuyAllowed": true, + "isMarginTrade": true, + "isSellAllowed": true, + "quote": "BTC", + "symbol": "TRXBTC" + } + ] + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'margin/allPairs', data=params) + + def create_isolated_margin_account(self, **params): + """Create isolated margin account for symbol + + https://binance-docs.github.io/apidocs/spot/en/#create-isolated-margin-account-margin + + :param base: Base asset of symbol + :type base: str + :param quote: Quote asset of symbol + :type quote: str + + .. code:: python + + pair_details = client.create_isolated_margin_account(base='USDT', quote='BTC') + + :returns: API response + + .. code-block:: python + + { + "success": true, + "symbol": "BTCUSDT" + } + + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('post', 'margin/isolated/create', signed=True, data=params) + + def get_isolated_margin_symbol(self, **params): + """Query isolated margin symbol info + + https://binance-docs.github.io/apidocs/spot/en/#query-isolated-margin-symbol-user_data + + :param symbol: name of the symbol pair + :type symbol: str + + .. code:: python + + pair_details = client.get_isolated_margin_symbol(symbol='BTCUSDT') + + :returns: API response + + .. code-block:: python + + { + "symbol":"BTCUSDT", + "base":"BTC", + "quote":"USDT", + "isMarginTrade":true, + "isBuyAllowed":true, + "isSellAllowed":true + } + + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'margin/isolated/pair', signed=True, data=params) + + def get_all_isolated_margin_symbols(self, **params): + """Query isolated margin symbol info for all pairs + + https://binance-docs.github.io/apidocs/spot/en/#get-all-isolated-margin-symbol-user_data + + .. code:: python + + pair_details = client.get_all_isolated_margin_symbols() + + :returns: API response + + .. code-block:: python + + [ + { + "base": "BNB", + "isBuyAllowed": true, + "isMarginTrade": true, + "isSellAllowed": true, + "quote": "BTC", + "symbol": "BNBBTC" + }, + { + "base": "TRX", + "isBuyAllowed": true, + "isMarginTrade": true, + "isSellAllowed": true, + "quote": "BTC", + "symbol": "TRXBTC" + } + ] + + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'margin/isolated/allPairs', signed=True, data=params) + + def toggle_bnb_burn_spot_margin(self, **params): + """Toggle BNB Burn On Spot Trade And Margin Interest + + https://binance-docs.github.io/apidocs/spot/en/#toggle-bnb-burn-on-spot-trade-and-margin-interest-user_data + + :param spotBNBBurn: Determines whether to use BNB to pay for trading fees on SPOT + :type spotBNBBurn: bool + :param interestBNBBurn: Determines whether to use BNB to pay for margin loan's interest + :type interestBNBBurn: bool + + .. code:: python + + response = client.toggle_bnb_burn_spot_margin() + + :returns: API response + + .. code-block:: python + + { + "spotBNBBurn":true, + "interestBNBBurn": false + } + + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('post', 'bnbBurn', signed=True, data=params) + + def get_bnb_burn_spot_margin(self, **params): + """Get BNB Burn Status + + https://binance-docs.github.io/apidocs/spot/en/#get-bnb-burn-status-user_data + + .. code:: python + + status = client.get_bnb_burn_spot_margin() + + :returns: API response + + .. code-block:: python + + { + "spotBNBBurn":true, + "interestBNBBurn": false + } + + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'bnbBurn', signed=True, data=params) + + def get_margin_price_index(self, **params): + """Query margin priceIndex + + https://binance-docs.github.io/apidocs/spot/en/#query-margin-priceindex-market_data + + :param symbol: name of the symbol pair + :type symbol: str + + .. code:: python + + price_index_details = client.get_margin_price_index(symbol='BTCUSDT') + + :returns: API response + + .. code-block:: python + + { + "calcTime": 1562046418000, + "price": "0.00333930", + "symbol": "BNBBTC" + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'margin/priceIndex', data=params) + + def transfer_margin_to_spot(self, **params): + """Execute transfer between cross-margin account and spot account. + + https://binance-docs.github.io/apidocs/spot/en/#cross-margin-account-transfer-margin + + :param asset: name of the asset + :type asset: str + :param amount: amount to transfer + :type amount: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + .. code:: python + + transfer = client.transfer_margin_to_spot(asset='BTC', amount='1.1') + + :returns: API response + + .. code-block:: python + + { + "tranId": 100000001 + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + params['type'] = 2 + return self._request_margin_api('post', 'margin/transfer', signed=True, data=params) + + def transfer_spot_to_margin(self, **params): + """Execute transfer between spot account and cross-margin account. + + https://binance-docs.github.io/apidocs/spot/en/#cross-margin-account-transfer-margin + + :param asset: name of the asset + :type asset: str + :param amount: amount to transfer + :type amount: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + .. code:: python + + transfer = client.transfer_spot_to_margin(asset='BTC', amount='1.1') + + :returns: API response + + .. code-block:: python + + { + "tranId": 100000001 + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + params['type'] = 1 + return self._request_margin_api('post', 'margin/transfer', signed=True, data=params) + + def transfer_isolated_margin_to_spot(self, **params): + """Execute transfer between isolated margin account and spot account. + + https://binance-docs.github.io/apidocs/spot/en/#isolated-margin-account-transfer-margin + + :param asset: name of the asset + :type asset: str + :param symbol: pair symbol + :type symbol: str + :param amount: amount to transfer + :type amount: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + .. code:: python + + transfer = client.transfer_isolated_margin_to_spot(asset='BTC', + symbol='ETHBTC', amount='1.1') + + :returns: API response + + .. code-block:: python + + { + "tranId": 100000001 + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + params['transFrom'] = "ISOLATED_MARGIN" + params['transTo'] = "SPOT" + return self._request_margin_api('post', 'margin/isolated/transfer', signed=True, data=params) + + def transfer_spot_to_isolated_margin(self, **params): + """Execute transfer between spot account and isolated margin account. + + https://binance-docs.github.io/apidocs/spot/en/#isolated-margin-account-transfer-margin + + :param asset: name of the asset + :type asset: str + :param symbol: pair symbol + :type symbol: str + :param amount: amount to transfer + :type amount: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + .. code:: python + + transfer = client.transfer_spot_to_isolated_margin(asset='BTC', + symbol='ETHBTC', amount='1.1') + + :returns: API response + + .. code-block:: python + + { + "tranId": 100000001 + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + params['transFrom'] = "SPOT" + params['transTo'] = "ISOLATED_MARGIN" + return self._request_margin_api('post', 'margin/isolated/transfer', signed=True, data=params) + + def create_margin_loan(self, **params): + """Apply for a loan in cross-margin or isolated-margin account. + + https://binance-docs.github.io/apidocs/spot/en/#margin-account-borrow-margin + + :param asset: name of the asset + :type asset: str + :param amount: amount to transfer + :type amount: str + :param isIsolated: set to 'TRUE' for isolated margin (default 'FALSE') + :type isIsolated: str + :param symbol: Isolated margin symbol (default blank for cross-margin) + :type symbol: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + .. code:: python + + transaction = client.margin_create_loan(asset='BTC', amount='1.1') + + transaction = client.margin_create_loan(asset='BTC', amount='1.1', + isIsolated='TRUE', symbol='ETHBTC') + + :returns: API response + + .. code-block:: python + + { + "tranId": 100000001 + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('post', 'margin/loan', signed=True, data=params) + + def repay_margin_loan(self, **params): + """Repay loan in cross-margin or isolated-margin account. + + If amount is more than the amount borrowed, the full loan will be repaid. + + https://binance-docs.github.io/apidocs/spot/en/#margin-account-repay-margin + + :param asset: name of the asset + :type asset: str + :param amount: amount to transfer + :type amount: str + :param isIsolated: set to 'TRUE' for isolated margin (default 'FALSE') + :type isIsolated: str + :param symbol: Isolated margin symbol (default blank for cross-margin) + :type symbol: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + .. code:: python + + transaction = client.margin_repay_loan(asset='BTC', amount='1.1') + + transaction = client.margin_repay_loan(asset='BTC', amount='1.1', + isIsolated='TRUE', symbol='ETHBTC') + + :returns: API response + + .. code-block:: python + + { + "tranId": 100000001 + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('post', 'margin/repay', signed=True, data=params) + + def create_margin_order(self, **params): + """Post a new order for margin account. + + https://binance-docs.github.io/apidocs/spot/en/#margin-account-new-order-trade + + :param symbol: required + :type symbol: str + :param isIsolated: set to 'TRUE' for isolated margin (default 'FALSE') + :type isIsolated: str + :param side: required + :type side: str + :param type: required + :type type: str + :param quantity: required + :type quantity: decimal + :param price: required + :type price: str + :param stopPrice: Used with STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, and TAKE_PROFIT_LIMIT orders. + :type stopPrice: str + :param timeInForce: required if limit order GTC,IOC,FOK + :type timeInForce: str + :param newClientOrderId: A unique id for the order. Automatically generated if not sent. + :type newClientOrderId: str + :param icebergQty: Used with LIMIT, STOP_LOSS_LIMIT, and TAKE_PROFIT_LIMIT to create an iceberg order. + :type icebergQty: str + :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; MARKET and LIMIT order types default to + FULL, all other orders default to ACK. + :type newOrderRespType: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + Response ACK: + + .. code-block:: python + + { + "symbol": "BTCUSDT", + "orderId": 28, + "clientOrderId": "6gCrw2kRUAF9CvJDGP16IP", + "transactTime": 1507725176595 + } + + Response RESULT: + + .. code-block:: python + + { + "symbol": "BTCUSDT", + "orderId": 28, + "clientOrderId": "6gCrw2kRUAF9CvJDGP16IP", + "transactTime": 1507725176595, + "price": "1.00000000", + "origQty": "10.00000000", + "executedQty": "10.00000000", + "cummulativeQuoteQty": "10.00000000", + "status": "FILLED", + "timeInForce": "GTC", + "type": "MARKET", + "side": "SELL" + } + + Response FULL: + + .. code-block:: python + + { + "symbol": "BTCUSDT", + "orderId": 28, + "clientOrderId": "6gCrw2kRUAF9CvJDGP16IP", + "transactTime": 1507725176595, + "price": "1.00000000", + "origQty": "10.00000000", + "executedQty": "10.00000000", + "cummulativeQuoteQty": "10.00000000", + "status": "FILLED", + "timeInForce": "GTC", + "type": "MARKET", + "side": "SELL", + "fills": [ + { + "price": "4000.00000000", + "qty": "1.00000000", + "commission": "4.00000000", + "commissionAsset": "USDT" + }, + { + "price": "3999.00000000", + "qty": "5.00000000", + "commission": "19.99500000", + "commissionAsset": "USDT" + }, + { + "price": "3998.00000000", + "qty": "2.00000000", + "commission": "7.99600000", + "commissionAsset": "USDT" + }, + { + "price": "3997.00000000", + "qty": "1.00000000", + "commission": "3.99700000", + "commissionAsset": "USDT" + }, + { + "price": "3995.00000000", + "qty": "1.00000000", + "commission": "3.99500000", + "commissionAsset": "USDT" + } + ] + } + + :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, + BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, + BinanceOrderInactiveSymbolException + + """ + return self._request_margin_api('post', 'margin/order', signed=True, data=params) + + def cancel_margin_order(self, **params): + """Cancel an active order for margin account. + + Either orderId or origClientOrderId must be sent. + + https://binance-docs.github.io/apidocs/spot/en/#margin-account-cancel-order-trade + + :param symbol: required + :type symbol: str + :param isIsolated: set to 'TRUE' for isolated margin (default 'FALSE') + :type isIsolated: str + :param orderId: + :type orderId: str + :param origClientOrderId: + :type origClientOrderId: str + :param newClientOrderId: Used to uniquely identify this cancel. Automatically generated by default. + :type newClientOrderId: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + { + "symbol": "LTCBTC", + "orderId": 28, + "origClientOrderId": "myOrder1", + "clientOrderId": "cancelMyOrder1", + "transactTime": 1507725176595, + "price": "1.00000000", + "origQty": "10.00000000", + "executedQty": "8.00000000", + "cummulativeQuoteQty": "8.00000000", + "status": "CANCELED", + "timeInForce": "GTC", + "type": "LIMIT", + "side": "SELL" + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('delete', 'margin/order', signed=True, data=params) + + def get_margin_loan_details(self, **params): + """Query loan record + + txId or startTime must be sent. txId takes precedence. + + https://binance-docs.github.io/apidocs/spot/en/#query-loan-record-user_data + + :param asset: required + :type asset: str + :param isolatedSymbol: isolated symbol (if querying isolated margin) + :type isolatedSymbol: str + :param txId: the tranId in of the created loan + :type txId: str + :param startTime: earliest timestamp to filter transactions + :type startTime: str + :param endTime: Used to uniquely identify this cancel. Automatically generated by default. + :type endTime: str + :param current: Currently querying page. Start from 1. Default:1 + :type current: str + :param size: Default:10 Max:100 + :type size: int + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + { + "rows": [ + { + "asset": "BNB", + "principal": "0.84624403", + "timestamp": 1555056425000, + //one of PENDING (pending to execution), CONFIRMED (successfully loaned), FAILED (execution failed, nothing happened to your account); + "status": "CONFIRMED" + } + ], + "total": 1 + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'margin/loan', signed=True, data=params) + + def get_margin_repay_details(self, **params): + """Query repay record + + txId or startTime must be sent. txId takes precedence. + + https://binance-docs.github.io/apidocs/spot/en/#query-repay-record-user_data + + :param asset: required + :type asset: str + :param isolatedSymbol: isolated symbol (if querying isolated margin) + :type isolatedSymbol: str + :param txId: the tranId in of the created loan + :type txId: str + :param startTime: + :type startTime: str + :param endTime: Used to uniquely identify this cancel. Automatically generated by default. + :type endTime: str + :param current: Currently querying page. Start from 1. Default:1 + :type current: str + :param size: Default:10 Max:100 + :type size: int + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + { + "rows": [ + { + //Total amount repaid + "amount": "14.00000000", + "asset": "BNB", + //Interest repaid + "interest": "0.01866667", + //Principal repaid + "principal": "13.98133333", + //one of PENDING (pending to execution), CONFIRMED (successfully loaned), FAILED (execution failed, nothing happened to your account); + "status": "CONFIRMED", + "timestamp": 1563438204000, + "txId": 2970933056 + } + ], + "total": 1 + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'margin/repay', signed=True, data=params) + + def get_margin_interest_history(self, **params): + """Get Interest History (USER_DATA) + + https://binance-docs.github.io/apidocs/spot/en/#get-interest-history-user_data + + :param asset: + :type asset: str + :param isolatedSymbol: isolated symbol (if querying isolated margin) + :type isolatedSymbol: str + :param startTime: + :type startTime: str + :param endTime: + :type endTime: str + :param current: Currently querying page. Start from 1. Default:1 + :type current: str + :param size: Default:10 Max:100 + :type size: int + :param archived: Default: false. Set to true for archived data from 6 months ago + :type archived: bool + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + { + "rows":[ + { + "isolatedSymbol": "BNBUSDT", // isolated symbol, will not be returned for crossed margin + "asset": "BNB", + "interest": "0.02414667", + "interestAccuredTime": 1566813600000, + "interestRate": "0.01600000", + "principal": "36.22000000", + "type": "ON_BORROW" + } + ], + "total": 1 + } + + + """ + return self._request_margin_api('get', 'margin/interestHistory', signed=True, data=params) + + def get_margin_force_liquidation_rec(self, **params): + """Get Force Liquidation Record (USER_DATA) + + https://binance-docs.github.io/apidocs/spot/en/#get-force-liquidation-record-user_data + + :param startTime: + :type startTime: str + :param endTime: + :type endTime: str + :param isolatedSymbol: isolated symbol (if querying isolated margin) + :type isolatedSymbol: str + :param current: Currently querying page. Start from 1. Default:1 + :type current: str + :param size: Default:10 Max:100 + :type size: int + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + { + "rows": [ + { + "avgPrice": "0.00388359", + "executedQty": "31.39000000", + "orderId": 180015097, + "price": "0.00388110", + "qty": "31.39000000", + "side": "SELL", + "symbol": "BNBBTC", + "timeInForce": "GTC", + "isIsolated": true, + "updatedTime": 1558941374745 + } + ], + "total": 1 + } + + """ + return self._request_margin_api('get', 'margin/forceLiquidationRec', signed=True, data=params) + + def get_margin_order(self, **params): + """Query margin accounts order + + Either orderId or origClientOrderId must be sent. + + For some historical orders cummulativeQuoteQty will be < 0, meaning the data is not available at this time. + + https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-order-user_data + + :param symbol: required + :type symbol: str + :param isIsolated: set to 'TRUE' for isolated margin (default 'FALSE') + :type isIsolated: str + :param orderId: + :type orderId: str + :param origClientOrderId: + :type origClientOrderId: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + { + "clientOrderId": "ZwfQzuDIGpceVhKW5DvCmO", + "cummulativeQuoteQty": "0.00000000", + "executedQty": "0.00000000", + "icebergQty": "0.00000000", + "isWorking": true, + "orderId": 213205622, + "origQty": "0.30000000", + "price": "0.00493630", + "side": "SELL", + "status": "NEW", + "stopPrice": "0.00000000", + "symbol": "BNBBTC", + "time": 1562133008725, + "timeInForce": "GTC", + "type": "LIMIT", + "updateTime": 1562133008725 + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'margin/order', signed=True, data=params) + + def get_open_margin_orders(self, **params): + """Query margin accounts open orders + + If the symbol is not sent, orders for all symbols will be returned in an array (cross-margin only). + + If querying isolated margin orders, both the isIsolated='TRUE' and symbol=symbol_name must be set. + + When all symbols are returned, the number of requests counted against the rate limiter is equal to the number + of symbols currently trading on the exchange. + + https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-open-order-user_data + + :param symbol: optional + :type symbol: str + :param isIsolated: set to 'TRUE' for isolated margin (default 'FALSE') + :type isIsolated: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + [ + { + "clientOrderId": "qhcZw71gAkCCTv0t0k8LUK", + "cummulativeQuoteQty": "0.00000000", + "executedQty": "0.00000000", + "icebergQty": "0.00000000", + "isWorking": true, + "orderId": 211842552, + "origQty": "0.30000000", + "price": "0.00475010", + "side": "SELL", + "status": "NEW", + "stopPrice": "0.00000000", + "symbol": "BNBBTC", + "time": 1562040170089, + "timeInForce": "GTC", + "type": "LIMIT", + "updateTime": 1562040170089 + } + ] + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'margin/openOrders', signed=True, data=params) + + def get_all_margin_orders(self, **params): + """Query all margin accounts orders + + If orderId is set, it will get orders >= that orderId. Otherwise most recent orders are returned. + + For some historical orders cummulativeQuoteQty will be < 0, meaning the data is not available at this time. + + https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-all-order-user_data + + :param symbol: required + :type symbol: str + :param isIsolated: set to 'TRUE' for isolated margin (default 'FALSE') + :type isIsolated: str + :param orderId: optional + :type orderId: str + :param startTime: optional + :type startTime: str + :param endTime: optional + :type endTime: str + :param limit: Default 500; max 1000 + :type limit: int + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + [ + { + "id": 43123876, + "price": "0.00395740", + "qty": "4.06000000", + "quoteQty": "0.01606704", + "symbol": "BNBBTC", + "time": 1556089977693 + }, + { + "id": 43123877, + "price": "0.00395740", + "qty": "0.77000000", + "quoteQty": "0.00304719", + "symbol": "BNBBTC", + "time": 1556089977693 + }, + { + "id": 43253549, + "price": "0.00428930", + "qty": "23.30000000", + "quoteQty": "0.09994069", + "symbol": "BNBBTC", + "time": 1556163963504 + } + ] + + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'margin/allOrders', signed=True, data=params) + + def get_margin_trades(self, **params): + """Query margin accounts trades + + If fromId is set, it will get orders >= that fromId. Otherwise most recent orders are returned. + + https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-trade-list-user_data + + :param symbol: required + :type symbol: str + :param isIsolated: set to 'TRUE' for isolated margin (default 'FALSE') + :type isIsolated: str + :param fromId: optional + :type fromId: str + :param startTime: optional + :type startTime: str + :param endTime: optional + :type endTime: str + :param limit: Default 500; max 1000 + :type limit: int + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + [ + { + "commission": "0.00006000", + "commissionAsset": "BTC", + "id": 34, + "isBestMatch": true, + "isBuyer": false, + "isMaker": false, + "orderId": 39324, + "price": "0.02000000", + "qty": "3.00000000", + "symbol": "BNBBTC", + "time": 1561973357171 + }, { + "commission": "0.00002950", + "commissionAsset": "BTC", + "id": 32, + "isBestMatch": true, + "isBuyer": false, + "isMaker": true, + "orderId": 39319, + "price": "0.00590000", + "qty": "5.00000000", + "symbol": "BNBBTC", + "time": 1561964645345 + } + ] + + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'margin/myTrades', signed=True, data=params) + + def get_max_margin_loan(self, **params): + """Query max borrow amount for an asset + + https://binance-docs.github.io/apidocs/spot/en/#query-max-borrow-user_data + + :param asset: required + :type asset: str + :param isolatedSymbol: isolated symbol (if querying isolated margin) + :type isolatedSymbol: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + { + "amount": "1.69248805" + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'margin/maxBorrowable', signed=True, data=params) + + def get_max_margin_transfer(self, **params): + """Query max transfer-out amount + + https://binance-docs.github.io/apidocs/spot/en/#query-max-transfer-out-amount-user_data + + :param asset: required + :type asset: str + :param isolatedSymbol: isolated symbol (if querying isolated margin) + :type isolatedSymbol: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + { + "amount": "3.59498107" + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'margin/maxTransferable', signed=True, data=params) + + # Margin OCO + + def create_margin_oco_order(self, **params): + """Post a new OCO trade for margin account. + + https://binance-docs.github.io/apidocs/spot/en/#margin-account-new-oco-trade + + + :param symbol: required + :type symbol: str + :param isIsolated: for isolated margin or not, "TRUE", "FALSE",default "FALSE" + :type symbol: str + :param listClientOrderId: A unique id for the list order. Automatically generated if not sent. + :type listClientOrderId: str + :param side: required + :type side: str + :param quantity: required + :type quantity: decimal + :param limitClientOrderId: A unique id for the limit order. Automatically generated if not sent. + :type limitClientOrderId: str + :param price: required + :type price: str + :param limitIcebergQty: Used to make the LIMIT_MAKER leg an iceberg order. + :type limitIcebergQty: decimal + :param stopClientOrderId: A unique Id for the stop loss/stop loss limit leg. Automatically generated if not sent. + :type stopClientOrderId: str + :param stopPrice: required + :type stopPrice: str + :param stopLimitPrice: If provided, stopLimitTimeInForce is required. + :type stopLimitPrice: str + :param stopIcebergQty: Used with STOP_LOSS_LIMIT leg to make an iceberg order. + :type stopIcebergQty: decimal + :param stopLimitTimeInForce: Valid values are GTC/FOK/IOC. + :type stopLimitTimeInForce: str + :param newOrderRespType: Set the response JSON. ACK, RESULT, or FULL; default: RESULT. + :type newOrderRespType: str + :param sideEffectType: NO_SIDE_EFFECT, MARGIN_BUY, AUTO_REPAY; default NO_SIDE_EFFECT. + :type sideEffectType: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "orderListId": 0, + "contingencyType": "OCO", + "listStatusType": "EXEC_STARTED", + "listOrderStatus": "EXECUTING", + "listClientOrderId": "JYVpp3F0f5CAG15DhtrqLp", + "transactionTime": 1563417480525, + "symbol": "LTCBTC", + "marginBuyBorrowAmount": "5", // will not return if no margin trade happens + "marginBuyBorrowAsset": "BTC", // will not return if no margin trade happens + "isIsolated": false, // if isolated margin + "orders": [ + { + "symbol": "LTCBTC", + "orderId": 2, + "clientOrderId": "Kk7sqHb9J6mJWTMDVW7Vos" + }, + { + "symbol": "LTCBTC", + "orderId": 3, + "clientOrderId": "xTXKaGYd4bluPVp78IVRvl" + } + ], + "orderReports": [ + { + "symbol": "LTCBTC", + "orderId": 2, + "orderListId": 0, + "clientOrderId": "Kk7sqHb9J6mJWTMDVW7Vos", + "transactTime": 1563417480525, + "price": "0.000000", + "origQty": "0.624363", + "executedQty": "0.000000", + "cummulativeQuoteQty": "0.000000", + "status": "NEW", + "timeInForce": "GTC", + "type": "STOP_LOSS", + "side": "BUY", + "stopPrice": "0.960664" + }, + { + "symbol": "LTCBTC", + "orderId": 3, + "orderListId": 0, + "clientOrderId": "xTXKaGYd4bluPVp78IVRvl", + "transactTime": 1563417480525, + "price": "0.036435", + "origQty": "0.624363", + "executedQty": "0.000000", + "cummulativeQuoteQty": "0.000000", + "status": "NEW", + "timeInForce": "GTC", + "type": "LIMIT_MAKER", + "side": "BUY" + } + ] + } + + :raises: BinanceRequestException, BinanceAPIException, BinanceOrderException, BinanceOrderMinAmountException, + BinanceOrderMinPriceException, BinanceOrderMinTotalException, BinanceOrderUnknownSymbolException, + BinanceOrderInactiveSymbolException + + """ + return self._request_margin_api('post', 'margin/order/oco', signed=True, data=params) + + def cancel_margin_oco_order(self, **params): + """Cancel an entire Order List for a margin account. + + https://binance-docs.github.io/apidocs/spot/en/#margin-account-cancel-oco-trade + + :param symbol: required + :type symbol: str + :param isIsolated: for isolated margin or not, "TRUE", "FALSE",default "FALSE" + :type symbol: str + :param orderListId: Either orderListId or listClientOrderId must be provided + :type orderListId: int + :param listClientOrderId: Either orderListId or listClientOrderId must be provided + :type listClientOrderId: str + :param newClientOrderId: Used to uniquely identify this cancel. Automatically generated by default. + :type newClientOrderId: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "orderListId": 0, + "contingencyType": "OCO", + "listStatusType": "ALL_DONE", + "listOrderStatus": "ALL_DONE", + "listClientOrderId": "C3wyj4WVEktd7u9aVBRXcN", + "transactionTime": 1574040868128, + "symbol": "LTCBTC", + "isIsolated": false, // if isolated margin + "orders": [ + { + "symbol": "LTCBTC", + "orderId": 2, + "clientOrderId": "pO9ufTiFGg3nw2fOdgeOXa" + }, + { + "symbol": "LTCBTC", + "orderId": 3, + "clientOrderId": "TXOvglzXuaubXAaENpaRCB" + } + ], + "orderReports": [ + { + "symbol": "LTCBTC", + "origClientOrderId": "pO9ufTiFGg3nw2fOdgeOXa", + "orderId": 2, + "orderListId": 0, + "clientOrderId": "unfWT8ig8i0uj6lPuYLez6", + "price": "1.00000000", + "origQty": "10.00000000", + "executedQty": "0.00000000", + "cummulativeQuoteQty": "0.00000000", + "status": "CANCELED", + "timeInForce": "GTC", + "type": "STOP_LOSS_LIMIT", + "side": "SELL", + "stopPrice": "1.00000000" + }, + { + "symbol": "LTCBTC", + "origClientOrderId": "TXOvglzXuaubXAaENpaRCB", + "orderId": 3, + "orderListId": 0, + "clientOrderId": "unfWT8ig8i0uj6lPuYLez6", + "price": "3.00000000", + "origQty": "10.00000000", + "executedQty": "0.00000000", + "cummulativeQuoteQty": "0.00000000", + "status": "CANCELED", + "timeInForce": "GTC", + "type": "LIMIT_MAKER", + "side": "SELL" + } + ] + } + + """ + return self._request_margin_api('delete', 'margin/orderList', signed=True, data=params) + + def get_margin_oco_order(self, **params): + """Retrieves a specific OCO based on provided optional parameters + + https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-oco-user_data + + :param isIsolated: for isolated margin or not, "TRUE", "FALSE",default "FALSE" + :type symbol: str + :param symbol: mandatory for isolated margin, not supported for cross margin + :type symbol: str + :param orderListId: Either orderListId or listClientOrderId must be provided + :type orderListId: int + :param listClientOrderId: Either orderListId or listClientOrderId must be provided + :type listClientOrderId: str + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + { + "orderListId": 27, + "contingencyType": "OCO", + "listStatusType": "EXEC_STARTED", + "listOrderStatus": "EXECUTING", + "listClientOrderId": "h2USkA5YQpaXHPIrkd96xE", + "transactionTime": 1565245656253, + "symbol": "LTCBTC", + "isIsolated": false, // if isolated margin + "orders": [ + { + "symbol": "LTCBTC", + "orderId": 4, + "clientOrderId": "qD1gy3kc3Gx0rihm9Y3xwS" + }, + { + "symbol": "LTCBTC", + "orderId": 5, + "clientOrderId": "ARzZ9I00CPM8i3NhmU9Ega" + } + ] + } + + """ + return self._request_margin_api('get', 'margin/orderList', signed=True, data=params) + + def get_open_margin_oco_orders(self, **params): + """Retrieves open OCO trades + + https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-open-oco-user_data + + :param isIsolated: for isolated margin or not, "TRUE", "FALSE",default "FALSE" + :type symbol: str + :param symbol: mandatory for isolated margin, not supported for cross margin + :type symbol: str + :param fromId: If supplied, neither startTime or endTime can be provided + :type fromId: int + :param startTime: optional + :type startTime: int + :param endTime: optional + :type endTime: int + :param limit: optional Default Value: 500; Max Value: 1000 + :type limit: int + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + [ + { + "orderListId": 29, + "contingencyType": "OCO", + "listStatusType": "EXEC_STARTED", + "listOrderStatus": "EXECUTING", + "listClientOrderId": "amEEAXryFzFwYF1FeRpUoZ", + "transactionTime": 1565245913483, + "symbol": "LTCBTC", + "isIsolated": true, // if isolated margin + "orders": [ + { + "symbol": "LTCBTC", + "orderId": 4, + "clientOrderId": "oD7aesZqjEGlZrbtRpy5zB" + }, + { + "symbol": "LTCBTC", + "orderId": 5, + "clientOrderId": "Jr1h6xirOxgeJOUuYQS7V3" + } + ] + }, + { + "orderListId": 28, + "contingencyType": "OCO", + "listStatusType": "EXEC_STARTED", + "listOrderStatus": "EXECUTING", + "listClientOrderId": "hG7hFNxJV6cZy3Ze4AUT4d", + "transactionTime": 1565245913407, + "symbol": "LTCBTC", + "orders": [ + { + "symbol": "LTCBTC", + "orderId": 2, + "clientOrderId": "j6lFOfbmFMRjTYA7rRJ0LP" + }, + { + "symbol": "LTCBTC", + "orderId": 3, + "clientOrderId": "z0KCjOdditiLS5ekAFtK81" + } + ] + } + ] + + """ + return self._request_margin_api('get', 'margin/allOrderList', signed=True, data=params) + + # Cross-margin + + def margin_stream_get_listen_key(self): + """Start a new cross-margin data stream and return the listen key + If a stream already exists it should return the same key. + If the stream becomes invalid a new key is returned. + + Can be used to keep the stream alive. + + https://binance-docs.github.io/apidocs/spot/en/#listen-key-margin + + :returns: API response + + .. code-block:: python + + { + "listenKey": "pqia91ma19a5s61cv6a81va65sdf19v8a65a1a5s61cv6a81va65sdf19v8a65a1" + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + res = self._request_margin_api('post', 'userDataStream', signed=False, data={}) + return res['listenKey'] + + def margin_stream_keepalive(self, listenKey): + """PING a cross-margin data stream to prevent a time out. + + https://binance-docs.github.io/apidocs/spot/en/#listen-key-margin + + :param listenKey: required + :type listenKey: str + + :returns: API response + + .. code-block:: python + + {} + + :raises: BinanceRequestException, BinanceAPIException + + """ + params = { + 'listenKey': listenKey + } + return self._request_margin_api('put', 'userDataStream', signed=False, data=params) + + def margin_stream_close(self, listenKey): + """Close out a cross-margin data stream. + + https://binance-docs.github.io/apidocs/spot/en/#listen-key-margin + + :param listenKey: required + :type listenKey: str + + :returns: API response + + .. code-block:: python + + {} + + :raises: BinanceRequestException, BinanceAPIException + + """ + params = { + 'listenKey': listenKey + } + return self._request_margin_api('delete', 'userDataStream', signed=False, data=params) + + # Isolated margin + + def isolated_margin_stream_get_listen_key(self, symbol): + """Start a new isolated margin data stream and return the listen key + If a stream already exists it should return the same key. + If the stream becomes invalid a new key is returned. + + Can be used to keep the stream alive. + + https://binance-docs.github.io/apidocs/spot/en/#listen-key-isolated-margin + + :param symbol: required - symbol for the isolated margin account + :type symbol: str + + :returns: API response + + .. code-block:: python + + { + "listenKey": "T3ee22BIYuWqmvne0HNq2A2WsFlEtLhvWCtItw6ffhhdmjifQ2tRbuKkTHhr" + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + params = { + 'symbol': symbol + } + res = self._request_margin_api('post', 'userDataStream/isolated', signed=False, data=params) + return res['listenKey'] + + def isolated_margin_stream_keepalive(self, symbol, listenKey): + """PING an isolated margin data stream to prevent a time out. + + https://binance-docs.github.io/apidocs/spot/en/#listen-key-isolated-margin + + :param symbol: required - symbol for the isolated margin account + :type symbol: str + :param listenKey: required + :type listenKey: str + + :returns: API response + + .. code-block:: python + + {} + + :raises: BinanceRequestException, BinanceAPIException + + """ + params = { + 'symbol': symbol, + 'listenKey': listenKey + } + return self._request_margin_api('put', 'userDataStream/isolated', signed=False, data=params) + + def isolated_margin_stream_close(self, symbol, listenKey): + """Close out an isolated margin data stream. + + https://binance-docs.github.io/apidocs/spot/en/#listen-key-isolated-margin + + :param symbol: required - symbol for the isolated margin account + :type symbol: str + :param listenKey: required + :type listenKey: str + + :returns: API response + + .. code-block:: python + + {} + + :raises: BinanceRequestException, BinanceAPIException + + """ + params = { + 'symbol': symbol, + 'listenKey': listenKey + } + return self._request_margin_api('delete', 'userDataStream/isolated', signed=False, data=params) + + # Lending Endpoints + + def get_lending_product_list(self, **params): + """Get Lending Product List + + https://binance-docs.github.io/apidocs/spot/en/#get-flexible-product-list-user_data + + """ + return self._request_margin_api('get', 'lending/daily/product/list', signed=True, data=params) + + def get_lending_daily_quota_left(self, **params): + """Get Left Daily Purchase Quota of Flexible Product. + + https://binance-docs.github.io/apidocs/spot/en/#get-left-daily-purchase-quota-of-flexible-product-user_data + + """ + return self._request_margin_api('get', 'lending/daily/userLeftQuota', signed=True, data=params) + + def purchase_lending_product(self, **params): + """Purchase Flexible Product + + https://binance-docs.github.io/apidocs/spot/en/#purchase-flexible-product-user_data + + """ + return self._request_margin_api('post', 'lending/daily/purchase', signed=True, data=params) + + def get_lending_daily_redemption_quota(self, **params): + """Get Left Daily Redemption Quota of Flexible Product + + https://binance-docs.github.io/apidocs/spot/en/#get-left-daily-redemption-quota-of-flexible-product-user_data + + """ + return self._request_margin_api('get', 'lending/daily/userRedemptionQuota', signed=True, data=params) + + def redeem_lending_product(self, **params): + """Redeem Flexible Product + + https://binance-docs.github.io/apidocs/spot/en/#redeem-flexible-product-user_data + + """ + return self._request_margin_api('post', 'lending/daily/redeem', signed=True, data=params) + + def get_lending_position(self, **params): + """Get Flexible Product Position + + https://binance-docs.github.io/apidocs/spot/en/#get-flexible-product-position-user_data + + """ + return self._request_margin_api('get', 'lending/daily/token/position', signed=True, data=params) + + def get_fixed_activity_project_list(self, **params): + """Get Fixed and Activity Project List + + https://binance-docs.github.io/apidocs/spot/en/#get-fixed-and-activity-project-list-user_data + + :param asset: optional + :type asset: str + :param type: required - "ACTIVITY", "CUSTOMIZED_FIXED" + :type type: str + :param status: optional - "ALL", "SUBSCRIBABLE", "UNSUBSCRIBABLE"; default "ALL" + :type status: str + :param sortBy: optional - "START_TIME", "LOT_SIZE", "INTEREST_RATE", "DURATION"; default "START_TIME" + :type sortBy: str + :param current: optional - Currently querying page. Start from 1. Default:1 + :type current: int + :param size: optional - Default:10, Max:100 + :type size: int + :param recvWindow: the number of milliseconds the request is valid for + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + [ + { + "asset": "USDT", + "displayPriority": 1, + "duration": 90, + "interestPerLot": "1.35810000", + "interestRate": "0.05510000", + "lotSize": "100.00000000", + "lotsLowLimit": 1, + "lotsPurchased": 74155, + "lotsUpLimit": 80000, + "maxLotsPerUser": 2000, + "needKyc": False, + "projectId": "CUSDT90DAYSS001", + "projectName": "USDT", + "status": "PURCHASING", + "type": "CUSTOMIZED_FIXED", + "withAreaLimitation": False + } + ] + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'lending/project/list', signed=True, data=params) + + def get_lending_account(self, **params): + """Get Lending Account Details + + https://binance-docs.github.io/apidocs/spot/en/#lending-account-user_data + + """ + return self._request_margin_api('get', 'lending/union/account', signed=True, data=params) + + def get_lending_purchase_history(self, **params): + """Get Lending Purchase History + + https://binance-docs.github.io/apidocs/spot/en/#get-purchase-record-user_data + + """ + return self._request_margin_api('get', 'lending/union/purchaseRecord', signed=True, data=params) + + def get_lending_redemption_history(self, **params): + """Get Lending Redemption History + + https://binance-docs.github.io/apidocs/spot/en/#get-redemption-record-user_data + + """ + return self._request_margin_api('get', 'lending/union/redemptionRecord', signed=True, data=params) + + def get_lending_interest_history(self, **params): + """Get Lending Interest History + + https://binance-docs.github.io/apidocs/spot/en/#get-interest-history-user_data-2 + + """ + return self._request_margin_api('get', 'lending/union/interestHistory', signed=True, data=params) + + def change_fixed_activity_to_daily_position(self, **params): + """Change Fixed/Activity Position to Daily Position + + https://binance-docs.github.io/apidocs/spot/en/#change-fixed-activity-position-to-daily-position-user_data + + """ + return self._request_margin_api('post', 'lending/positionChanged', signed=True, data=params) + + # Sub Accounts + + def get_sub_account_list(self, **params): + """Query Sub-account List. + + https://binance-docs.github.io/apidocs/spot/en/#query-sub-account-list-sapi-for-master-account + + :param email: optional - Sub-account email + :type email: str + :param isFreeze: optional + :type isFreeze: str + :param page: optional - Default value: 1 + :type page: int + :param limit: optional - Default value: 1, Max value: 200 + :type limit: int + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "subAccounts":[ + { + "email":"testsub@gmail.com", + "isFreeze":false, + "createTime":1544433328000 + }, + { + "email":"virtual@oxebmvfonoemail.com", + "isFreeze":false, + "createTime":1544433328000 + } + ] + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'sub-account/list', True, data=params) + + def get_sub_account_transfer_history(self, **params): + """Query Sub-account Transfer History. + + https://binance-docs.github.io/apidocs/spot/en/#query-sub-account-spot-asset-transfer-history-sapi-for-master-account + + :param fromEmail: optional + :type fromEmail: str + :param toEmail: optional + :type toEmail: str + :param startTime: optional + :type startTime: int + :param endTime: optional + :type endTime: int + :param page: optional - Default value: 1 + :type page: int + :param limit: optional - Default value: 500 + :type limit: int + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + [ + { + "from":"aaa@test.com", + "to":"bbb@test.com", + "asset":"BTC", + "qty":"10", + "status": "SUCCESS", + "tranId": 6489943656, + "time":1544433328000 + }, + { + "from":"bbb@test.com", + "to":"ccc@test.com", + "asset":"ETH", + "qty":"2", + "status": "SUCCESS", + "tranId": 6489938713, + "time":1544433328000 + } + ] + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'sub-account/sub/transfer/history', True, data=params) + + def get_sub_account_futures_transfer_history(self, **params): + """Query Sub-account Futures Transfer History. + + https://binance-docs.github.io/apidocs/spot/en/#query-sub-account-futures-asset-transfer-history-for-master-account + + :param email: required + :type email: str + :param futuresType: required + :type futuresType: int + :param startTime: optional + :type startTime: int + :param endTime: optional + :type endTime: int + :param page: optional + :type page: int + :param limit: optional + :type limit: int + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "success":true, + "futuresType": 2, + "transfers":[ + { + "from":"aaa@test.com", + "to":"bbb@test.com", + "asset":"BTC", + "qty":"1", + "time":1544433328000 + }, + { + "from":"bbb@test.com", + "to":"ccc@test.com", + "asset":"ETH", + "qty":"2", + "time":1544433328000 + } + ] + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'sub-account/futures/internalTransfer', True, data=params) + + def create_sub_account_futures_transfer(self, **params): + """Execute sub-account Futures transfer + + https://github.com/binance-exchange/binance-official-api-docs/blob/9dbe0e961b80557bb19708a707c7fad08842b28e/wapi-api.md#sub-account-transferfor-master-account + + :param fromEmail: required - Sender email + :type fromEmail: str + :param toEmail: required - Recipient email + :type toEmail: str + :param futuresType: required + :type futuresType: int + :param asset: required + :type asset: str + :param amount: required + :type amount: decimal + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "success":true, + "txnId":"2934662589" + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('post', 'sub-account/futures/internalTransfer', True, data=params) + + def get_sub_account_assets(self, **params): + """Fetch sub-account assets + + https://binance-docs.github.io/apidocs/spot/en/#query-sub-account-assets-sapi-for-master-account + + :param email: required + :type email: str + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "balances":[ + { + "asset":"ADA", + "free":10000, + "locked":0 + }, + { + "asset":"BNB", + "free":10003, + "locked":0 + }, + { + "asset":"BTC", + "free":11467.6399, + "locked":0 + }, + { + "asset":"ETH", + "free":10004.995, + "locked":0 + }, + { + "asset":"USDT", + "free":11652.14213, + "locked":0 + } + ] + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'sub-account/assets', True, data=params) + + def query_subaccount_spot_summary(self, **params): + """Query Sub-account Spot Assets Summary (For Master Account) + + https://binance-docs.github.io/apidocs/spot/en/#query-sub-account-spot-assets-summary-for-master-account + + :param email: optional - Sub account email + :type email: str + :param page: optional - default 1 + :type page: int + :param size: optional - default 10, max 20 + :type size: int + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "totalCount":2, + "masterAccountTotalAsset": "0.23231201", + "spotSubUserAssetBtcVoList":[ + { + "email":"sub123@test.com", + "totalAsset":"9999.00000000" + }, + { + "email":"test456@test.com", + "totalAsset":"0.00000000" + } + ] + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'sub-account/spotSummary', True, data=params) + + def get_subaccount_deposit_address(self, **params): + """Get Sub-account Deposit Address (For Master Account) + + https://binance-docs.github.io/apidocs/spot/en/#get-sub-account-deposit-address-for-master-account + + :param email: required - Sub account email + :type email: str + :param coin: required + :type coin: str + :param network: optional + :type network: str + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "address":"TDunhSa7jkTNuKrusUTU1MUHtqXoBPKETV", + "coin":"USDT", + "tag":"", + "url":"https://tronscan.org/#/address/TDunhSa7jkTNuKrusUTU1MUHtqXoBPKETV" + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'capital/deposit/subAddress', True, data=params) + + def get_subaccount_deposit_history(self, **params): + """Get Sub-account Deposit History (For Master Account) + + https://binance-docs.github.io/apidocs/spot/en/#get-sub-account-deposit-address-for-master-account + + :param email: required - Sub account email + :type email: str + :param coin: optional + :type coin: str + :param status: optional - (0:pending,6: credited but cannot withdraw, 1:success) + :type status: int + :param startTime: optional + :type startTime: int + :param endTime: optional + :type endTime: int + :param limit: optional + :type limit: int + :param offset: optional - default:0 + :type offset: int + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + [ + { + "amount":"0.00999800", + "coin":"PAXG", + "network":"ETH", + "status":1, + "address":"0x788cabe9236ce061e5a892e1a59395a81fc8d62c", + "addressTag":"", + "txId":"0xaad4654a3234aa6118af9b4b335f5ae81c360b2394721c019b5d1e75328b09f3", + "insertTime":1599621997000, + "transferType":0, + "confirmTimes":"12/12" + }, + { + "amount":"0.50000000", + "coin":"IOTA", + "network":"IOTA", + "status":1, + "address":"SIZ9VLMHWATXKV99LH99CIGFJFUMLEHGWVZVNNZXRJJVWBPHYWPPBOSDORZ9EQSHCZAMPVAPGFYQAUUV9DROOXJLNW", + "addressTag":"", + "txId":"ESBFVQUTPIWQNJSPXFNHNYHSQNTGKRVKPRABQWTAXCDWOAKDKYWPTVG9BGXNVNKTLEJGESAVXIKIZ9999", + "insertTime":1599620082000, + "transferType":0, + "confirmTimes":"1/1" + } + ] + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'capital/deposit/subHisrec', True, data=params) + + def get_subaccount_futures_margin_status(self, **params): + """Get Sub-account's Status on Margin/Futures (For Master Account) + + https://binance-docs.github.io/apidocs/spot/en/#get-sub-account-39-s-status-on-margin-futures-for-master-account + + :param email: optional - Sub account email + :type email: str + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + [ + { + "email":"123@test.com", // user email + "isSubUserEnabled": true, // true or false + "isUserActive": true, // true or false + "insertTime": 1570791523523 // sub account create time + "isMarginEnabled": true, // true or false for margin + "isFutureEnabled": true // true or false for futures. + "mobile": 1570791523523 // user mobile number + } + ] + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'sub-account/status', True, data=params) + + def enable_subaccount_margin(self, **params): + """Enable Margin for Sub-account (For Master Account) + + https://binance-docs.github.io/apidocs/spot/en/#enable-margin-for-sub-account-for-master-account + + :param email: required - Sub account email + :type email: str + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + + "email":"123@test.com", + + "isMarginEnabled": true + + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('post', 'sub-account/margin/enable', True, data=params) + + def get_subaccount_margin_details(self, **params): + """Get Detail on Sub-account's Margin Account (For Master Account) + + https://binance-docs.github.io/apidocs/spot/en/#get-detail-on-sub-account-39-s-margin-account-for-master-account + + :param email: required - Sub account email + :type email: str + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "email":"123@test.com", + "marginLevel": "11.64405625", + "totalAssetOfBtc": "6.82728457", + "totalLiabilityOfBtc": "0.58633215", + "totalNetAssetOfBtc": "6.24095242", + "marginTradeCoeffVo": + { + "forceLiquidationBar": "1.10000000", // Liquidation margin ratio + "marginCallBar": "1.50000000", // Margin call margin ratio + "normalBar": "2.00000000" // Initial margin ratio + }, + "marginUserAssetVoList": [ + { + "asset": "BTC", + "borrowed": "0.00000000", + "free": "0.00499500", + "interest": "0.00000000", + "locked": "0.00000000", + "netAsset": "0.00499500" + }, + { + "asset": "BNB", + "borrowed": "201.66666672", + "free": "2346.50000000", + "interest": "0.00000000", + "locked": "0.00000000", + "netAsset": "2144.83333328" + }, + { + "asset": "ETH", + "borrowed": "0.00000000", + "free": "0.00000000", + "interest": "0.00000000", + "locked": "0.00000000", + "netAsset": "0.00000000" + }, + { + "asset": "USDT", + "borrowed": "0.00000000", + "free": "0.00000000", + "interest": "0.00000000", + "locked": "0.00000000", + "netAsset": "0.00000000" + } + ] + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'sub-account/margin/account', True, data=params) + + def get_subaccount_margin_summary(self, **params): + """Get Summary of Sub-account's Margin Account (For Master Account) + + https://binance-docs.github.io/apidocs/spot/en/#get-summary-of-sub-account-39-s-margin-account-for-master-account + + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "totalAssetOfBtc": "4.33333333", + "totalLiabilityOfBtc": "2.11111112", + "totalNetAssetOfBtc": "2.22222221", + "subAccountList":[ + { + "email":"123@test.com", + "totalAssetOfBtc": "2.11111111", + "totalLiabilityOfBtc": "1.11111111", + "totalNetAssetOfBtc": "1.00000000" + }, + { + "email":"345@test.com", + "totalAssetOfBtc": "2.22222222", + "totalLiabilityOfBtc": "1.00000001", + "totalNetAssetOfBtc": "1.22222221" + } + ] + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'sub-account/margin/accountSummary', True, data=params) + + def enable_subaccount_futures(self, **params): + """Enable Futures for Sub-account (For Master Account) + + https://binance-docs.github.io/apidocs/spot/en/#enable-futures-for-sub-account-for-master-account + + :param email: required - Sub account email + :type email: str + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + + "email":"123@test.com", + + "isFuturesEnabled": true // true or false + + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('post', 'sub-account/futures/enable', True, data=params) + + def get_subaccount_futures_details(self, **params): + """Get Detail on Sub-account's Futures Account (For Master Account) + + https://binance-docs.github.io/apidocs/spot/en/#get-detail-on-sub-account-39-s-futures-account-for-master-account + + :param email: required - Sub account email + :type email: str + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "email": "abc@test.com", + "asset": "USDT", + "assets":[ + { + "asset": "USDT", + "initialMargin": "0.00000000", + "maintenanceMargin": "0.00000000", + "marginBalance": "0.88308000", + "maxWithdrawAmount": "0.88308000", + "openOrderInitialMargin": "0.00000000", + "positionInitialMargin": "0.00000000", + "unrealizedProfit": "0.00000000", + "walletBalance": "0.88308000" + } + ], + "canDeposit": true, + "canTrade": true, + "canWithdraw": true, + "feeTier": 2, + "maxWithdrawAmount": "0.88308000", + "totalInitialMargin": "0.00000000", + "totalMaintenanceMargin": "0.00000000", + "totalMarginBalance": "0.88308000", + "totalOpenOrderInitialMargin": "0.00000000", + "totalPositionInitialMargin": "0.00000000", + "totalUnrealizedProfit": "0.00000000", + "totalWalletBalance": "0.88308000", + "updateTime": 1576756674610 + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'sub-account/futures/account', True, data=params) + + def get_subaccount_futures_summary(self, **params): + """Get Summary of Sub-account's Futures Account (For Master Account) + + https://binance-docs.github.io/apidocs/spot/en/#get-summary-of-sub-account-39-s-futures-account-for-master-account + + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "totalInitialMargin": "9.83137400", + "totalMaintenanceMargin": "0.41568700", + "totalMarginBalance": "23.03235621", + "totalOpenOrderInitialMargin": "9.00000000", + "totalPositionInitialMargin": "0.83137400", + "totalUnrealizedProfit": "0.03219710", + "totalWalletBalance": "22.15879444", + "asset": "USDT", + "subAccountList":[ + { + "email": "123@test.com", + "totalInitialMargin": "9.00000000", + "totalMaintenanceMargin": "0.00000000", + "totalMarginBalance": "22.12659734", + "totalOpenOrderInitialMargin": "9.00000000", + "totalPositionInitialMargin": "0.00000000", + "totalUnrealizedProfit": "0.00000000", + "totalWalletBalance": "22.12659734", + "asset": "USDT" + }, + { + "email": "345@test.com", + "totalInitialMargin": "0.83137400", + "totalMaintenanceMargin": "0.41568700", + "totalMarginBalance": "0.90575887", + "totalOpenOrderInitialMargin": "0.00000000", + "totalPositionInitialMargin": "0.83137400", + "totalUnrealizedProfit": "0.03219710", + "totalWalletBalance": "0.87356177", + "asset": "USDT" + } + ] + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'sub-account/futures/accountSummary', True, data=params) + + def get_subaccount_futures_positionrisk(self, **params): + """Get Futures Position-Risk of Sub-account (For Master Account) + + https://binance-docs.github.io/apidocs/spot/en/#get-futures-position-risk-of-sub-account-for-master-account + + :param email: required - Sub account email + :type email: str + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + [ + { + "entryPrice": "9975.12000", + "leverage": "50", // current initial leverage + "maxNotional": "1000000", // notional value limit of current initial leverage + "liquidationPrice": "7963.54", + "markPrice": "9973.50770517", + "positionAmount": "0.010", + "symbol": "BTCUSDT", + "unrealizedProfit": "-0.01612295" + } + ] + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'sub-account/futures/positionRisk', True, data=params) + + def make_subaccount_futures_transfer(self, **params): + """Futures Transfer for Sub-account (For Master Account) + + https://binance-docs.github.io/apidocs/spot/en/#futures-transfer-for-sub-account-for-master-account + + :param email: required - Sub account email + :type email: str + :param asset: required - The asset being transferred, e.g., USDT + :type asset: str + :param amount: required - The amount to be transferred + :type amount: float + :param type: required - 1: transfer from subaccount's spot account to its USDT-margined futures account + 2: transfer from subaccount's USDT-margined futures account to its spot account + 3: transfer from subaccount's spot account to its COIN-margined futures account + 4: transfer from subaccount's COIN-margined futures account to its spot account + :type type: int + + :returns: API response + + .. code-block:: python + + { + "txnId":"2966662589" + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('post', 'sub-account/futures/transfer', True, data=params) + + def make_subaccount_margin_transfer(self, **params): + """Margin Transfer for Sub-account (For Master Account) + + https://binance-docs.github.io/apidocs/spot/en/#margin-transfer-for-sub-account-for-master-account + + :param email: required - Sub account email + :type email: str + :param asset: required - The asset being transferred, e.g., USDT + :type asset: str + :param amount: required - The amount to be transferred + :type amount: float + :param type: required - 1: transfer from subaccount's spot account to margin account + 2: transfer from subaccount's margin account to its spot account + :type type: int + + :returns: API response + + .. code-block:: python + + { + "txnId":"2966662589" + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('post', 'sub-account/margin/transfer', True, data=params) + + def make_subaccount_to_subaccount_transfer(self, **params): + """Transfer to Sub-account of Same Master (For Sub-account) + + https://binance-docs.github.io/apidocs/spot/en/#transfer-to-sub-account-of-same-master-for-sub-account + + :param toEmail: required - Sub account email + :type toEmail: str + :param asset: required - The asset being transferred, e.g., USDT + :type asset: str + :param amount: required - The amount to be transferred + :type amount: float + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "txnId":"2966662589" + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('post', 'sub-account/transfer/subToSub', True, data=params) + + def make_subaccount_to_master_transfer(self, **params): + """Transfer to Master (For Sub-account) + + https://binance-docs.github.io/apidocs/spot/en/#transfer-to-master-for-sub-account + + :param asset: required - The asset being transferred, e.g., USDT + :type asset: str + :param amount: required - The amount to be transferred + :type amount: float + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "txnId":"2966662589" + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('post', 'sub-account/transfer/subToMaster', True, data=params) + + def get_subaccount_transfer_history(self, **params): + """Sub-account Transfer History (For Sub-account) + + https://binance-docs.github.io/apidocs/spot/en/#transfer-to-master-for-sub-account + + :param asset: required - The asset being transferred, e.g., USDT + :type asset: str + :param type: optional - 1: transfer in, 2: transfer out + :type type: int + :param startTime: optional + :type startTime: int + :param endTime: optional + :type endTime: int + :param limit: optional - Default 500 + :type limit: int + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + [ + { + "counterParty":"master", + "email":"master@test.com", + "type":1, // 1 for transfer in, 2 for transfer out + "asset":"BTC", + "qty":"1", + "status":"SUCCESS", + "tranId":11798835829, + "time":1544433325000 + }, + { + "counterParty":"subAccount", + "email":"sub2@test.com", + "type":2, + "asset":"ETH", + "qty":"2", + "status":"SUCCESS", + "tranId":11798829519, + "time":1544433326000 + } + ] + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'sub-account/transfer/subUserHistory', True, data=params) + + def make_subaccount_universal_transfer(self, **params): + """Universal Transfer (For Master Account) + + https://binance-docs.github.io/apidocs/spot/en/#universal-transfer-for-master-account + + :param fromEmail: optional + :type fromEmail: str + :param toEmail: optional + :type toEmail: str + :param fromAccountType: required - "SPOT","USDT_FUTURE","COIN_FUTURE" + :type fromAccountType: str + :param toAccountType: required - "SPOT","USDT_FUTURE","COIN_FUTURE" + :type toAccountType: str + :param asset: required - The asset being transferred, e.g., USDT + :type asset: str + :param amount: required + :type amount: float + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "tranId":11945860693 + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('post', 'sub-account/universalTransfer', True, data=params) + + def get_universal_transfer_history(self, **params): + """Universal Transfer (For Master Account) + + https://binance-docs.github.io/apidocs/spot/en/#query-universal-transfer-history + + :param fromEmail: optional + :type fromEmail: str + :param toEmail: optional + :type toEmail: str + :param startTime: optional + :type startTime: int + :param endTime: optional + :type endTime: int + :param page: optional + :type page: int + :param limit: optional + :type limit: int + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + [ + { + "tranId":11945860693, + "fromEmail":"master@test.com", + "toEmail":"subaccount1@test.com", + "asset":"BTC", + "amount":"0.1", + "fromAccountType":"SPOT", + "toAccountType":"COIN_FUTURE", + "status":"SUCCESS", + "createTimeStamp":1544433325000 + }, + { + "tranId":11945857955, + "fromEmail":"master@test.com", + "toEmail":"subaccount2@test.com", + "asset":"ETH", + "amount":"0.2", + "fromAccountType":"SPOT", + "toAccountType":"USDT_FUTURE", + "status":"SUCCESS", + "createTimeStamp":1544433326000 + } + ] + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'sub-account/universalTransfer', True, data=params) + + # Futures API + + def futures_ping(self): + """Test connectivity to the Rest API + + https://binance-docs.github.io/apidocs/futures/en/#test-connectivity + + """ + return self._request_futures_api('get', 'ping') + + def futures_time(self): + """Test connectivity to the Rest API and get the current server time. + + https://binance-docs.github.io/apidocs/futures/en/#check-server-time + + """ + return self._request_futures_api('get', 'time') + + def futures_exchange_info(self): + """Current exchange trading rules and symbol information + + https://binance-docs.github.io/apidocs/futures/en/#exchange-information-market_data + + """ + return self._request_futures_api('get', 'exchangeInfo') + + def futures_order_book(self, **params): + """Get the Order Book for the market + + https://binance-docs.github.io/apidocs/futures/en/#order-book-market_data + + """ + return self._request_futures_api('get', 'depth', data=params) + + def futures_recent_trades(self, **params): + """Get recent trades (up to last 500). + + https://binance-docs.github.io/apidocs/futures/en/#recent-trades-list-market_data + + """ + return self._request_futures_api('get', 'trades', data=params) + + def futures_historical_trades(self, **params): + """Get older market historical trades. + + https://binance-docs.github.io/apidocs/futures/en/#old-trades-lookup-market_data + + """ + return self._request_futures_api('get', 'historicalTrades', data=params) + + def futures_aggregate_trades(self, **params): + """Get compressed, aggregate trades. Trades that fill at the time, from the same order, with the same + price will have the quantity aggregated. + + https://binance-docs.github.io/apidocs/futures/en/#compressed-aggregate-trades-list-market_data + + """ + return self._request_futures_api('get', 'aggTrades', data=params) + + def futures_klines(self, **params): + """Kline/candlestick bars for a symbol. Klines are uniquely identified by their open time. + + https://binance-docs.github.io/apidocs/futures/en/#kline-candlestick-data-market_data + + """ + return self._request_futures_api('get', 'klines', data=params) + + def futures_continous_klines(self, **params): + """Kline/candlestick bars for a specific contract type. Klines are uniquely identified by their open time. + + https://binance-docs.github.io/apidocs/futures/en/#continuous-contract-kline-candlestick-data + + """ + return self._request_futures_api('get', 'continuousKlines', data=params) + + def futures_historical_klines(self, symbol, interval, start_str, end_str=None, limit=500): + """Get historical futures klines from Binance + + :param symbol: Name of symbol pair e.g BNBBTC + :type symbol: str + :param interval: Binance Kline interval + :type interval: str + :param start_str: Start date string in UTC format or timestamp in milliseconds + :type start_str: str|int + :param end_str: optional - end date string in UTC format or timestamp in milliseconds (default will fetch everything up to now) + :type end_str: str|int + :param limit: Default 500; max 1000. + :type limit: int + + :return: list of OHLCV values + + """ + return self._historical_klines(symbol, interval, start_str, end_str=end_str, limit=limit, klines_type=HistoricalKlinesType.FUTURES) + + def futures_historical_klines_generator(self, symbol, interval, start_str, end_str=None): + """Get historical futures klines generator from Binance + + :param symbol: Name of symbol pair e.g BNBBTC + :type symbol: str + :param interval: Binance Kline interval + :type interval: str + :param start_str: Start date string in UTC format or timestamp in milliseconds + :type start_str: str|int + :param end_str: optional - end date string in UTC format or timestamp in milliseconds (default will fetch everything up to now) + :type end_str: str|int + + :return: generator of OHLCV values + + """ + + return self._historical_klines_generator(symbol, interval, start_str, end_str=end_str, klines_type=HistoricalKlinesType.FUTURES) + + def futures_mark_price(self, **params): + """Get Mark Price and Funding Rate + + https://binance-docs.github.io/apidocs/futures/en/#mark-price-market_data + + """ + return self._request_futures_api('get', 'premiumIndex', data=params) + + def futures_funding_rate(self, **params): + """Get funding rate history + + https://binance-docs.github.io/apidocs/futures/en/#get-funding-rate-history-market_data + + """ + return self._request_futures_api('get', 'fundingRate', data=params) + + def futures_top_longshort_account_ratio(self, **params): + """Get present long to short ratio for top accounts of a specific symbol. + + https://binance-docs.github.io/apidocs/futures/en/#top-trader-long-short-ratio-accounts-market_data + """ + return self._request_futures_data_api('get', 'topLongShortAccountRatio', data=params) + + def futures_top_longshort_position_ratio(self, **params): + """Get present long to short ratio for top positions of a specific symbol. + + https://binance-docs.github.io/apidocs/futures/en/#top-trader-long-short-ratio-positions + """ + return self._request_futures_data_api('get', 'topLongShortPositionRatio', data=params) + + def futures_global_longshort_ratio(self, **params): + """Get present global long to short ratio of a specific symbol. + + https://binance-docs.github.io/apidocs/futures/en/#long-short-ratio + """ + return self._request_futures_data_api('get', 'globalLongShortAccountRatio', data=params) + + def futures_ticker(self, **params): + """24 hour rolling window price change statistics. + + https://binance-docs.github.io/apidocs/futures/en/#24hr-ticker-price-change-statistics-market_data + + """ + return self._request_futures_api('get', 'ticker/24hr', data=params) + + def futures_symbol_ticker(self, **params): + """Latest price for a symbol or symbols. + + https://binance-docs.github.io/apidocs/futures/en/#symbol-price-ticker-market_data + + """ + return self._request_futures_api('get', 'ticker/price', data=params) + + def futures_orderbook_ticker(self, **params): + """Best price/qty on the order book for a symbol or symbols. + + https://binance-docs.github.io/apidocs/futures/en/#symbol-order-book-ticker-market_data + + """ + return self._request_futures_api('get', 'ticker/bookTicker', data=params) + + def futures_liquidation_orders(self, **params): + """Get all liquidation orders + + https://binance-docs.github.io/apidocs/futures/en/#get-all-liquidation-orders-market_data + + """ + return self._request_futures_api('get', 'forceOrders', signed=True, data=params) + + def futures_adl_quantile_estimate(self, **params): + """Get Position ADL Quantile Estimate + + https://binance-docs.github.io/apidocs/futures/en/#position-adl-quantile-estimation-user_data + + """ + return self._request_futures_api('get', 'adlQuantile', signed=True, data=params) + + def futures_open_interest(self, **params): + """Get present open interest of a specific symbol. + + https://binance-docs.github.io/apidocs/futures/en/#open-interest + + """ + return self._request_futures_api('get', 'openInterest', data=params) + + def futures_open_interest_hist(self, **params): + """Get open interest statistics of a specific symbol. + + https://binance-docs.github.io/apidocs/futures/en/#open-interest-statistics + + """ + return self._request_futures_data_api('get', 'openInterestHist', data=params) + + def futures_leverage_bracket(self, **params): + """Notional and Leverage Brackets + + https://binance-docs.github.io/apidocs/futures/en/#notional-and-leverage-brackets-market_data + + """ + return self._request_futures_api('get', 'leverageBracket', True, data=params) + + def futures_account_transfer(self, **params): + """Execute transfer between spot account and futures account. + + https://binance-docs.github.io/apidocs/futures/en/#new-future-account-transfer + + """ + return self._request_margin_api('post', 'futures/transfer', True, data=params) + + def transfer_history(self, **params): + """Get future account transaction history list + + https://binance-docs.github.io/apidocs/futures/en/#get-future-account-transaction-history-list-user_data + + """ + return self._request_margin_api('get', 'futures/transfer', True, data=params) + + def futures_create_order(self, **params): + """Send in a new order. + + https://binance-docs.github.io/apidocs/futures/en/#new-order-trade + + """ + return self._request_futures_api('post', 'order', True, data=params) + + def futures_place_batch_order(self, **params): + """Send in new orders. + + https://binance-docs.github.io/apidocs/futures/en/#place-multiple-orders-trade + + To avoid modifying the existing signature generation and parameter order logic, + the url encoding is done on the special query param, batchOrders, in the early stage. + + """ + query_string = urlencode(params) + query_string = query_string.replace('%27', '%22') + params['batchOrders'] = query_string[12:] + return self._request_futures_api('post', 'batchOrders', True, data=params) + + def futures_get_order(self, **params): + """Check an order's status. + + https://binance-docs.github.io/apidocs/futures/en/#query-order-user_data + + """ + return self._request_futures_api('get', 'order', True, data=params) + + def futures_get_open_orders(self, **params): + """Get all open orders on a symbol. + + https://binance-docs.github.io/apidocs/futures/en/#current-open-orders-user_data + + """ + return self._request_futures_api('get', 'openOrders', True, data=params) + + def futures_get_all_orders(self, **params): + """Get all futures account orders; active, canceled, or filled. + + https://binance-docs.github.io/apidocs/futures/en/#all-orders-user_data + + """ + return self._request_futures_api('get', 'allOrders', True, data=params) + + def futures_cancel_order(self, **params): + """Cancel an active futures order. + + https://binance-docs.github.io/apidocs/futures/en/#cancel-order-trade + + """ + return self._request_futures_api('delete', 'order', True, data=params) + + def futures_cancel_all_open_orders(self, **params): + """Cancel all open futures orders + + https://binance-docs.github.io/apidocs/futures/en/#cancel-all-open-orders-trade + + """ + return self._request_futures_api('delete', 'allOpenOrders', True, data=params) + + def futures_cancel_orders(self, **params): + """Cancel multiple futures orders + + https://binance-docs.github.io/apidocs/futures/en/#cancel-multiple-orders-trade + + """ + return self._request_futures_api('delete', 'batchOrders', True, data=params) + + def futures_account_balance(self, **params): + """Get futures account balance + + https://binance-docs.github.io/apidocs/futures/en/#future-account-balance-user_data + + """ + return self._request_futures_api('get', 'balance', True, data=params) + + def futures_account(self, **params): + """Get current account information. + + https://binance-docs.github.io/apidocs/futures/en/#account-information-user_data + + """ + return self._request_futures_api('get', 'account', True, data=params) + + def futures_change_leverage(self, **params): + """Change user's initial leverage of specific symbol market + + https://binance-docs.github.io/apidocs/futures/en/#change-initial-leverage-trade + + """ + return self._request_futures_api('post', 'leverage', True, data=params) + + def futures_change_margin_type(self, **params): + """Change the margin type for a symbol + + https://binance-docs.github.io/apidocs/futures/en/#change-margin-type-trade + + """ + return self._request_futures_api('post', 'marginType', True, data=params) + + def futures_change_position_margin(self, **params): + """Change the position margin for a symbol + + https://binance-docs.github.io/apidocs/futures/en/#modify-isolated-position-margin-trade + + """ + return self._request_futures_api('post', 'positionMargin', True, data=params) + + def futures_position_margin_history(self, **params): + """Get position margin change history + + https://binance-docs.github.io/apidocs/futures/en/#get-postion-margin-change-history-trade + + """ + return self._request_futures_api('get', 'positionMargin/history', True, data=params) + + def futures_position_information(self, **params): + """Get position information + + https://binance-docs.github.io/apidocs/futures/en/#position-information-user_data + + """ + return self._request_futures_api('get', 'positionRisk', True, data=params) + + def futures_account_trades(self, **params): + """Get trades for the authenticated account and symbol. + + https://binance-docs.github.io/apidocs/futures/en/#account-trade-list-user_data + + """ + return self._request_futures_api('get', 'userTrades', True, data=params) + + def futures_income_history(self, **params): + """Get income history for authenticated account + + https://binance-docs.github.io/apidocs/futures/en/#get-income-history-user_data + + """ + return self._request_futures_api('get', 'income', True, data=params) + + def futures_change_position_mode(self, **params): + """Change position mode for authenticated account + + https://binance-docs.github.io/apidocs/futures/en/#change-position-mode-trade + + """ + return self._request_futures_api('post', 'positionSide/dual', True, data=params) + + def futures_get_position_mode(self, **params): + """Get position mode for authenticated account + + https://binance-docs.github.io/apidocs/futures/en/#get-current-position-mode-user_data + + """ + return self._request_futures_api('get', 'positionSide/dual', True, data=params) + + def futures_change_multi_assets_mode(self, multiAssetsMargin: bool): + """Change user's Multi-Assets mode (Multi-Assets Mode or Single-Asset Mode) on Every symbol + + https://binance-docs.github.io/apidocs/futures/en/#change-multi-assets-mode-trade + + """ + params = { + 'true' if multiAssetsMargin else 'false' + } + return self._request_futures_api('post', 'multiAssetsMargin', True, data=params) + + def futures_get_multi_assets_mode(self): + """Get user's Multi-Assets mode (Multi-Assets Mode or Single-Asset Mode) on Every symbol + + https://binance-docs.github.io/apidocs/futures/en/#get-current-multi-assets-mode-user_data + + """ + return self._request_futures_api('get', 'multiAssetsMargin', True) + + def futures_stream_get_listen_key(self): + res = self._request_futures_api('post', 'listenKey', signed=False, data={}) + return res['listenKey'] + + def futures_stream_keepalive(self, listenKey): + params = { + 'listenKey': listenKey + } + return self._request_futures_api('put', 'listenKey', signed=False, data=params) + + def futures_stream_close(self, listenKey): + params = { + 'listenKey': listenKey + } + return self._request_futures_api('delete', 'listenKey', signed=False, data=params) + + # COIN Futures API + def futures_coin_ping(self): + """Test connectivity to the Rest API + + https://binance-docs.github.io/apidocs/delivery/en/#test-connectivity + + """ + return self._request_futures_coin_api("get", "ping") + + def futures_coin_time(self): + """Test connectivity to the Rest API and get the current server time. + + https://binance-docs.github.io/apidocs/delivery/en/#check-server-time + + """ + return self._request_futures_coin_api("get", "time") + + def futures_coin_exchange_info(self): + """Current exchange trading rules and symbol information + + https://binance-docs.github.io/apidocs/delivery/en/#exchange-information + + """ + return self._request_futures_coin_api("get", "exchangeInfo") + + def futures_coin_order_book(self, **params): + """Get the Order Book for the market + + https://binance-docs.github.io/apidocs/delivery/en/#order-book + + """ + return self._request_futures_coin_api("get", "depth", data=params) + + def futures_coin_recent_trades(self, **params): + """Get recent trades (up to last 500). + + https://binance-docs.github.io/apidocs/delivery/en/#recent-trades-list + + """ + return self._request_futures_coin_api("get", "trades", data=params) + + def futures_coin_historical_trades(self, **params): + """Get older market historical trades. + + https://binance-docs.github.io/apidocs/delivery/en/#old-trades-lookup-market_data + + """ + return self._request_futures_coin_api("get", "historicalTrades", data=params) + + def futures_coin_aggregate_trades(self, **params): + """Get compressed, aggregate trades. Trades that fill at the time, from the same order, with the same + price will have the quantity aggregated. + + https://binance-docs.github.io/apidocs/delivery/en/#compressed-aggregate-trades-list + + """ + return self._request_futures_coin_api("get", "aggTrades", data=params) + + def futures_coin_klines(self, **params): + """Kline/candlestick bars for a symbol. Klines are uniquely identified by their open time. + + https://binance-docs.github.io/apidocs/delivery/en/#kline-candlestick-data + + """ + return self._request_futures_coin_api("get", "klines", data=params) + + def futures_coin_continous_klines(self, **params): + """Kline/candlestick bars for a specific contract type. Klines are uniquely identified by their open time. + + https://binance-docs.github.io/apidocs/delivery/en/#continuous-contract-kline-candlestick-data + + """ + return self._request_futures_coin_api("get", "continuousKlines", data=params) + + def futures_coin_index_price_klines(self, **params): + """Kline/candlestick bars for the index price of a pair.. + + https://binance-docs.github.io/apidocs/delivery/en/#index-price-kline-candlestick-data + + """ + return self._request_futures_coin_api("get", "indexPriceKlines", data=params) + + def futures_coin_mark_price_klines(self, **params): + """Kline/candlestick bars for the index price of a pair.. + + https://binance-docs.github.io/apidocs/delivery/en/#mark-price-kline-candlestick-data + + """ + return self._request_futures_coin_api("get", "markPriceKlines", data=params) + + def futures_coin_mark_price(self, **params): + """Get Mark Price and Funding Rate + + https://binance-docs.github.io/apidocs/delivery/en/#index-price-and-mark-price + + """ + return self._request_futures_coin_api("get", "premiumIndex", data=params) + + def futures_coin_funding_rate(self, **params): + """Get funding rate history + + https://binance-docs.github.io/apidocs/delivery/en/#get-funding-rate-history-of-perpetual-futures + + """ + return self._request_futures_coin_api("get", "fundingRate", data=params) + + def futures_coin_ticker(self, **params): + """24 hour rolling window price change statistics. + + https://binance-docs.github.io/apidocs/delivery/en/#24hr-ticker-price-change-statistics + + """ + return self._request_futures_coin_api("get", "ticker/24hr", data=params) + + def futures_coin_symbol_ticker(self, **params): + """Latest price for a symbol or symbols. + + https://binance-docs.github.io/apidocs/delivery/en/#symbol-price-ticker + + """ + return self._request_futures_coin_api("get", "ticker/price", data=params) + + def futures_coin_orderbook_ticker(self, **params): + """Best price/qty on the order book for a symbol or symbols. + + https://binance-docs.github.io/apidocs/delivery/en/#symbol-order-book-ticker + + """ + return self._request_futures_coin_api("get", "ticker/bookTicker", data=params) + + def futures_coin_liquidation_orders(self, **params): + """Get all liquidation orders + + https://binance-docs.github.io/apidocs/delivery/en/#user-39-s-force-orders-user_data + + """ + return self._request_futures_coin_api("get", "forceOrders", signed=True, data=params) + + def futures_coin_open_interest(self, **params): + """Get present open interest of a specific symbol. + + https://binance-docs.github.io/apidocs/delivery/en/#open-interest + + """ + return self._request_futures_coin_api("get", "openInterest", data=params) + + def futures_coin_open_interest_hist(self, **params): + """Get open interest statistics of a specific symbol. + + https://binance-docs.github.io/apidocs/delivery/en/#open-interest-statistics-market-data + + """ + return self._request_futures_coin_data_api("get", "openInterestHist", data=params) + + def futures_coin_leverage_bracket(self, **params): + """Notional and Leverage Brackets + + https://binance-docs.github.io/apidocs/delivery/en/#notional-bracket-for-pair-user_data + + """ + return self._request_futures_coin_api( + "get", "leverageBracket", version=2, signed=True, data=params + ) + + def new_transfer_history(self, **params): + """Get future account transaction history list + + https://binance-docs.github.io/apidocs/delivery/en/#new-future-account-transfer + + """ + return self._request_margin_api("get", "asset/transfer", True, data=params) + # return self._request_margin_api("get", "futures/transfer", True, data=params) + + def universal_transfer(self, **params): + """Unviversal transfer api accross different binance account types + + https://binance-docs.github.io/apidocs/spot/en/#user-universal-transfer + """ + return self._request_margin_api( + "post", "asset/transfer", signed=True, data=params + ) + + def futures_coin_create_order(self, **params): + """Send in a new order. + + https://binance-docs.github.io/apidocs/delivery/en/#new-order-trade + + """ + return self._request_futures_coin_api("post", "order", True, data=params) + + def futures_coin_place_batch_order(self, **params): + """Send in new orders. + + https://binance-docs.github.io/apidocs/delivery/en/#place-multiple-orders-trade + + To avoid modifying the existing signature generation and parameter order logic, + the url encoding is done on the special query param, batchOrders, in the early stage. + + """ + query_string = urlencode(params) + query_string = query_string.replace('%27', '%22') + params['batchOrders'] = query_string[12:] + + return self._request_futures_coin_api('post', 'batchOrders', True, data=params) + + def futures_coin_get_order(self, **params): + """Check an order's status. + + https://binance-docs.github.io/apidocs/delivery/en/#query-order-user_data + + """ + return self._request_futures_coin_api("get", "order", True, data=params) + + def futures_coin_get_open_orders(self, **params): + """Get all open orders on a symbol. + + https://binance-docs.github.io/apidocs/delivery/en/#current-all-open-orders-user_data + + """ + return self._request_futures_coin_api("get", "openOrders", True, data=params) + + def futures_coin_get_all_orders(self, **params): + """Get all futures account orders; active, canceled, or filled. + + https://binance-docs.github.io/apidocs/delivery/en/#all-orders-user_data + + """ + return self._request_futures_coin_api( + "get", "allOrders", signed=True, data=params + ) + + def futures_coin_cancel_order(self, **params): + """Cancel an active futures order. + + https://binance-docs.github.io/apidocs/delivery/en/#cancel-order-trade + + """ + return self._request_futures_coin_api( + "delete", "order", signed=True, data=params + ) + + def futures_coin_cancel_all_open_orders(self, **params): + """Cancel all open futures orders + + https://binance-docs.github.io/apidocs/delivery/en/#cancel-all-open-orders-trade + + """ + return self._request_futures_coin_api( + "delete", "allOpenOrders", signed=True, data=params + ) + + def futures_coin_cancel_orders(self, **params): + """Cancel multiple futures orders + + https://binance-docs.github.io/apidocs/delivery/en/#cancel-multiple-orders-trade + + """ + return self._request_futures_coin_api( + "delete", "batchOrders", True, data=params + ) + + def futures_coin_account_balance(self, **params): + """Get futures account balance + + https://binance-docs.github.io/apidocs/delivery/en/#futures-account-balance-user_data + + """ + return self._request_futures_coin_api( + "get", "balance", signed=True, data=params + ) + + def futures_coin_account(self, **params): + """Get current account information. + + https://binance-docs.github.io/apidocs/delivery/en/#account-information-user_data + + """ + return self._request_futures_coin_api( + "get", "account", signed=True, data=params + ) + + def futures_coin_change_leverage(self, **params): + """Change user's initial leverage of specific symbol market + + https://binance-docs.github.io/apidocs/delivery/en/#change-initial-leverage-trade + + """ + return self._request_futures_coin_api( + "post", "leverage", signed=True, data=params + ) + + def futures_coin_change_margin_type(self, **params): + """Change the margin type for a symbol + + https://binance-docs.github.io/apidocs/delivery/en/#change-margin-type-trade + + """ + return self._request_futures_coin_api( + "post", "marginType", signed=True, data=params + ) + + def futures_coin_change_position_margin(self, **params): + """Change the position margin for a symbol + + https://binance-docs.github.io/apidocs/delivery/en/#modify-isolated-position-margin-trade + + """ + return self._request_futures_coin_api( + "post", "positionMargin", True, data=params + ) + + def futures_coin_position_margin_history(self, **params): + """Get position margin change history + + https://binance-docs.github.io/apidocs/delivery/en/#get-position-margin-change-history-trade + + """ + return self._request_futures_coin_api( + "get", "positionMargin/history", True, data=params + ) + + def futures_coin_position_information(self, **params): + """Get position information + + https://binance-docs.github.io/apidocs/delivery/en/#position-information-user_data + + """ + return self._request_futures_coin_api("get", "positionRisk", True, data=params) + + def futures_coin_account_trades(self, **params): + """Get trades for the authenticated account and symbol. + + https://binance-docs.github.io/apidocs/delivery/en/#account-trade-list-user_data + + """ + return self._request_futures_coin_api("get", "userTrades", True, data=params) + + def futures_coin_income_history(self, **params): + """Get income history for authenticated account + + https://binance-docs.github.io/apidocs/delivery/en/#get-income-history-user_data + + """ + return self._request_futures_coin_api("get", "income", True, data=params) + + def futures_coin_change_position_mode(self, **params): + """Change user's position mode (Hedge Mode or One-way Mode ) on EVERY symbol + + https://binance-docs.github.io/apidocs/delivery/en/#change-position-mode-trade + """ + return self._request_futures_coin_api("post", "positionSide/dual", True, data=params) + + def futures_coin_get_position_mode(self, **params): + """Get user's position mode (Hedge Mode or One-way Mode ) on EVERY symbol + + https://binance-docs.github.io/apidocs/delivery/en/#get-current-position-mode-user_data + + """ + return self._request_futures_coin_api("get", "positionSide/dual", True, data=params) + + def futures_coin_stream_get_listen_key(self): + res = self._request_futures_coin_api('post', 'listenKey', signed=False, data={}) + return res['listenKey'] + + def futures_coin_stream_keepalive(self, listenKey): + params = { + 'listenKey': listenKey + } + return self._request_futures_coin_api('put', 'listenKey', signed=False, data=params) + + def futures_coin_stream_close(self, listenKey): + params = { + 'listenKey': listenKey + } + return self._request_futures_coin_api('delete', 'listenKey', signed=False, data=params) + + def get_all_coins_info(self, **params): + """Get information of coins (available for deposit and withdraw) for user. + + https://binance-docs.github.io/apidocs/spot/en/#all-coins-39-information-user_data + + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "coin": "BTC", + "depositAllEnable": true, + "withdrawAllEnable": true, + "name": "Bitcoin", + "free": "0", + "locked": "0", + "freeze": "0", + "withdrawing": "0", + "ipoing": "0", + "ipoable": "0", + "storage": "0", + "isLegalMoney": false, + "trading": true, + "networkList": [ + { + "network": "BNB", + "coin": "BTC", + "withdrawIntegerMultiple": "0.00000001", + "isDefault": false, + "depositEnable": true, + "withdrawEnable": true, + "depositDesc": "", + "withdrawDesc": "", + "specialTips": "Both a MEMO and an Address are required to successfully deposit your BEP2-BTCB tokens to Binance.", + "name": "BEP2", + "resetAddressStatus": false, + "addressRegex": "^(bnb1)[0-9a-z]{38}$", + "memoRegex": "^[0-9A-Za-z-_]{1,120}$", + "withdrawFee": "0.0000026", + "withdrawMin": "0.0000052", + "withdrawMax": "0", + "minConfirm": 1, + "unLockConfirm": 0 + }, + { + "network": "BTC", + "coin": "BTC", + "withdrawIntegerMultiple": "0.00000001", + "isDefault": true, + "depositEnable": true, + "withdrawEnable": true, + "depositDesc": "", + "withdrawDesc": "", + "specialTips": "", + "name": "BTC", + "resetAddressStatus": false, + "addressRegex": "^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$|^(bc1)[0-9A-Za-z]{39,59}$", + "memoRegex": "", + "withdrawFee": "0.0005", + "withdrawMin": "0.001", + "withdrawMax": "0", + "minConfirm": 1, + "unLockConfirm": 2 + } + ] + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'capital/config/getall', True, data=params) + + def get_account_snapshot(self, **params): + """Get daily account snapshot of specific type. + + https://binance-docs.github.io/apidocs/spot/en/#daily-account-snapshot-user_data + + :param type: required. Valid values are SPOT/MARGIN/FUTURES. + :type type: string + :param startTime: optional + :type startTime: int + :param endTime: optional + :type endTime: int + :param limit: optional + :type limit: int + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + .. code-block:: python + + { + "code":200, // 200 for success; others are error codes + "msg":"", // error message + "snapshotVos":[ + { + "data":{ + "balances":[ + { + "asset":"BTC", + "free":"0.09905021", + "locked":"0.00000000" + }, + { + "asset":"USDT", + "free":"1.89109409", + "locked":"0.00000000" + } + ], + "totalAssetOfBtc":"0.09942700" + }, + "type":"spot", + "updateTime":1576281599000 + } + ] + } + + OR + + .. code-block:: python + + { + "code":200, // 200 for success; others are error codes + "msg":"", // error message + "snapshotVos":[ + { + "data":{ + "marginLevel":"2748.02909813", + "totalAssetOfBtc":"0.00274803", + "totalLiabilityOfBtc":"0.00000100", + "totalNetAssetOfBtc":"0.00274750", + "userAssets":[ + { + "asset":"XRP", + "borrowed":"0.00000000", + "free":"1.00000000", + "interest":"0.00000000", + "locked":"0.00000000", + "netAsset":"1.00000000" + } + ] + }, + "type":"margin", + "updateTime":1576281599000 + } + ] + } + + OR + + .. code-block:: python + + { + "code":200, // 200 for success; others are error codes + "msg":"", // error message + "snapshotVos":[ + { + "data":{ + "assets":[ + { + "asset":"USDT", + "marginBalance":"118.99782335", + "walletBalance":"120.23811389" + } + ], + "position":[ + { + "entryPrice":"7130.41000000", + "markPrice":"7257.66239673", + "positionAmt":"0.01000000", + "symbol":"BTCUSDT", + "unRealizedProfit":"1.24029054" + } + ] + }, + "type":"futures", + "updateTime":1576281599000 + } + ] + } + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('get', 'accountSnapshot', True, data=params) + + def disable_fast_withdraw_switch(self, **params): + """Disable Fast Withdraw Switch + + https://binance-docs.github.io/apidocs/spot/en/#disable-fast-withdraw-switch-user_data + + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('post', 'disableFastWithdrawSwitch', True, data=params) + + def enable_fast_withdraw_switch(self, **params): + """Enable Fast Withdraw Switch + + https://binance-docs.github.io/apidocs/spot/en/#enable-fast-withdraw-switch-user_data + + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + :raises: BinanceRequestException, BinanceAPIException + + """ + return self._request_margin_api('post', 'enableFastWithdrawSwitch', True, data=params) + + """ + ==================================================================================================================== + Options API + ==================================================================================================================== + """ + # Quoting interface endpoints + + def options_ping(self): + """Test connectivity + + https://binance-docs.github.io/apidocs/voptions/en/#test-connectivity + + """ + return self._request_options_api('get', 'ping') + + def options_time(self): + """Get server time + + https://binance-docs.github.io/apidocs/voptions/en/#get-server-time + + """ + return self._request_options_api('get', 'time') + + def options_info(self): + """Get current trading pair info + + https://binance-docs.github.io/apidocs/voptions/en/#get-current-trading-pair-info + + """ + return self._request_options_api('get', 'optionInfo') + + def options_exchange_info(self): + """Get current limit info and trading pair info + + https://binance-docs.github.io/apidocs/voptions/en/#get-current-limit-info-and-trading-pair-info + + """ + return self._request_options_api('get', 'exchangeInfo') + + def options_index_price(self, **params): + """Get the spot index price + + https://binance-docs.github.io/apidocs/voptions/en/#get-the-spot-index-price + + :param underlying: required - Spot pair(Option contract underlying asset)- BTCUSDT + :type underlying: str + + """ + return self._request_options_api('get', 'index', data=params) + + def options_price(self, **params): + """Get the latest price + + https://binance-docs.github.io/apidocs/voptions/en/#get-the-latest-price + + :param symbol: optional - Option trading pair - BTC-200730-9000-C + :type symbol: str + + """ + return self._request_options_api('get', 'ticker', data=params) + + def options_mark_price(self, **params): + """Get the latest mark price + + https://binance-docs.github.io/apidocs/voptions/en/#get-the-latest-mark-price + + :param symbol: optional - Option trading pair - BTC-200730-9000-C + :type symbol: str + + """ + return self._request_options_api('get', 'mark', data=params) + + def options_order_book(self, **params): + """Depth information + + https://binance-docs.github.io/apidocs/voptions/en/#depth-information + + :param symbol: required - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param limit: optional - Default:100 Max:1000.Optional value:[10, 20, 50, 100, 500, 1000] - 100 + :type limit: int + + """ + return self._request_options_api('get', 'depth', data=params) + + def options_klines(self, **params): + """Candle data + + https://binance-docs.github.io/apidocs/voptions/en/#candle-data + + :param symbol: required - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param interval: required - Time interval - 5m + :type interval: str + :param startTime: optional - Start Time - 1592317127349 + :type startTime: int + :param endTime: optional - End Time - 1592317127349 + :type endTime: int + :param limit: optional - Number of records Default:500 Max:1500 - 500 + :type limit: int + + """ + return self._request_options_api('get', 'klines', data=params) + + def options_recent_trades(self, **params): + """Recently completed Option trades + + https://binance-docs.github.io/apidocs/voptions/en/#recently-completed-option-trades + + :param symbol: required - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param limit: optional - Number of records Default:100 Max:500 - 100 + :type limit: int + + """ + return self._request_options_api('get', 'trades', data=params) + + def options_historical_trades(self, **params): + """Query trade history + + https://binance-docs.github.io/apidocs/voptions/en/#query-trade-history + + :param symbol: required - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param fromId: optional - The deal ID from which to return. The latest deal record is returned by default - 1592317127349 + :type fromId: int + :param limit: optional - Number of records Default:100 Max:500 - 100 + :type limit: int + + """ + return self._request_options_api('get', 'historicalTrades', data=params) + + # Account and trading interface endpoints + + def options_account_info(self, **params): + """Account asset info (USER_DATA) + + https://binance-docs.github.io/apidocs/voptions/en/#account-asset-info-user_data + + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('get', 'account', signed=True, data=params) + + def options_funds_transfer(self, **params): + """Funds transfer (USER_DATA) + + https://binance-docs.github.io/apidocs/voptions/en/#funds-transfer-user_data + + :param currency: required - Asset type - USDT + :type currency: str + :param type: required - IN: Transfer from spot account to option account OUT: Transfer from option account to spot account - IN + :type type: str (ENUM) + :param amount: required - Amount - 10000 + :type amount: float + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('post', 'transfer', signed=True, data=params) + + def options_positions(self, **params): + """Option holdings info (USER_DATA) + + https://binance-docs.github.io/apidocs/voptions/en/#option-holdings-info-user_data + + :param symbol: optional - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('get', 'position', signed=True, data=params) + + def options_bill(self, **params): + """Account funding flow (USER_DATA) + + https://binance-docs.github.io/apidocs/voptions/en/#account-funding-flow-user_data + + :param currency: required - Asset type - USDT + :type currency: str + :param recordId: optional - Return the recordId and subsequent data, the latest data is returned by default - 100000 + :type recordId: int + :param startTime: optional - Start Time - 1593511200000 + :type startTime: int + :param endTime: optional - End Time - 1593511200000 + :type endTime: int + :param limit: optional - Number of result sets returned Default:100 Max:1000 - 100 + :type limit: int + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('post', 'bill', signed=True, data=params) + + def options_place_order(self, **params): + """Option order (TRADE) + + https://binance-docs.github.io/apidocs/voptions/en/#option-order-trade + + :param symbol: required - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param side: required - Buy/sell direction: SELL, BUY - BUY + :type side: str (ENUM) + :param type: required - Order Type: LIMIT, MARKET - LIMIT + :type type: str (ENUM) + :param quantity: required - Order Quantity - 3 + :type quantity: float + :param price: optional - Order Price - 1000 + :type price: float + :param timeInForce: optional - Time in force method(Default GTC) - GTC + :type timeInForce: str (ENUM) + :param reduceOnly: optional - Reduce Only (Default false) - false + :type reduceOnly: bool + :param postOnly: optional - Post Only (Default false) - false + :type postOnly: bool + :param newOrderRespType: optional - "ACK", "RESULT", Default "ACK" - ACK + :type newOrderRespType: str (ENUM) + :param clientOrderId: optional - User-defined order ID cannot be repeated in pending orders - 10000 + :type clientOrderId: str + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('post', 'order', signed=True, data=params) + + def options_place_batch_order(self, **params): + """Place Multiple Option orders (TRADE) + + https://binance-docs.github.io/apidocs/voptions/en/#place-multiple-option-orders-trade + + :param orders: required - order list. Max 5 orders - [{"symbol":"BTC-210115-35000-C","price":"100","quantity":"0.0001","side":"BUY","type":"LIMIT"}] + :type orders: list + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('post', 'batchOrders', signed=True, data=params) + + def options_cancel_order(self, **params): + """Cancel Option order (TRADE) + + https://binance-docs.github.io/apidocs/voptions/en/#cancel-option-order-trade + + :param symbol: required - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param orderId: optional - Order ID - 4611875134427365377 + :type orderId: str + :param clientOrderId: optional - User-defined order ID - 10000 + :type clientOrderId: str + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('delete', 'order', signed=True, data=params) + + def options_cancel_batch_order(self, **params): + """Cancel Multiple Option orders (TRADE) + + https://binance-docs.github.io/apidocs/voptions/en/#cancel-multiple-option-orders-trade + + :param symbol: required - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param orderIds: optional - Order ID - [4611875134427365377,4611875134427365378] + :type orderId: list + :param clientOrderIds: optional - User-defined order ID - ["my_id_1","my_id_2"] + :type clientOrderIds: list + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('delete', 'batchOrders', signed=True, data=params) + + def options_cancel_all_orders(self, **params): + """Cancel all Option orders (TRADE) + + https://binance-docs.github.io/apidocs/voptions/en/#cancel-all-option-orders-trade + + :param symbol: required - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('delete', 'allOpenOrders', signed=True, data=params) + + def options_query_order(self, **params): + """Query Option order (TRADE) + + https://binance-docs.github.io/apidocs/voptions/en/#query-option-order-trade + + :param symbol: required - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param orderId: optional - Order ID - 4611875134427365377 + :type orderId: str + :param clientOrderId: optional - User-defined order ID - 10000 + :type clientOrderId: str + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('get', 'order', signed=True, data=params) + + def options_query_pending_orders(self, **params): + """Query current pending Option orders (TRADE) + + https://binance-docs.github.io/apidocs/voptions/en/#query-current-pending-option-orders-trade + + :param symbol: required - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param orderId: optional - Returns the orderId and subsequent orders, the most recent order is returned by default - 100000 + :type orderId: str + :param startTime: optional - Start Time - 1593511200000 + :type startTime: int + :param endTime: optional - End Time - 1593511200000 + :type endTime: int + :param limit: optional - Number of result sets returned Default:100 Max:1000 - 100 + :type limit: int + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('get', 'openOrders', signed=True, data=params) + + def options_query_order_history(self, **params): + """Query Option order history (TRADE) + + https://binance-docs.github.io/apidocs/voptions/en/#query-option-order-history-trade + + :param symbol: required - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param orderId: optional - Returns the orderId and subsequent orders, the most recent order is returned by default - 100000 + :type orderId: str + :param startTime: optional - Start Time - 1593511200000 + :type startTime: int + :param endTime: optional - End Time - 1593511200000 + :type endTime: int + :param limit: optional - Number of result sets returned Default:100 Max:1000 - 100 + :type limit: int + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('get', 'historyOrders', signed=True, data=params) + + def options_user_trades(self, **params): + """Option Trade List (USER_DATA) + + https://binance-docs.github.io/apidocs/voptions/en/#option-trade-list-user_data + + :param symbol: required - Option trading pair - BTC-200730-9000-C + :type symbol: str + :param fromId: optional - Trade id to fetch from. Default gets most recent trades. - 4611875134427365376 + :type fromId: int + :param startTime: optional - Start Time - 1593511200000 + :type startTime: int + :param endTime: optional - End Time - 1593511200000 + :type endTime: int + :param limit: optional - Number of result sets returned Default:100 Max:1000 - 100 + :type limit: int + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_options_api('get', 'userTrades', signed=True, data=params) + + # Fiat Endpoints + + def get_fiat_deposit_withdraw_history(self, **params): + """Get Fiat Deposit/Withdraw History + + https://binance-docs.github.io/apidocs/spot/en/#get-fiat-deposit-withdraw-history-user_data + + :param transactionType: required - 0-deposit,1-withdraw + :type transactionType: str + :param beginTime: optional + :type beginTime: int + :param endTime: optional + :type endTime: int + :param page: optional - default 1 + :type page: int + :param rows: optional - default 100, max 500 + :type rows: int + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_margin_api('get', 'fiat/orders', signed=True, data=params) + + def get_fiat_payments_history(self, **params): + """Get Fiat Payments History + + https://binance-docs.github.io/apidocs/spot/en/#get-fiat-payments-history-user_data + + :param transactionType: required - 0-buy,1-sell + :type transactionType: str + :param beginTime: optional + :type beginTime: int + :param endTime: optional + :type endTime: int + :param page: optional - default 1 + :type page: int + :param rows: optional - default 100, max 500 + :type rows: int + :param recvWindow: optional + :type recvWindow: int + + """ + return self._request_margin_api('get', 'fiat/payments', signed=True, data=params) + + # C2C Endpoints + + def get_c2c_trade_history(self, **params): + """Get C2C Trade History + + https://binance-docs.github.io/apidocs/spot/en/#get-c2c-trade-history-user_data + + :param tradeType: required - BUY, SELL + :type tradeType: str + :param startTimestamp: optional + :type startTime: int + :param endTimestamp: optional + :type endTimestamp: int + :param page: optional - default 1 + :type page: int + :param rows: optional - default 100, max 100 + :type rows: int + :param recvWindow: optional + :type recvWindow: int + + :returns: API response + + { + "code": "000000", + "message": "success", + "data": [ + { + "orderNumber":"20219644646554779648", + "advNo": "11218246497340923904", + "tradeType": "SELL", + "asset": "BUSD", + "fiat": "CNY", + "fiatSymbol": "¥", + "amount": "5000.00000000", // Quantity (in Crypto) + "totalPrice": "33400.00000000", + "unitPrice": "6.68", // Unit Price (in Fiat) + "orderStatus": "COMPLETED", // PENDING, TRADING, BUYER_PAYED, DISTRIBUTING, COMPLETED, IN_APPEAL, CANCELLED, CANCELLED_BY_SYSTEM + "createTime": 1619361369000, + "commission": "0", // Transaction Fee (in Crypto) + "counterPartNickName": "ab***", + "advertisementRole": "TAKER" + } + ], + "total": 1, + "success": true + } + + """ + return self._request_margin_api('get', 'c2c/orderMatch/listUserOrderHistory', signed=True, data=params) + + def close_connection(self): + if self.session: + self.session.close() + + def __del__(self): + self.close_connection() + + +class AsyncClient(BaseClient): + + def __init__( + self, api_key: Optional[str] = None, api_secret: Optional[str] = None, + requests_params: Dict[str, str] = None, tld: str = 'com', + testnet: bool = False, loop=None + ): + + self.loop = loop or asyncio.get_event_loop() + super().__init__(api_key, api_secret, requests_params, tld, testnet) + + @classmethod + async def create( + cls, api_key: Optional[str] = None, api_secret: Optional[str] = None, + requests_params: Dict[str, str] = None, tld: str = 'com', + testnet: bool = False, loop=None + ): + + self = cls(api_key, api_secret, requests_params, tld, testnet, loop) + + try: + await self.ping() + + # calculate timestamp offset between local and binance server + res = await self.get_server_time() + self.timestamp_offset = res['serverTime'] - int(time.time() * 1000) + + return self + except Exception: + # If ping throw an exception, the current self must be cleaned + # else, we can receive a "asyncio:Unclosed client session" + await self.close_connection() + raise + + def _init_session(self) -> aiohttp.ClientSession: + + session = aiohttp.ClientSession( + loop=self.loop, + headers=self._get_headers() + ) + return session + + async def close_connection(self): + if self.session: + assert self.session + await self.session.close() + + async def _request(self, method, uri: str, signed: bool, force_params: bool = False, **kwargs): + + kwargs = self._get_request_kwargs(method, signed, force_params, **kwargs) + + async with getattr(self.session, method)(uri, **kwargs) as response: + self.response = response + return await self._handle_response(response) + + async def _handle_response(self, response: aiohttp.ClientResponse): + """Internal helper for handling API responses from the Binance server. + Raises the appropriate exceptions when necessary; otherwise, returns the + response. + """ + if not str(response.status).startswith('2'): + raise BinanceAPIException(response, response.status, await response.text()) + try: + return await response.json() + except ValueError: + txt = await response.text() + raise BinanceRequestException(f'Invalid Response: {txt}') + + async def _request_api(self, method, path, signed=False, version=BaseClient.PUBLIC_API_VERSION, **kwargs): + uri = self._create_api_uri(path, signed, version) + return await self._request(method, uri, signed, **kwargs) + + async def _request_futures_api(self, method, path, signed=False, **kwargs) -> Dict: + uri = self._create_futures_api_uri(path) + + return await self._request(method, uri, signed, True, **kwargs) + + async def _request_futures_data_api(self, method, path, signed=False, **kwargs) -> Dict: + uri = self._create_futures_data_api_uri(path) + + return await self._request(method, uri, signed, True, **kwargs) + + async def _request_futures_coin_api(self, method, path, signed=False, version=1, **kwargs) -> Dict: + uri = self._create_futures_coin_api_url(path, version=version) + + return await self._request(method, uri, signed, True, **kwargs) + + async def _request_futures_coin_data_api(self, method, path, signed=False, version=1, **kwargs) -> Dict: + uri = self._create_futures_coin_data_api_url(path, version=version) + + return await self._request(method, uri, signed, True, **kwargs) + + async def _request_options_api(self, method, path, signed=False, **kwargs) -> Dict: + uri = self._create_options_api_uri(path) + + return await self._request(method, uri, signed, True, **kwargs) + + async def _request_margin_api(self, method, path, signed=False, **kwargs) -> Dict: + uri = self._create_margin_api_uri(path) + + return await self._request(method, uri, signed, **kwargs) + + async def _request_website(self, method, path, signed=False, **kwargs) -> Dict: + uri = self._create_website_uri(path) + return await self._request(method, uri, signed, **kwargs) + + async def _get(self, path, signed=False, version=BaseClient.PUBLIC_API_VERSION, **kwargs): + return await self._request_api('get', path, signed, version, **kwargs) + + async def _post(self, path, signed=False, version=BaseClient.PUBLIC_API_VERSION, **kwargs) -> Dict: + return await self._request_api('post', path, signed, version, **kwargs) + + async def _put(self, path, signed=False, version=BaseClient.PUBLIC_API_VERSION, **kwargs) -> Dict: + return await self._request_api('put', path, signed, version, **kwargs) + + async def _delete(self, path, signed=False, version=BaseClient.PUBLIC_API_VERSION, **kwargs) -> Dict: + return await self._request_api('delete', path, signed, version, **kwargs) + + # Exchange Endpoints + + async def get_products(self) -> Dict: + products = await self._request_website('get', 'exchange-api/v1/public/asset-service/product/get-products') + return products + get_products.__doc__ = Client.get_products.__doc__ + + async def get_exchange_info(self) -> Dict: + return await self._get('exchangeInfo', version=self.PRIVATE_API_VERSION) + get_exchange_info.__doc__ = Client.get_exchange_info.__doc__ + + async def get_symbol_info(self, symbol) -> Optional[Dict]: + res = await self.get_exchange_info() + + for item in res['symbols']: + if item['symbol'] == symbol.upper(): + return item + + return None + get_symbol_info.__doc__ = Client.get_symbol_info.__doc__ + + # General Endpoints + + async def ping(self) -> Dict: + return await self._get('ping', version=self.PRIVATE_API_VERSION) + ping.__doc__ = Client.ping.__doc__ + + async def get_server_time(self) -> Dict: + return await self._get('time', version=self.PRIVATE_API_VERSION) + get_server_time.__doc__ = Client.get_server_time.__doc__ + + # Market Data Endpoints + + async def get_all_tickers(self, symbol: Optional[str] = None) -> List[Dict[str, str]]: + params = {} + if symbol: + params['symbol'] = symbol + return await self._get('ticker/price', version=self.PRIVATE_API_VERSION, data=params) + get_all_tickers.__doc__ = Client.get_all_tickers.__doc__ + + async def get_orderbook_tickers(self) -> Dict: + return await self._get('ticker/bookTicker', version=self.PRIVATE_API_VERSION) + get_orderbook_tickers.__doc__ = Client.get_orderbook_tickers.__doc__ + + async def get_order_book(self, **params) -> Dict: + return await self._get('depth', data=params, version=self.PRIVATE_API_VERSION) + get_order_book.__doc__ = Client.get_order_book.__doc__ + + async def get_recent_trades(self, **params) -> Dict: + return await self._get('trades', data=params) + get_recent_trades.__doc__ = Client.get_recent_trades.__doc__ + + async def get_historical_trades(self, **params) -> Dict: + return await self._get('historicalTrades', data=params, version=self.PRIVATE_API_VERSION) + get_historical_trades.__doc__ = Client.get_historical_trades.__doc__ + + async def get_aggregate_trades(self, **params) -> Dict: + return await self._get('aggTrades', data=params, version=self.PRIVATE_API_VERSION) + get_aggregate_trades.__doc__ = Client.get_aggregate_trades.__doc__ + + async def aggregate_trade_iter(self, symbol, start_str=None, last_id=None): + if start_str is not None and last_id is not None: + raise ValueError( + 'start_time and last_id may not be simultaneously specified.') + + # If there's no last_id, get one. + if last_id is None: + # Without a last_id, we actually need the first trade. Normally, + # we'd get rid of it. See the next loop. + if start_str is None: + trades = await self.get_aggregate_trades(symbol=symbol, fromId=0) + else: + # The difference between startTime and endTime should be less + # or equal than an hour and the result set should contain at + # least one trade. + start_ts = convert_ts_str(start_str) + # If the resulting set is empty (i.e. no trades in that interval) + # then we just move forward hour by hour until we find at least one + # trade or reach present moment + while True: + end_ts = start_ts + (60 * 60 * 1000) + trades = await self.get_aggregate_trades( + symbol=symbol, + startTime=start_ts, + endTime=end_ts) + if len(trades) > 0: + break + # If we reach present moment and find no trades then there is + # nothing to iterate, so we're done + if end_ts > int(time.time() * 1000): + return + start_ts = end_ts + for t in trades: + yield t + last_id = trades[-1][self.AGG_ID] + + while True: + # There is no need to wait between queries, to avoid hitting the + # rate limit. We're using blocking IO, and as long as we're the + # only thread running calls like this, Binance will automatically + # add the right delay time on their end, forcing us to wait for + # data. That really simplifies this function's job. Binance is + # fucking awesome. + trades = await self.get_aggregate_trades(symbol=symbol, fromId=last_id) + # fromId=n returns a set starting with id n, but we already have + # that one. So get rid of the first item in the result set. + trades = trades[1:] + if len(trades) == 0: + return + for t in trades: + yield t + last_id = trades[-1][self.AGG_ID] + aggregate_trade_iter.__doc__ = Client.aggregate_trade_iter.__doc__ + + async def get_klines(self, **params) -> Dict: + return await self._get('klines', data=params, version=self.PRIVATE_API_VERSION) + get_klines.__doc__ = Client.get_klines.__doc__ + + async def _klines(self, klines_type: HistoricalKlinesType = HistoricalKlinesType.SPOT, **params) -> Dict: + if 'endTime' in params and not params['endTime']: + del params['endTime'] + if HistoricalKlinesType.SPOT == klines_type: + return await self.get_klines(**params) + elif HistoricalKlinesType.FUTURES == klines_type: + return await self.futures_klines(**params) + else: + raise NotImplementedException(klines_type) + _klines.__doc__ = Client._klines.__doc__ + + async def _get_earliest_valid_timestamp(self, symbol, interval, + klines_type: HistoricalKlinesType = HistoricalKlinesType.SPOT): + kline = await self._klines( + klines_type=klines_type, + symbol=symbol, + interval=interval, + limit=1, + startTime=0, + endTime=int(time.time() * 1000) + ) + return kline[0][0] + _get_earliest_valid_timestamp.__doc__ = Client._get_earliest_valid_timestamp.__doc__ + + async def get_historical_klines(self, symbol, interval, start_str, end_str=None, limit=500, + klines_type: HistoricalKlinesType = HistoricalKlinesType.SPOT): + return await self._historical_klines(symbol, interval, start_str, end_str=end_str, limit=limit, klines_type=klines_type) + get_historical_klines.__doc__ = Client.get_historical_klines.__doc__ + + async def _historical_klines(self, symbol, interval, start_str, end_str=None, limit=500, + klines_type: HistoricalKlinesType = HistoricalKlinesType.SPOT): + + # init our list + output_data = [] + + # convert interval to useful value in seconds + timeframe = interval_to_milliseconds(interval) + + # convert our date strings to milliseconds + start_ts = convert_ts_str(start_str) + + # establish first available start timestamp + first_valid_ts = await self._get_earliest_valid_timestamp(symbol, interval, klines_type) + start_ts = max(start_ts, first_valid_ts) + + # if an end time was passed convert it + end_ts = convert_ts_str(end_str) + + idx = 0 + while True: + # fetch the klines from start_ts up to max 500 entries or the end_ts if set + temp_data = await self._klines( + klines_type=klines_type, + symbol=symbol, + interval=interval, + limit=limit, + startTime=start_ts, + endTime=end_ts + ) + + # handle the case where exactly the limit amount of data was returned last loop + if not len(temp_data): + break + + # append this loops data to our output data + output_data += temp_data + + # set our start timestamp using the last value in the array + start_ts = temp_data[-1][0] + + idx += 1 + # check if we received less than the required limit and exit the loop + if len(temp_data) < limit: + # exit the while loop + break + + # increment next call by our timeframe + start_ts += timeframe + + # sleep after every 3rd call to be kind to the API + if idx % 3 == 0: + await asyncio.sleep(1) + + return output_data + _historical_klines.__doc__ = Client._historical_klines.__doc__ + + async def get_historical_klines_generator(self, symbol, interval, start_str, end_str=None, + klines_type: HistoricalKlinesType = HistoricalKlinesType.SPOT): + return self._historical_klines_generator(symbol, interval, start_str, end_str=end_str, klines_type=klines_type) + get_historical_klines_generator.__doc__ = Client.get_historical_klines_generator.__doc__ + + async def _historical_klines_generator(self, symbol, interval, start_str, end_str=None, + klines_type: HistoricalKlinesType = HistoricalKlinesType.SPOT): + + # setup the max limit + limit = 500 + + # convert interval to useful value in seconds + timeframe = interval_to_milliseconds(interval) + + # convert our date strings to milliseconds + start_ts = convert_ts_str(start_str) + + # establish first available start timestamp + first_valid_ts = await self._get_earliest_valid_timestamp(symbol, interval, klines_type) + start_ts = max(start_ts, first_valid_ts) + + # if an end time was passed convert it + end_ts = convert_ts_str(end_str) + + idx = 0 + while True: + # fetch the klines from start_ts up to max 500 entries or the end_ts if set + output_data = await self._klines( + klines_type=klines_type, + symbol=symbol, + interval=interval, + limit=limit, + startTime=start_ts, + endTime=end_ts + ) + + # handle the case where exactly the limit amount of data was returned last loop + if not len(output_data): + break + + # yield data + for o in output_data: + yield o + + # set our start timestamp using the last value in the array + start_ts = output_data[-1][0] + + idx += 1 + # check if we received less than the required limit and exit the loop + if len(output_data) < limit: + # exit the while loop + break + + # increment next call by our timeframe + start_ts += timeframe + + # sleep after every 3rd call to be kind to the API + if idx % 3 == 0: + await asyncio.sleep(1) + _historical_klines_generator.__doc__ = Client._historical_klines_generator.__doc__ + + async def get_avg_price(self, **params): + return await self._get('avgPrice', data=params, version=self.PRIVATE_API_VERSION) + get_avg_price.__doc__ = Client.get_avg_price.__doc__ + + async def get_ticker(self, **params): + return await self._get('ticker/24hr', data=params, version=self.PRIVATE_API_VERSION) + get_ticker.__doc__ = Client.get_ticker.__doc__ + + async def get_symbol_ticker(self, **params): + return await self._get('ticker/price', data=params, version=self.PRIVATE_API_VERSION) + get_symbol_ticker.__doc__ = Client.get_symbol_ticker.__doc__ + + async def get_orderbook_ticker(self, **params): + return await self._get('ticker/bookTicker', data=params, version=self.PRIVATE_API_VERSION) + get_orderbook_ticker.__doc__ = Client.get_orderbook_ticker.__doc__ + + # Account Endpoints + + async def create_order(self, **params): + return await self._post('order', True, data=params) + create_order.__doc__ = Client.create_order.__doc__ + + async def order_limit(self, timeInForce=BaseClient.TIME_IN_FORCE_GTC, **params): + params.update({ + 'type': self.ORDER_TYPE_LIMIT, + 'timeInForce': timeInForce + }) + return await self.create_order(**params) + order_limit.__doc__ = Client.order_limit.__doc__ + + async def order_limit_buy(self, timeInForce=BaseClient.TIME_IN_FORCE_GTC, **params): + params.update({ + 'side': self.SIDE_BUY, + }) + return await self.order_limit(timeInForce=timeInForce, **params) + order_limit_buy.__doc__ = Client.order_limit_buy.__doc__ + + async def order_limit_sell(self, timeInForce=BaseClient.TIME_IN_FORCE_GTC, **params): + params.update({ + 'side': self.SIDE_SELL + }) + return await self.order_limit(timeInForce=timeInForce, **params) + order_limit_sell.__doc__ = Client.order_limit_sell.__doc__ + + async def order_market(self, **params): + params.update({ + 'type': self.ORDER_TYPE_MARKET + }) + return await self.create_order(**params) + order_market.__doc__ = Client.order_market.__doc__ + + async def order_market_buy(self, **params): + params.update({ + 'side': self.SIDE_BUY + }) + return await self.order_market(**params) + order_market_buy.__doc__ = Client.order_market_buy.__doc__ + + async def order_market_sell(self, **params): + params.update({ + 'side': self.SIDE_SELL + }) + return await self.order_market(**params) + order_market_sell.__doc__ = Client.order_market_sell.__doc__ + + async def create_oco_order(self, **params): + return await self._post('order/oco', True, data=params) + create_oco_order.__doc__ = Client.create_oco_order.__doc__ + + async def order_oco_buy(self, **params): + params.update({ + 'side': self.SIDE_BUY + }) + return await self.create_oco_order(**params) + order_oco_buy.__doc__ = Client.order_oco_buy.__doc__ + + async def order_oco_sell(self, **params): + params.update({ + 'side': self.SIDE_SELL + }) + return await self.create_oco_order(**params) + order_oco_sell.__doc__ = Client.order_oco_sell.__doc__ + + async def create_test_order(self, **params): + return await self._post('order/test', True, data=params) + create_test_order.__doc__ = Client.create_test_order.__doc__ + + async def get_order(self, **params): + return await self._get('order', True, data=params) + get_order.__doc__ = Client.get_order.__doc__ + + async def get_all_orders(self, **params): + return await self._get('allOrders', True, data=params) + get_all_orders.__doc__ = Client.get_all_orders.__doc__ + + async def cancel_order(self, **params): + return await self._delete('order', True, data=params) + cancel_order.__doc__ = Client.cancel_order.__doc__ + + async def get_open_orders(self, **params): + return await self._get('openOrders', True, data=params) + get_open_orders.__doc__ = Client.get_open_orders.__doc__ + + # User Stream Endpoints + async def get_account(self, **params): + return await self._get('account', True, data=params) + get_account.__doc__ = Client.get_account.__doc__ + + async def get_asset_balance(self, asset, **params): + res = await self.get_account(**params) + # find asset balance in list of balances + if "balances" in res: + for bal in res['balances']: + if bal['asset'].lower() == asset.lower(): + return bal + return None + get_asset_balance.__doc__ = Client.get_asset_balance.__doc__ + + async def get_my_trades(self, **params): + return await self._get('myTrades', True, data=params) + get_my_trades.__doc__ = Client.get_my_trades.__doc__ + + async def get_system_status(self): + return await self._request_margin_api('get', 'system/status') + get_system_status.__doc__ = Client.get_system_status.__doc__ + + async def get_account_status(self, **params): + return await self._request_margin_api('get', 'account/status', True, data=params) + get_account_status.__doc__ = Client.get_account_status.__doc__ + + async def get_account_api_trading_status(self, **params): + return await self._request_margin_api('get', 'account/apiTradingStatus', True, data=params) + get_account_api_trading_status.__doc__ = Client.get_account_api_trading_status.__doc__ + + async def get_account_api_permissions(self, **params): + return await self._request_margin_api('get', 'account/apiRestrictions', True, data=params) + get_account_api_permissions.__doc__ = Client.get_account_api_permissions.__doc__ + + async def get_dust_log(self, **params): + return await self._request_margin_api('get', 'asset/dribblet', True, data=params) + get_dust_log.__doc__ = Client.get_dust_log.__doc__ + + async def transfer_dust(self, **params): + return await self._request_margin_api('post', 'asset/dust', True, data=params) + transfer_dust.__doc__ = Client.transfer_dust.__doc__ + + async def get_asset_dividend_history(self, **params): + return await self._request_margin_api('get', 'asset/assetDividend', True, data=params) + get_asset_dividend_history.__doc__ = Client.get_asset_dividend_history.__doc__ + + async def make_universal_transfer(self, **params): + return await self._request_margin_api('post', 'asset/transfer', signed=True, data=params) + make_universal_transfer.__doc__ = Client.make_universal_transfer.__doc__ + + async def query_universal_transfer_history(self, **params): + return await self._request_margin_api('get', 'asset/transfer', signed=True, data=params) + query_universal_transfer_history.__doc__ = Client.query_universal_transfer_history.__doc__ + + async def get_trade_fee(self, **params): + return await self._request_margin_api('get', 'asset/tradeFee', True, data=params) + get_trade_fee.__doc__ = Client.get_trade_fee.__doc__ + + async def get_asset_details(self, **params): + return await self._request_margin_api('get', 'asset/assetDetail', True, data=params) + get_asset_details.__doc__ = Client.get_asset_details.__doc__ + + # Withdraw Endpoints + + async def withdraw(self, **params): + # force a name for the withdrawal if one not set + if 'coin' in params and 'name' not in params: + params['name'] = params['coin'] + return await self._request_margin_api('post', 'capital/withdraw/apply', True, data=params) + withdraw.__doc__ = Client.withdraw.__doc__ + + async def get_deposit_history(self, **params): + return await self._request_margin_api('get', 'capital/deposit/hisrec', True, data=params) + get_deposit_history.__doc__ = Client.get_deposit_history.__doc__ + + async def get_withdraw_history(self, **params): + return await self._request_margin_api('get', 'capital/withdraw/history', True, data=params) + get_withdraw_history.__doc__ = Client.get_withdraw_history.__doc__ + + async def get_withdraw_history_id(self, withdraw_id, **params): + result = await self.get_withdraw_history(**params) + + for entry in result: + if 'id' in entry and entry['id'] == withdraw_id: + return entry + + raise Exception("There is no entry with withdraw id", result) + get_withdraw_history_id.__doc__ = Client.get_withdraw_history_id.__doc__ + + async def get_deposit_address(self, coin: str, network: Optional[str] = None, **params): + params['coin'] = coin + if network: + params['network'] = network + return await self._request_margin_api('get', 'capital/deposit/address', True, data=params) + get_deposit_address.__doc__ = Client.get_deposit_address.__doc__ + + # User Stream Endpoints + + async def stream_get_listen_key(self): + res = await self._post('userDataStream', False, data={}) + return res['listenKey'] + stream_get_listen_key.__doc__ = Client.stream_get_listen_key.__doc__ + + async def stream_keepalive(self, listenKey): + params = { + 'listenKey': listenKey + } + return await self._put('userDataStream', False, data=params) + stream_keepalive.__doc__ = Client.stream_keepalive.__doc__ + + async def stream_close(self, listenKey): + params = { + 'listenKey': listenKey + } + return await self._delete('userDataStream', False, data=params) + stream_close.__doc__ = Client.stream_close.__doc__ + + # Margin Trading Endpoints + async def get_margin_account(self, **params): + return await self._request_margin_api('get', 'margin/account', True, data=params) + get_margin_account.__doc__ = Client.get_margin_account.__doc__ + + async def get_isolated_margin_account(self, **params): + return await self._request_margin_api('get', 'margin/isolated/account', True, data=params) + + async def enable_isolated_margin_account(self, **params): + return await self._request_margin_api('post', 'margin/isolated/account', True, data=params) + + async def disable_isolated_margin_account(self, **params): + return await self._request_margin_api('delete', 'margin/isolated/account', True, data=params) + + async def get_margin_asset(self, **params): + return await self._request_margin_api('get', 'margin/asset', data=params) + + async def get_margin_symbol(self, **params): + return await self._request_margin_api('get', 'margin/pair', data=params) + + async def get_margin_all_assets(self, **params): + return await self._request_margin_api('get', 'margin/allAssets', data=params) + + async def get_margin_all_pairs(self, **params): + return await self._request_margin_api('get', 'margin/allPairs', data=params) + + async def create_isolated_margin_account(self, **params): + return await self._request_margin_api('post', 'margin/isolated/create', signed=True, data=params) + + async def get_isolated_margin_symbol(self, **params): + return await self._request_margin_api('get', 'margin/isolated/pair', signed=True, data=params) + + async def get_all_isolated_margin_symbols(self, **params): + return await self._request_margin_api('get', 'margin/isolated/allPairs', signed=True, data=params) + + async def toggle_bnb_burn_spot_margin(self, **params): + return await self._request_margin_api('post', 'bnbBurn', signed=True, data=params) + + async def get_bnb_burn_spot_margin(self, **params): + return await self._request_margin_api('get', 'bnbBurn', signed=True, data=params) + + async def get_margin_price_index(self, **params): + return await self._request_margin_api('get', 'margin/priceIndex', data=params) + + async def transfer_margin_to_spot(self, **params): + params['type'] = 2 + return await self._request_margin_api('post', 'margin/transfer', signed=True, data=params) + + async def transfer_spot_to_margin(self, **params): + params['type'] = 1 + return await self._request_margin_api('post', 'margin/transfer', signed=True, data=params) + + async def transfer_isolated_margin_to_spot(self, **params): + params['transFrom'] = "ISOLATED_MARGIN" + params['transTo'] = "SPOT" + return await self._request_margin_api('post', 'margin/isolated/transfer', signed=True, data=params) + + async def transfer_spot_to_isolated_margin(self, **params): + params['transFrom'] = "SPOT" + params['transTo'] = "ISOLATED_MARGIN" + return await self._request_margin_api('post', 'margin/isolated/transfer', signed=True, data=params) + + async def create_margin_loan(self, **params): + return await self._request_margin_api('post', 'margin/loan', signed=True, data=params) + + async def repay_margin_loan(self, **params): + return await self._request_margin_api('post', 'margin/repay', signed=True, data=params) + + async def create_margin_order(self, **params): + return await self._request_margin_api('post', 'margin/order', signed=True, data=params) + + async def cancel_margin_order(self, **params): + return await self._request_margin_api('delete', 'margin/order', signed=True, data=params) + + async def get_margin_loan_details(self, **params): + return await self._request_margin_api('get', 'margin/loan', signed=True, data=params) + + async def get_margin_repay_details(self, **params): + return await self._request_margin_api('get', 'margin/repay', signed=True, data=params) + + async def get_margin_interest_history(self, **params): + return await self._request_margin_api('get', 'margin/interestHistory', signed=True, data=params) + + async def get_margin_force_liquidation_rec(self, **params): + return await self._request_margin_api('get', 'margin/forceLiquidationRec', signed=True, data=params) + + async def get_margin_order(self, **params): + return await self._request_margin_api('get', 'margin/order', signed=True, data=params) + + async def get_open_margin_orders(self, **params): + return await self._request_margin_api('get', 'margin/openOrders', signed=True, data=params) + + async def get_all_margin_orders(self, **params): + return await self._request_margin_api('get', 'margin/allOrders', signed=True, data=params) + + async def get_margin_trades(self, **params): + return await self._request_margin_api('get', 'margin/myTrades', signed=True, data=params) + + async def get_max_margin_loan(self, **params): + return await self._request_margin_api('get', 'margin/maxBorrowable', signed=True, data=params) + + async def get_max_margin_transfer(self, **params): + return await self._request_margin_api('get', 'margin/maxTransferable', signed=True, data=params) + + # Margin OCO + + async def create_margin_oco_order(self, **params): + return await self._request_margin_api('post', 'margin/order/oco', signed=True, data=params) + + async def cancel_margin_oco_order(self, **params): + return await self._request_margin_api('delete', 'margin/orderList', signed=True, data=params) + + async def get_margin_oco_order(self, **params): + return await self._request_margin_api('get', 'margin/orderList', signed=True, data=params) + + async def get_open_margin_oco_orders(self, **params): + return await self._request_margin_api('get', 'margin/allOrderList', signed=True, data=params) + + # Cross-margin + + async def margin_stream_get_listen_key(self): + res = await self._request_margin_api('post', 'userDataStream', signed=False, data={}) + return res['listenKey'] + + async def margin_stream_keepalive(self, listenKey): + params = { + 'listenKey': listenKey + } + return await self._request_margin_api('put', 'userDataStream', signed=False, data=params) + + async def margin_stream_close(self, listenKey): + params = { + 'listenKey': listenKey + } + return await self._request_margin_api('delete', 'userDataStream', signed=False, data=params) + + # Isolated margin + + async def isolated_margin_stream_get_listen_key(self, symbol): + params = { + 'symbol': symbol + } + res = await self._request_margin_api('post', 'userDataStream/isolated', signed=False, data=params) + return res['listenKey'] + + async def isolated_margin_stream_keepalive(self, symbol, listenKey): + params = { + 'symbol': symbol, + 'listenKey': listenKey + } + return await self._request_margin_api('put', 'userDataStream/isolated', signed=False, data=params) + + async def isolated_margin_stream_close(self, symbol, listenKey): + params = { + 'symbol': symbol, + 'listenKey': listenKey + } + return await self._request_margin_api('delete', 'userDataStream/isolated', signed=False, data=params) + + # Lending Endpoints + + async def get_lending_product_list(self, **params): + return await self._request_margin_api('get', 'lending/daily/product/list', signed=True, data=params) + + async def get_lending_daily_quota_left(self, **params): + return await self._request_margin_api('get', 'lending/daily/userLeftQuota', signed=True, data=params) + + async def purchase_lending_product(self, **params): + return await self._request_margin_api('post', 'lending/daily/purchase', signed=True, data=params) + + async def get_lending_daily_redemption_quota(self, **params): + return await self._request_margin_api('get', 'lending/daily/userRedemptionQuota', signed=True, data=params) + + async def redeem_lending_product(self, **params): + return await self._request_margin_api('post', 'lending/daily/redeem', signed=True, data=params) + + async def get_lending_position(self, **params): + return await self._request_margin_api('get', 'lending/daily/token/position', signed=True, data=params) + + async def get_fixed_activity_project_list(self, **params): + return await self._request_margin_api('get', 'lending/project/list', signed=True, data=params) + + async def get_lending_account(self, **params): + return await self._request_margin_api('get', 'lending/union/account', signed=True, data=params) + + async def get_lending_purchase_history(self, **params): + return await self._request_margin_api('get', 'lending/union/purchaseRecord', signed=True, data=params) + + async def get_lending_redemption_history(self, **params): + return await self._request_margin_api('get', 'lending/union/redemptionRecord', signed=True, data=params) + + async def get_lending_interest_history(self, **params): + return await self._request_margin_api('get', 'lending/union/interestHistory', signed=True, data=params) + + async def change_fixed_activity_to_daily_position(self, **params): + return await self._request_margin_api('post', 'lending/positionChanged', signed=True, data=params) + + # Sub Accounts + + async def get_sub_account_list(self, **params): + return await self._request_margin_api('get', 'sub-account/list', True, data=params) + + async def get_sub_account_transfer_history(self, **params): + return await self._request_margin_api('get', 'sub-account/sub/transfer/history', True, data=params) + + async def get_sub_account_futures_transfer_history(self, **params): + return await self._request_margin_api('get', 'sub-account/futures/internalTransfer', True, data=params) + + async def create_sub_account_futures_transfer(self, **params): + return await self._request_margin_api('post', 'sub-account/futures/internalTransfer', True, data=params) + + async def get_sub_account_assets(self, **params): + return await self._request_margin_api('get', 'sub-account/assets', True, data=params) + + async def query_subaccount_spot_summary(self, **params): + return await self._request_margin_api('get', 'sub-account/spotSummary', True, data=params) + + async def get_subaccount_deposit_address(self, **params): + return await self._request_margin_api('get', 'capital/deposit/subAddress', True, data=params) + + async def get_subaccount_deposit_history(self, **params): + return await self._request_margin_api('get', 'capital/deposit/subHisrec', True, data=params) + + async def get_subaccount_futures_margin_status(self, **params): + return await self._request_margin_api('get', 'sub-account/status', True, data=params) + + async def enable_subaccount_margin(self, **params): + return await self._request_margin_api('post', 'sub-account/margin/enable', True, data=params) + + async def get_subaccount_margin_details(self, **params): + return await self._request_margin_api('get', 'sub-account/margin/account', True, data=params) + + async def get_subaccount_margin_summary(self, **params): + return await self._request_margin_api('get', 'sub-account/margin/accountSummary', True, data=params) + + async def enable_subaccount_futures(self, **params): + return await self._request_margin_api('post', 'sub-account/futures/enable', True, data=params) + + async def get_subaccount_futures_details(self, **params): + return await self._request_margin_api('get', 'sub-account/futures/account', True, data=params) + + async def get_subaccount_futures_summary(self, **params): + return await self._request_margin_api('get', 'sub-account/futures/accountSummary', True, data=params) + + async def get_subaccount_futures_positionrisk(self, **params): + return await self._request_margin_api('get', 'sub-account/futures/positionRisk', True, data=params) + + async def make_subaccount_futures_transfer(self, **params): + return await self._request_margin_api('post', 'sub-account/futures/transfer', True, data=params) + + async def make_subaccount_margin_transfer(self, **params): + return await self._request_margin_api('post', 'sub-account/margin/transfer', True, data=params) + + async def make_subaccount_to_subaccount_transfer(self, **params): + return await self._request_margin_api('post', 'sub-account/transfer/subToSub', True, data=params) + + async def make_subaccount_to_master_transfer(self, **params): + return await self._request_margin_api('post', 'sub-account/transfer/subToMaster', True, data=params) + + async def get_subaccount_transfer_history(self, **params): + return await self._request_margin_api('get', 'sub-account/transfer/subUserHistory', True, data=params) + + async def make_subaccount_universal_transfer(self, **params): + return await self._request_margin_api('post', 'sub-account/universalTransfer', True, data=params) + + async def get_universal_transfer_history(self, **params): + return await self._request_margin_api('get', 'sub-account/universalTransfer', True, data=params) + + # Futures API + + async def futures_ping(self): + return await self._request_futures_api('get', 'ping') + + async def futures_time(self): + return await self._request_futures_api('get', 'time') + + async def futures_exchange_info(self): + return await self._request_futures_api('get', 'exchangeInfo') + + async def futures_order_book(self, **params): + return await self._request_futures_api('get', 'depth', data=params) + + async def futures_recent_trades(self, **params): + return await self._request_futures_api('get', 'trades', data=params) + + async def futures_historical_trades(self, **params): + return await self._request_futures_api('get', 'historicalTrades', data=params) + + async def futures_aggregate_trades(self, **params): + return await self._request_futures_api('get', 'aggTrades', data=params) + + async def futures_klines(self, **params): + return await self._request_futures_api('get', 'klines', data=params) + + async def futures_continous_klines(self, **params): + return await self._request_futures_api('get', 'continuousKlines', data=params) + + async def futures_historical_klines(self, symbol, interval, start_str, end_str=None, limit=500): + return self._historical_klines(symbol, interval, start_str, end_str=end_str, limit=limit, klines_type=HistoricalKlinesType.FUTURES) + + async def futures_historical_klines_generator(self, symbol, interval, start_str, end_str=None): + return self._historical_klines_generator(symbol, interval, start_str, end_str=end_str, klines_type=HistoricalKlinesType.FUTURES) + + async def futures_mark_price(self, **params): + return await self._request_futures_api('get', 'premiumIndex', data=params) + + async def futures_funding_rate(self, **params): + return await self._request_futures_api('get', 'fundingRate', data=params) + + async def futures_top_longshort_account_ratio(self, **params): + return await self._request_futures_data_api('get', 'topLongShortAccountRatio', data=params) + + async def futures_top_longshort_position_ratio(self, **params): + return await self._request_futures_data_api('get', 'topLongShortPositionRatio', data=params) + + async def futures_global_longshort_ratio(self, **params): + return await self._request_futures_data_api('get', 'globalLongShortAccountRatio', data=params) + + async def futures_ticker(self, **params): + return await self._request_futures_api('get', 'ticker/24hr', data=params) + + async def futures_symbol_ticker(self, **params): + return await self._request_futures_api('get', 'ticker/price', data=params) + + async def futures_orderbook_ticker(self, **params): + return await self._request_futures_api('get', 'ticker/bookTicker', data=params) + + async def futures_liquidation_orders(self, **params): + return await self._request_futures_api('get', 'forceOrders', signed=True, data=params) + + async def futures_adl_quantile_estimate(self, **params): + return await self._request_futures_api('get', 'adlQuantile', signed=True, data=params) + + async def futures_open_interest(self, **params): + return await self._request_futures_api('get', 'openInterest', data=params) + + async def futures_open_interest_hist(self, **params): + return await self._request_futures_data_api('get', 'openInterestHist', data=params) + + async def futures_leverage_bracket(self, **params): + return await self._request_futures_api('get', 'leverageBracket', True, data=params) + + async def futures_account_transfer(self, **params): + return await self._request_margin_api('post', 'futures/transfer', True, data=params) + + async def transfer_history(self, **params): + return await self._request_margin_api('get', 'futures/transfer', True, data=params) + + async def futures_create_order(self, **params): + return await self._request_futures_api('post', 'order', True, data=params) + + async def futures_place_batch_order(self, **params): + query_string = urlencode(params) + query_string = query_string.replace('%27', '%22') + params['batchOrders'] = query_string[12:] + return await self._request_futures_api('post', 'batchOrders', True, data=params) + + async def futures_get_order(self, **params): + return await self._request_futures_api('get', 'order', True, data=params) + + async def futures_get_open_orders(self, **params): + return await self._request_futures_api('get', 'openOrders', True, data=params) + + async def futures_get_all_orders(self, **params): + return await self._request_futures_api('get', 'allOrders', True, data=params) + + async def futures_cancel_order(self, **params): + return await self._request_futures_api('delete', 'order', True, data=params) + + async def futures_cancel_all_open_orders(self, **params): + return await self._request_futures_api('delete', 'allOpenOrders', True, data=params) + + async def futures_cancel_orders(self, **params): + return await self._request_futures_api('delete', 'batchOrders', True, data=params) + + async def futures_account_balance(self, **params): + return await self._request_futures_api('get', 'balance', True, data=params) + + async def futures_account(self, **params): + return await self._request_futures_api('get', 'account', True, data=params) + + async def futures_change_leverage(self, **params): + return await self._request_futures_api('post', 'leverage', True, data=params) + + async def futures_change_margin_type(self, **params): + return await self._request_futures_api('post', 'marginType', True, data=params) + + async def futures_change_position_margin(self, **params): + return await self._request_futures_api('post', 'positionMargin', True, data=params) + + async def futures_position_margin_history(self, **params): + return await self._request_futures_api('get', 'positionMargin/history', True, data=params) + + async def futures_position_information(self, **params): + return await self._request_futures_api('get', 'positionRisk', True, data=params) + + async def futures_account_trades(self, **params): + return await self._request_futures_api('get', 'userTrades', True, data=params) + + async def futures_income_history(self, **params): + return await self._request_futures_api('get', 'income', True, data=params) + + async def futures_change_position_mode(self, **params): + return await self._request_futures_api('post', 'positionSide/dual', True, data=params) + + async def futures_get_position_mode(self, **params): + return await self._request_futures_api('get', 'positionSide/dual', True, data=params) + + async def futures_change_multi_assets_mode(self, multiAssetsMargin: bool): + params = { + 'true' if multiAssetsMargin else 'false' + } + return await self._request_futures_api('post', 'multiAssetsMargin', True, data=params) + + async def futures_get_multi_assets_mode(self): + return await self._request_futures_api('get', 'multiAssetsMargin', True) + + async def futures_stream_get_listen_key(self): + res = await self._request_futures_api('post', 'listenKey', signed=False, data={}) + return res['listenKey'] + + async def futures_stream_keepalive(self, listenKey): + params = { + 'listenKey': listenKey + } + return await self._request_futures_api('put', 'listenKey', signed=False, data=params) + + async def futures_stream_close(self, listenKey): + params = { + 'listenKey': listenKey + } + return await self._request_futures_api('delete', 'listenKey', signed=False, data=params) + + # COIN Futures API + + async def futures_coin_ping(self): + return await self._request_futures_coin_api("get", "ping") + + async def futures_coin_time(self): + return await self._request_futures_coin_api("get", "time") + + async def futures_coin_exchange_info(self): + return await self._request_futures_coin_api("get", "exchangeInfo") + + async def futures_coin_order_book(self, **params): + return await self._request_futures_coin_api("get", "depth", data=params) + + async def futures_coin_recent_trades(self, **params): + return await self._request_futures_coin_api("get", "trades", data=params) + + async def futures_coin_historical_trades(self, **params): + return await self._request_futures_coin_api("get", "historicalTrades", data=params) + + async def futures_coin_aggregate_trades(self, **params): + return await self._request_futures_coin_api("get", "aggTrades", data=params) + + async def futures_coin_klines(self, **params): + return await self._request_futures_coin_api("get", "klines", data=params) + + async def futures_coin_continous_klines(self, **params): + return await self._request_futures_coin_api("get", "continuousKlines", data=params) + + async def futures_coin_index_price_klines(self, **params): + return await self._request_futures_coin_api("get", "indexPriceKlines", data=params) + + async def futures_coin_mark_price_klines(self, **params): + return await self._request_futures_coin_api("get", "markPriceKlines", data=params) + + async def futures_coin_mark_price(self, **params): + return await self._request_futures_coin_api("get", "premiumIndex", data=params) + + async def futures_coin_funding_rate(self, **params): + return await self._request_futures_coin_api("get", "fundingRate", data=params) + + async def futures_coin_ticker(self, **params): + return await self._request_futures_coin_api("get", "ticker/24hr", data=params) + + async def futures_coin_symbol_ticker(self, **params): + return await self._request_futures_coin_api("get", "ticker/price", data=params) + + async def futures_coin_orderbook_ticker(self, **params): + return await self._request_futures_coin_api("get", "ticker/bookTicker", data=params) + + async def futures_coin_liquidation_orders(self, **params): + return await self._request_futures_coin_api("get", "forceOrders", signed=True, data=params) + + async def futures_coin_open_interest(self, **params): + return await self._request_futures_coin_api("get", "openInterest", data=params) + + async def futures_coin_open_interest_hist(self, **params): + return await self._request_futures_coin_data_api("get", "openInterestHist", data=params) + + async def futures_coin_leverage_bracket(self, **params): + return await self._request_futures_coin_api( + "get", "leverageBracket", version=2, signed=True, data=params + ) + + async def new_transfer_history(self, **params): + return await self._request_margin_api("get", "asset/transfer", True, data=params) + + async def universal_transfer(self, **params): + return await self._request_margin_api( + "post", "asset/transfer", signed=True, data=params + ) + + async def futures_coin_create_order(self, **params): + return await self._request_futures_coin_api("post", "order", True, data=params) + + async def futures_coin_place_batch_order(self, **params): + query_string = urlencode(params) + query_string = query_string.replace('%27', '%22') + params['batchOrders'] = query_string[12:] + + return await self._request_futures_coin_api('post', 'batchOrders', True, data=params) + + async def futures_coin_get_order(self, **params): + return await self._request_futures_coin_api("get", "order", True, data=params) + + async def futures_coin_get_open_orders(self, **params): + return await self._request_futures_coin_api("get", "openOrders", True, data=params) + + async def futures_coin_get_all_orders(self, **params): + return await self._request_futures_coin_api( + "get", "allOrders", signed=True, data=params + ) + + async def futures_coin_cancel_order(self, **params): + return await self._request_futures_coin_api( + "delete", "order", signed=True, data=params + ) + + async def futures_coin_cancel_all_open_orders(self, **params): + return await self._request_futures_coin_api( + "delete", "allOpenOrders", signed=True, data=params + ) + + async def futures_coin_cancel_orders(self, **params): + return await self._request_futures_coin_api( + "delete", "batchOrders", True, data=params + ) + + async def futures_coin_account_balance(self, **params): + return await self._request_futures_coin_api( + "get", "balance", signed=True, data=params + ) + + async def futures_coin_account(self, **params): + return await self._request_futures_coin_api( + "get", "account", signed=True, data=params + ) + + async def futures_coin_change_leverage(self, **params): + return await self._request_futures_coin_api( + "post", "leverage", signed=True, data=params + ) + + async def futures_coin_change_margin_type(self, **params): + return await self._request_futures_coin_api( + "post", "marginType", signed=True, data=params + ) + + async def futures_coin_change_position_margin(self, **params): + return await self._request_futures_coin_api( + "post", "positionMargin", True, data=params + ) + + async def futures_coin_position_margin_history(self, **params): + return await self._request_futures_coin_api( + "get", "positionMargin/history", True, data=params + ) + + async def futures_coin_position_information(self, **params): + return await self._request_futures_coin_api("get", "positionRisk", True, data=params) + + async def futures_coin_account_trades(self, **params): + return await self._request_futures_coin_api("get", "userTrades", True, data=params) + + async def futures_coin_income_history(self, **params): + return await self._request_futures_coin_api("get", "income", True, data=params) + + async def futures_coin_change_position_mode(self, **params): + return await self._request_futures_coin_api("post", "positionSide/dual", True, data=params) + + async def futures_coin_get_position_mode(self, **params): + return await self._request_futures_coin_api("get", "positionSide/dual", True, data=params) + + async def futures_coin_stream_get_listen_key(self): + res = await self._request_futures_coin_api('post', 'listenKey', signed=False, data={}) + return res['listenKey'] + + async def futures_coin_stream_keepalive(self, listenKey): + params = { + 'listenKey': listenKey + } + return await self._request_futures_coin_api('put', 'listenKey', signed=False, data=params) + + async def futures_coin_stream_close(self, listenKey): + params = { + 'listenKey': listenKey + } + return await self._request_futures_coin_api('delete', 'listenKey', signed=False, data=params) + + async def get_all_coins_info(self, **params): + return await self._request_margin_api('get', 'capital/config/getall', True, data=params) + + async def get_account_snapshot(self, **params): + return await self._request_margin_api('get', 'accountSnapshot', True, data=params) + + async def disable_fast_withdraw_switch(self, **params): + return await self._request_margin_api('post', 'disableFastWithdrawSwitch', True, data=params) + + async def enable_fast_withdraw_switch(self, **params): + return await self._request_margin_api('post', 'enableFastWithdrawSwitch', True, data=params) + + """ + ==================================================================================================================== + Options API + ==================================================================================================================== + """ + + # Quoting interface endpoints + + async def options_ping(self): + return await self._request_options_api('get', 'ping') + + async def options_time(self): + return await self._request_options_api('get', 'time') + + async def options_info(self): + return await self._request_options_api('get', 'optionInfo') + + async def options_exchange_info(self): + return await self._request_options_api('get', 'exchangeInfo') + + async def options_index_price(self, **params): + return await self._request_options_api('get', 'index', data=params) + + async def options_price(self, **params): + return await self._request_options_api('get', 'ticker', data=params) + + async def options_mark_price(self, **params): + return await self._request_options_api('get', 'mark', data=params) + + async def options_order_book(self, **params): + return await self._request_options_api('get', 'depth', data=params) + + async def options_klines(self, **params): + return await self._request_options_api('get', 'klines', data=params) + + async def options_recent_trades(self, **params): + return await self._request_options_api('get', 'trades', data=params) + + async def options_historical_trades(self, **params): + return await self._request_options_api('get', 'historicalTrades', data=params) + + # Account and trading interface endpoints + + async def options_account_info(self, **params): + return await self._request_options_api('get', 'account', signed=True, data=params) + + async def options_funds_transfer(self, **params): + return await self._request_options_api('post', 'transfer', signed=True, data=params) + + async def options_positions(self, **params): + return await self._request_options_api('get', 'position', signed=True, data=params) + + async def options_bill(self, **params): + return await self._request_options_api('post', 'bill', signed=True, data=params) + + async def options_place_order(self, **params): + return await self._request_options_api('post', 'order', signed=True, data=params) + + async def options_place_batch_order(self, **params): + return await self._request_options_api('post', 'batchOrders', signed=True, data=params) + + async def options_cancel_order(self, **params): + return await self._request_options_api('delete', 'order', signed=True, data=params) + + async def options_cancel_batch_order(self, **params): + return await self._request_options_api('delete', 'batchOrders', signed=True, data=params) + + async def options_cancel_all_orders(self, **params): + return await self._request_options_api('delete', 'allOpenOrders', signed=True, data=params) + + async def options_query_order(self, **params): + return await self._request_options_api('get', 'order', signed=True, data=params) + + async def options_query_pending_orders(self, **params): + return await self._request_options_api('get', 'openOrders', signed=True, data=params) + + async def options_query_order_history(self, **params): + return await self._request_options_api('get', 'historyOrders', signed=True, data=params) + + async def options_user_trades(self, **params): + return await self._request_options_api('get', 'userTrades', signed=True, data=params) + + # Fiat Endpoints + + async def get_fiat_deposit_withdraw_history(self, **params): + return await self._request_margin_api('get', 'fiat/orders', signed=True, data=params) + + async def get_fiat_payments_history(self, **params): + return await self._request_margin_api('get', 'fiat/payments', signed=True, data=params) + + # C2C Endpoints + + async def get_c2c_trade_history(self, **params): + return await self._request_margin_api('get', 'c2c/orderMatch/listUserOrderHistory', signed=True, data=params) diff --git a/binance/streams.py b/binance/streams.py index d7a580122..560db8844 100755 --- a/binance/streams.py +++ b/binance/streams.py @@ -1,1492 +1,1492 @@ -import asyncio -import gzip -import json -import logging -import time -from asyncio import sleep -from enum import Enum -from random import random -from socket import gaierror -from typing import Optional, List, Dict, Callable, Any - -import websockets as ws -from websockets.exceptions import ConnectionClosedError - -from .client import AsyncClient -from .enums import FuturesType -from .exceptions import BinanceWebsocketUnableToConnect -from .enums import ContractType -from .threaded_stream import ThreadedApiManager - -KEEPALIVE_TIMEOUT = 5 * 60 # 5 minutes - - -class WSListenerState(Enum): - INITIALISING = 'Initialising' - STREAMING = 'Streaming' - RECONNECTING = 'Reconnecting' - EXITING = 'Exiting' - - -class BinanceSocketType(str, Enum): - SPOT = 'Spot' - USD_M_FUTURES = 'USD_M_Futures' - COIN_M_FUTURES = 'Coin_M_Futures' - OPTIONS = 'Vanilla_Options' - ACCOUNT = 'Account' - - -class ReconnectingWebsocket: - MAX_RECONNECTS = 5 - MAX_RECONNECT_SECONDS = 60 - MIN_RECONNECT_WAIT = 0.1 - TIMEOUT = 10 - NO_MESSAGE_RECONNECT_TIMEOUT = 60 - MAX_QUEUE_SIZE = 100 - - def __init__( - self, loop, url: str, path: Optional[str] = None, prefix: str = 'ws/', is_binary: bool = False, exit_coro=None - ): - self._loop = loop or asyncio.get_event_loop() - self._log = logging.getLogger(__name__) - self._path = path - self._url = url - self._exit_coro = exit_coro - self._prefix = prefix - self._reconnects = 0 - self._is_binary = is_binary - self._conn = None - self._socket = None - self.ws: Optional[ws.WebSocketClientProtocol] = None - self.ws_state = WSListenerState.INITIALISING - self._queue = asyncio.Queue(loop=self._loop) - self._handle_read_loop = None - - async def __aenter__(self): - await self.connect() - return self - - async def __aexit__(self, exc_type, exc_val, exc_tb): - if self._exit_coro: - await self._exit_coro(self._path) - self.ws_state = WSListenerState.EXITING - if self.ws: - self.ws.fail_connection() - if self._conn and hasattr(self._conn, 'protocol'): - await self._conn.__aexit__(exc_type, exc_val, exc_tb) - self.ws = None - if not self._handle_read_loop: - self._log.error("CANCEL read_loop") - await self._kill_read_loop() - - async def connect(self): - await self._before_connect() - assert self._path - self.ws_state = WSListenerState.STREAMING - ws_url = self._url + self._prefix + self._path - self._conn = ws.connect(ws_url, close_timeout=0.1) - try: - self.ws = await self._conn.__aenter__() - except: # noqa - await self._reconnect() - return - self._reconnects = 0 - await self._after_connect() - # To manage the "cannot call recv while another coroutine is already waiting for the next message" - if not self._handle_read_loop: - self._handle_read_loop = self._loop.call_soon_threadsafe(asyncio.create_task, self._read_loop()) - - async def _kill_read_loop(self): - self.ws_state = WSListenerState.EXITING - while self._handle_read_loop: - await sleep(0.1) - - async def _before_connect(self): - pass - - async def _after_connect(self): - pass - - def _handle_message(self, evt): - if self._is_binary: - try: - evt = gzip.decompress(evt) - except (ValueError, OSError): - return None - try: - return json.loads(evt) - except ValueError: - self._log.debug(f'error parsing evt json:{evt}') - return None - - async def _read_loop(self): - try: - while True: - try: - if self.ws_state == WSListenerState.RECONNECTING: - await self._run_reconnect() - - if not self.ws or self.ws_state != WSListenerState.STREAMING: - await self._wait_for_reconnect() - break - elif self.ws_state == WSListenerState.EXITING: - break - elif self.ws.state == ws.protocol.State.CLOSING: - await asyncio.sleep(0.1) - continue - elif self.ws.state == ws.protocol.State.CLOSED: - await self._reconnect() - elif self.ws_state == WSListenerState.STREAMING: - res = await asyncio.wait_for(self.ws.recv(), timeout=self.TIMEOUT) - res = self._handle_message(res) - if res: - if self._queue.qsize() < self.MAX_QUEUE_SIZE: - await self._queue.put(res) - else: - self._log.debug(f"Queue overflow {self.MAX_QUEUE_SIZE}. Message not filled") - await self._queue.put({ - 'e': 'error', - 'm': 'Queue overflow. Message not filled' - }) - raise BinanceWebsocketUnableToConnect - except asyncio.TimeoutError: - self._log.debug(f"no message in {self.TIMEOUT} seconds") - # _no_message_received_reconnect - except asyncio.CancelledError as e: - self._log.debug(f"cancelled error {e}") - break - except asyncio.IncompleteReadError as e: - self._log.debug(f"incomplete read error ({e})") - except ConnectionClosedError as e: - self._log.debug(f"connection close error ({e})") - except gaierror as e: - self._log.debug(f"DNS Error ({e})") - except BinanceWebsocketUnableToConnect as e: - self._log.debug(f"BinanceWebsocketUnableToConnect ({e})") - break - except Exception as e: - self._log.debug(f"Unknown exception ({e})") - continue - finally: - self._handle_read_loop = None # Signal the coro is stopped - self._reconnects = 0 - - async def _run_reconnect(self): - await self.before_reconnect() - if self._reconnects < self.MAX_RECONNECTS: - reconnect_wait = self._get_reconnect_wait(self._reconnects) - self._log.debug( - f"websocket reconnecting. {self.MAX_RECONNECTS - self._reconnects} reconnects left - " - f"waiting {reconnect_wait}" - ) - await asyncio.sleep(reconnect_wait) - await self.connect() - else: - self._log.error(f'Max reconnections {self.MAX_RECONNECTS} reached:') - # Signal the error - await self._queue.put({ - 'e': 'error', - 'm': 'Max reconnect retries reached' - }) - raise BinanceWebsocketUnableToConnect - - async def recv(self): - res = None - while not res: - try: - res = await asyncio.wait_for(self._queue.get(), timeout=self.TIMEOUT) - except asyncio.TimeoutError: - self._log.debug(f"no message in {self.TIMEOUT} seconds") - return res - - async def _wait_for_reconnect(self): - while self.ws_state != WSListenerState.STREAMING and self.ws_state != WSListenerState.EXITING: - await sleep(0.1) - - def _get_reconnect_wait(self, attempts: int) -> int: - expo = 2 ** attempts - return round(random() * min(self.MAX_RECONNECT_SECONDS, expo - 1) + 1) - - async def before_reconnect(self): - if self.ws: - await self._conn.__aexit__(None, None, None) - self.ws = None - self._reconnects += 1 - - def _no_message_received_reconnect(self): - self._log.debug('No message received, reconnecting') - self.ws_state = WSListenerState.RECONNECTING - - async def _reconnect(self): - self.ws_state = WSListenerState.RECONNECTING - - -class KeepAliveWebsocket(ReconnectingWebsocket): - - def __init__( - self, client: AsyncClient, loop, url, keepalive_type, prefix='ws/', is_binary=False, exit_coro=None, - user_timeout=None - ): - super().__init__(loop=loop, path=None, url=url, prefix=prefix, is_binary=is_binary, exit_coro=exit_coro) - self._keepalive_type = keepalive_type - self._client = client - self._user_timeout = user_timeout or KEEPALIVE_TIMEOUT - self._timer = None - - async def __aexit__(self, *args, **kwargs): - if not self._path: - return - if self._timer: - self._timer.cancel() - self._timer = None - await super().__aexit__(*args, **kwargs) - - async def _before_connect(self): - if not self._path: - self._path = await self._get_listen_key() - - async def _after_connect(self): - self._start_socket_timer() - - def _start_socket_timer(self): - self._timer = self._loop.call_later( - self._user_timeout, - asyncio.create_task, - self._keepalive_socket() - ) - - async def _get_listen_key(self): - if self._keepalive_type == 'user': - listen_key = await self._client.stream_get_listen_key() - elif self._keepalive_type == 'margin': # cross-margin - listen_key = await self._client.margin_stream_get_listen_key() - elif self._keepalive_type == 'futures': - listen_key = await self._client.futures_stream_get_listen_key() - elif self._keepalive_type == 'coin_futures': - listen_key = await self._client.futures_coin_stream_get_listen_key() - else: # isolated margin - # Passing symbol for isolated margin - listen_key = await self._client.isolated_margin_stream_get_listen_key(self._keepalive_type) - return listen_key - - async def _keepalive_socket(self): - try: - listen_key = await self._get_listen_key() - if listen_key != self._path: - self._log.debug("listen key changed: reconnect") - self._path = listen_key - await self._reconnect() - else: - self._log.debug("listen key same: keepalive") - if self._keepalive_type == 'user': - await self._client.stream_keepalive(self._path) - elif self._keepalive_type == 'margin': # cross-margin - await self._client.margin_stream_keepalive(self._path) - elif self._keepalive_type == 'futures': - await self._client.futures_stream_keepalive(self._path) - elif self._keepalive_type == 'coin_futures': - await self._client.futures_coin_stream_keepalive(self._path) - else: # isolated margin - # Passing symbol for isolated margin - await self._client.isolated_margin_stream_keepalive(self._keepalive_type, self._path) - except Exception: - pass # Ignore - finally: - self._start_socket_timer() - - -class BinanceSocketManager: - STREAM_URL = 'wss://stream.binance.{}:9443/' - STREAM_TESTNET_URL = 'wss://testnet.binance.vision/' - FSTREAM_URL = 'wss://fstream.binance.{}/' - FSTREAM_TESTNET_URL = 'wss://stream.binancefuture.com/' - DSTREAM_URL = 'wss://dstream.binance.{}/' - DSTREAM_TESTNET_URL = 'wss://dstream.binancefuture.com/' - VSTREAM_URL = 'wss://vstream.binance.{}/' - VSTREAM_TESTNET_URL = 'wss://testnetws.binanceops.{}/' - - WEBSOCKET_DEPTH_5 = '5' - WEBSOCKET_DEPTH_10 = '10' - WEBSOCKET_DEPTH_20 = '20' - - def __init__(self, client: AsyncClient, loop=None, user_timeout=KEEPALIVE_TIMEOUT): - """Initialise the BinanceSocketManager - - :param client: Binance API client - :type client: binance.AsyncClient - - """ - self.STREAM_URL = self.STREAM_URL.format(client.tld) - self.FSTREAM_URL = self.FSTREAM_URL.format(client.tld) - self.DSTREAM_URL = self.DSTREAM_URL.format(client.tld) - self.VSTREAM_URL = self.VSTREAM_URL.format(client.tld) - self.VSTREAM_TESTNET_URL = self.VSTREAM_TESTNET_URL.format(client.tld) - - self._conns = {} - self._loop = loop or asyncio.get_event_loop() - self._client = client - self._user_timeout = user_timeout - - self.testnet = self._client.testnet - - def _get_stream_url(self, stream_url: Optional[str] = None): - if stream_url: - return stream_url - stream_url = self.STREAM_URL - if self.testnet: - stream_url = self.STREAM_TESTNET_URL - return stream_url - - def _get_socket( - self, path: str, stream_url: Optional[str] = None, prefix: str = 'ws/', is_binary: bool = False, - socket_type: BinanceSocketType = BinanceSocketType.SPOT - ) -> str: - conn_id = f'{socket_type}_{path}' - if conn_id not in self._conns: - self._conns[conn_id] = ReconnectingWebsocket( - loop=self._loop, - path=path, - url=self._get_stream_url(stream_url), - prefix=prefix, - exit_coro=self._exit_socket, - is_binary=is_binary - ) - - return self._conns[conn_id] - - def _get_account_socket( - self, path: str, stream_url: Optional[str] = None, prefix: str = 'ws/', is_binary: bool = False - ): - conn_id = f'{BinanceSocketType.ACCOUNT}_{path}' - if conn_id not in self._conns: - self._conns[conn_id] = KeepAliveWebsocket( - client=self._client, - loop=self._loop, - url=self._get_stream_url(stream_url), - keepalive_type=path, - prefix=prefix, - exit_coro=self._exit_socket, - is_binary=is_binary, - user_timeout=self._user_timeout - ) - - return self._conns[conn_id] - - def _get_futures_socket(self, path: str, futures_type: FuturesType, prefix: str = 'stream?streams='): - socket_type: BinanceSocketType = BinanceSocketType.USD_M_FUTURES - if futures_type == FuturesType.USD_M: - stream_url = self.FSTREAM_URL - if self.testnet: - stream_url = self.FSTREAM_TESTNET_URL - else: - stream_url = self.DSTREAM_URL - if self.testnet: - stream_url = self.DSTREAM_TESTNET_URL - return self._get_socket(path, stream_url, prefix, socket_type=socket_type) - - def _get_options_socket(self, path: str, prefix: str = 'ws/'): - stream_url = self.VSTREAM_URL - if self.testnet: - stream_url = self.VSTREAM_TESTNET_URL - return self._get_socket(path, stream_url, prefix, is_binary=True, socket_type=BinanceSocketType.OPTIONS) - - async def _exit_socket(self, path: str): - await self._stop_socket(path) - - def depth_socket(self, symbol: str, depth: Optional[str] = None, interval: Optional[int] = None): - """Start a websocket for symbol market depth returning either a diff or a partial book - - https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md#partial-book-depth-streams - - :param symbol: required - :type symbol: str - :param depth: optional Number of depth entries to return, default None. If passed returns a partial book instead of a diff - :type depth: str - :param interval: optional interval for updates, default None. If not set, updates happen every second. Must be 0, None (1s) or 100 (100ms) - :type interval: int - - :returns: connection key string if successful, False otherwise - - Partial Message Format - - .. code-block:: python - - { - "lastUpdateId": 160, # Last update ID - "bids": [ # Bids to be updated - [ - "0.0024", # price level to be updated - "10", # quantity - [] # ignore - ] - ], - "asks": [ # Asks to be updated - [ - "0.0026", # price level to be updated - "100", # quantity - [] # ignore - ] - ] - } - - - Diff Message Format - - .. code-block:: python - - { - "e": "depthUpdate", # Event type - "E": 123456789, # Event time - "s": "BNBBTC", # Symbol - "U": 157, # First update ID in event - "u": 160, # Final update ID in event - "b": [ # Bids to be updated - [ - "0.0024", # price level to be updated - "10", # quantity - [] # ignore - ] - ], - "a": [ # Asks to be updated - [ - "0.0026", # price level to be updated - "100", # quantity - [] # ignore - ] - ] - } - - """ - socket_name = symbol.lower() + '@depth' - if depth and depth != '1': - socket_name = f'{socket_name}{depth}' - if interval: - if interval in [0, 100]: - socket_name = f'{socket_name}@{interval}ms' - else: - raise ValueError("Websocket interval value not allowed. Allowed values are [0, 100]") - return self._get_socket(socket_name) - - def kline_socket(self, symbol: str, interval=AsyncClient.KLINE_INTERVAL_1MINUTE): - """Start a websocket for symbol kline data - - https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md#klinecandlestick-streams - - :param symbol: required - :type symbol: str - :param interval: Kline interval, default KLINE_INTERVAL_1MINUTE - :type interval: str - - :returns: connection key string if successful, False otherwise - - Message Format - - .. code-block:: python - - { - "e": "kline", # event type - "E": 1499404907056, # event time - "s": "ETHBTC", # symbol - "k": { - "t": 1499404860000, # start time of this bar - "T": 1499404919999, # end time of this bar - "s": "ETHBTC", # symbol - "i": "1m", # interval - "f": 77462, # first trade id - "L": 77465, # last trade id - "o": "0.10278577", # open - "c": "0.10278645", # close - "h": "0.10278712", # high - "l": "0.10278518", # low - "v": "17.47929838", # volume - "n": 4, # number of trades - "x": false, # whether this bar is final - "q": "1.79662878", # quote volume - "V": "2.34879839", # volume of active buy - "Q": "0.24142166", # quote volume of active buy - "B": "13279784.01349473" # can be ignored - } - } - """ - path = f'{symbol.lower()}@kline_{interval}' - return self._get_socket(path) - - def kline_futures_socket(self, symbol: str, interval=AsyncClient.KLINE_INTERVAL_1MINUTE, - futures_type: FuturesType = FuturesType.USD_M, - contract_type: ContractType = ContractType.PERPETUAL): - """Start a websocket for symbol kline data for the perpeual futures stream - - https://binance-docs.github.io/apidocs/futures/en/#continuous-contract-kline-candlestick-streams - - :param symbol: required - :type symbol: str - :param interval: Kline interval, default KLINE_INTERVAL_1MINUTE - :type interval: str - :param futures_type: use USD-M or COIN-M futures default USD-M - :param contract_type: use PERPETUAL or CURRENT_QUARTER or NEXT_QUARTER default PERPETUAL - - :returns: connection key string if successful, False otherwise - - Message Format - - .. code-block:: python - - { - "e":"continuous_kline", // Event type - "E":1607443058651, // Event time - "ps":"BTCUSDT", // Pair - "ct":"PERPETUAL" // Contract type - "k":{ - "t":1607443020000, // Kline start time - "T":1607443079999, // Kline close time - "i":"1m", // Interval - "f":116467658886, // First trade ID - "L":116468012423, // Last trade ID - "o":"18787.00", // Open price - "c":"18804.04", // Close price - "h":"18804.04", // High price - "l":"18786.54", // Low price - "v":"197.664", // volume - "n": 543, // Number of trades - "x":false, // Is this kline closed? - "q":"3715253.19494", // Quote asset volume - "V":"184.769", // Taker buy volume - "Q":"3472925.84746", //Taker buy quote asset volume - "B":"0" // Ignore - } - } - _@continuousKline_ - """ - - path = f'{symbol.lower()}_{contract_type.value}@continuousKline_{interval}' - return self._get_futures_socket(path, prefix='ws/', futures_type=futures_type) - - def miniticker_socket(self, update_time: int = 1000): - """Start a miniticker websocket for all trades - - This is not in the official Binance api docs, but this is what - feeds the right column on a ticker page on Binance. - - :param update_time: time between callbacks in milliseconds, must be 1000 or greater - :type update_time: int - - :returns: connection key string if successful, False otherwise - - Message Format - - .. code-block:: python - - [ - { - 'e': '24hrMiniTicker', # Event type - 'E': 1515906156273, # Event time - 's': 'QTUMETH', # Symbol - 'c': '0.03836900', # close - 'o': '0.03953500', # open - 'h': '0.04400000', # high - 'l': '0.03756000', # low - 'v': '147435.80000000', # volume - 'q': '5903.84338533' # quote volume - } - ] - """ - - return self._get_socket(f'!miniTicker@arr@{update_time}ms') - - def trade_socket(self, symbol: str): - """Start a websocket for symbol trade data - - https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md#trade-streams - - :param symbol: required - :type symbol: str - - :returns: connection key string if successful, False otherwise - - Message Format - - .. code-block:: python - - { - "e": "trade", # Event type - "E": 123456789, # Event time - "s": "BNBBTC", # Symbol - "t": 12345, # Trade ID - "p": "0.001", # Price - "q": "100", # Quantity - "b": 88, # Buyer order Id - "a": 50, # Seller order Id - "T": 123456785, # Trade time - "m": true, # Is the buyer the market maker? - "M": true # Ignore. - } - - """ - - return self._get_socket(symbol.lower() + '@trade') - - def aggtrade_socket(self, symbol: str): - """Start a websocket for symbol trade data - - https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md#aggregate-trade-streams - - :param symbol: required - :type symbol: str - - :returns: connection key string if successful, False otherwise - - Message Format - - .. code-block:: python - - { - "e": "aggTrade", # event type - "E": 1499405254326, # event time - "s": "ETHBTC", # symbol - "a": 70232, # aggregated tradeid - "p": "0.10281118", # price - "q": "8.15632997", # quantity - "f": 77489, # first breakdown trade id - "l": 77489, # last breakdown trade id - "T": 1499405254324, # trade time - "m": false, # whether buyer is a maker - "M": true # can be ignored - } - - """ - return self._get_socket(symbol.lower() + '@aggTrade') - - def aggtrade_futures_socket(self, symbol: str, futures_type: FuturesType = FuturesType.USD_M): - """Start a websocket for aggregate symbol trade data for the futures stream - - :param symbol: required - :param futures_type: use USD-M or COIN-M futures default USD-M - - :returns: connection key string if successful, False otherwise - - Message Format - - .. code-block:: python - - { - "e": "aggTrade", // Event type - "E": 123456789, // Event time - "s": "BTCUSDT", // Symbol - "a": 5933014, // Aggregate trade ID - "p": "0.001", // Price - "q": "100", // Quantity - "f": 100, // First trade ID - "l": 105, // Last trade ID - "T": 123456785, // Trade time - "m": true, // Is the buyer the market maker? - } - - """ - return self._get_futures_socket(symbol.lower() + '@aggTrade', futures_type=futures_type) - - def symbol_miniticker_socket(self, symbol: str): - """Start a websocket for a symbol's miniTicker data - - https://binance-docs.github.io/apidocs/spot/en/#individual-symbol-mini-ticker-stream - - :param symbol: required - :type symbol: str - - :returns: connection key string if successful, False otherwise - - Message Format - - .. code-block:: python - - { - "e": "24hrMiniTicker", // Event type - "E": 123456789, // Event time - "s": "BNBBTC", // Symbol - "c": "0.0025", // Close price - "o": "0.0010", // Open price - "h": "0.0025", // High price - "l": "0.0010", // Low price - "v": "10000", // Total traded base asset volume - "q": "18" // Total traded quote asset volume - } - - """ - return self._get_socket(symbol.lower() + '@miniTicker') - - def symbol_ticker_socket(self, symbol: str): - """Start a websocket for a symbol's ticker data - - https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md#individual-symbol-ticker-streams - - :param symbol: required - :type symbol: str - - :returns: connection key string if successful, False otherwise - - Message Format - - .. code-block:: python - - { - "e": "24hrTicker", # Event type - "E": 123456789, # Event time - "s": "BNBBTC", # Symbol - "p": "0.0015", # Price change - "P": "250.00", # Price change percent - "w": "0.0018", # Weighted average price - "x": "0.0009", # Previous day's close price - "c": "0.0025", # Current day's close price - "Q": "10", # Close trade's quantity - "b": "0.0024", # Best bid price - "B": "10", # Bid bid quantity - "a": "0.0026", # Best ask price - "A": "100", # Best ask quantity - "o": "0.0010", # Open price - "h": "0.0025", # High price - "l": "0.0010", # Low price - "v": "10000", # Total traded base asset volume - "q": "18", # Total traded quote asset volume - "O": 0, # Statistics open time - "C": 86400000, # Statistics close time - "F": 0, # First trade ID - "L": 18150, # Last trade Id - "n": 18151 # Total number of trades - } - - """ - return self._get_socket(symbol.lower() + '@ticker') - - def ticker_socket(self): - """Start a websocket for all ticker data - - By default all markets are included in an array. - - https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md#all-market-tickers-stream - - :param coro: callback function to handle messages - :type coro: function - - :returns: connection key string if successful, False otherwise - - Message Format - - .. code-block:: python - - [ - { - 'F': 278610, - 'o': '0.07393000', - 's': 'BCCBTC', - 'C': 1509622420916, - 'b': '0.07800800', - 'l': '0.07160300', - 'h': '0.08199900', - 'L': 287722, - 'P': '6.694', - 'Q': '0.10000000', - 'q': '1202.67106335', - 'p': '0.00494900', - 'O': 1509536020916, - 'a': '0.07887800', - 'n': 9113, - 'B': '1.00000000', - 'c': '0.07887900', - 'x': '0.07399600', - 'w': '0.07639068', - 'A': '2.41900000', - 'v': '15743.68900000' - } - ] - """ - return self._get_socket('!ticker@arr') - - def index_price_socket(self, symbol: str, fast: bool = True): - """Start a websocket for a symbol's futures mark price - https://binance-docs.github.io/apidocs/delivery/en/#index-price-stream - :param symbol: required - :param fast: use faster or 1s default - :returns: connection key string if successful, False otherwise - - Message Format - .. code-block:: python - { - "e": "indexPriceUpdate", // Event type - "E": 1591261236000, // Event time - "i": "BTCUSD", // Pair - "p": "9636.57860000", // Index Price - } - """ - stream_name = '@indexPrice@1s' if fast else '@indexPrice' - return self._get_futures_socket(symbol.lower() + stream_name, futures_type=FuturesType.COIN_M) - - def symbol_mark_price_socket(self, symbol: str, fast: bool = True, futures_type: FuturesType = FuturesType.USD_M): - """Start a websocket for a symbol's futures mark price - https://binance-docs.github.io/apidocs/futures/en/#mark-price-stream - :param symbol: required - :param fast: use faster or 1s default - :param futures_type: use USD-M or COIN-M futures default USD-M - :returns: connection key string if successful, False otherwise - Message Format - .. code-block:: python - { - "e": "markPriceUpdate", // Event type - "E": 1562305380000, // Event time - "s": "BTCUSDT", // Symbol - "p": "11185.87786614", // Mark price - "r": "0.00030000", // Funding rate - "T": 1562306400000 // Next funding time - } - """ - stream_name = '@markPrice@1s' if fast else '@markPrice' - return self._get_futures_socket(symbol.lower() + stream_name, futures_type=futures_type) - - def all_mark_price_socket(self, fast: bool = True, futures_type: FuturesType = FuturesType.USD_M): - """Start a websocket for all futures mark price data - By default all symbols are included in an array. - https://binance-docs.github.io/apidocs/futures/en/#mark-price-stream-for-all-market - :param fast: use faster or 1s default - :param futures_type: use USD-M or COIN-M futures default USD-M - :returns: connection key string if successful, False otherwise - Message Format - .. code-block:: python - - [ - { - "e": "markPriceUpdate", // Event type - "E": 1562305380000, // Event time - "s": "BTCUSDT", // Symbol - "p": "11185.87786614", // Mark price - "r": "0.00030000", // Funding rate - "T": 1562306400000 // Next funding time - } - ] - """ - stream_name = '!markPrice@arr@1s' if fast else '!markPrice@arr' - return self._get_futures_socket(stream_name, futures_type=futures_type) - - def symbol_ticker_futures_socket(self, symbol: str, futures_type: FuturesType = FuturesType.USD_M): - """Start a websocket for a symbol's ticker data - By default all markets are included in an array. - https://binance-docs.github.io/apidocs/futures/en/#individual-symbol-book-ticker-streams - :param symbol: required - :param futures_type: use USD-M or COIN-M futures default USD-M - :returns: connection key string if successful, False otherwise - .. code-block:: python - [ - { - "u":400900217, // order book updateId - "s":"BNBUSDT", // symbol - "b":"25.35190000", // best bid price - "B":"31.21000000", // best bid qty - "a":"25.36520000", // best ask price - "A":"40.66000000" // best ask qty - } - ] - """ - return self._get_futures_socket(symbol.lower() + '@bookTicker', futures_type=futures_type) - - def individual_symbol_ticker_futures_socket(self, symbol: str, futures_type: FuturesType = FuturesType.USD_M): - """Start a futures websocket for a single symbol's ticker data - https://binance-docs.github.io/apidocs/futures/en/#individual-symbol-ticker-streams - :param symbol: required - :type symbol: str - :param futures_type: use USD-M or COIN-M futures default USD-M - :returns: connection key string if successful, False otherwise - .. code-block:: python - { - "e": "24hrTicker", // Event type - "E": 123456789, // Event time - "s": "BTCUSDT", // Symbol - "p": "0.0015", // Price change - } - """ - return self._get_futures_socket(symbol.lower() + '@ticker', futures_type=futures_type) - - def all_ticker_futures_socket(self, futures_type: FuturesType = FuturesType.USD_M): - """Start a websocket for all ticker data - By default all markets are included in an array. - https://binance-docs.github.io/apidocs/futures/en/#all-book-tickers-stream - :param futures_type: use USD-M or COIN-M futures default USD-M - :returns: connection key string if successful, False otherwise - Message Format - .. code-block:: python - [ - { - "u":400900217, // order book updateId - "s":"BNBUSDT", // symbol - "b":"25.35190000", // best bid price - "B":"31.21000000", // best bid qty - "a":"25.36520000", // best ask price - "A":"40.66000000" // best ask qty - } - ] - """ - - return self._get_futures_socket('!bookTicker', futures_type=futures_type) - - def symbol_book_ticker_socket(self, symbol: str): - """Start a websocket for the best bid or ask's price or quantity for a specified symbol. - - https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md#individual-symbol-book-ticker-streams - - :param symbol: required - :type symbol: str - - :returns: connection key string if successful, False otherwise - - Message Format - - .. code-block:: python - - { - "u":400900217, // order book updateId - "s":"BNBUSDT", // symbol - "b":"25.35190000", // best bid price - "B":"31.21000000", // best bid qty - "a":"25.36520000", // best ask price - "A":"40.66000000" // best ask qty - } - - """ - return self._get_socket(symbol.lower() + '@bookTicker') - - def book_ticker_socket(self): - """Start a websocket for the best bid or ask's price or quantity for all symbols. - - https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md#all-book-tickers-stream - - :returns: connection key string if successful, False otherwise - - Message Format - - .. code-block:: python - - { - // Same as @bookTicker payload - } - - """ - return self._get_socket('!bookTicker') - - def multiplex_socket(self, streams: List[str]): - """Start a multiplexed socket using a list of socket names. - User stream sockets can not be included. - - Symbols in socket name must be lowercase i.e bnbbtc@aggTrade, neobtc@ticker - - Combined stream events are wrapped as follows: {"stream":"","data":} - - https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md - - :param streams: list of stream names in lower case - :type streams: list - - :returns: connection key string if successful, False otherwise - - Message Format - see Binance API docs for all types - - """ - path = f'streams={"/".join(streams)}' - return self._get_socket(path, prefix='stream?') - - def options_multiplex_socket(self, streams: List[str]): - """Start a multiplexed socket using a list of socket names. - User stream sockets can not be included. - - Symbols in socket name must be lowercase i.e bnbbtc@aggTrade, neobtc@ticker - - Combined stream events are wrapped as follows: {"stream":"","data":} - - https://binance-docs.github.io/apidocs/voptions/en/#account-and-trading-interface - - :param streams: list of stream names in lower case - :type streams: list - - :returns: connection key string if successful, False otherwise - - Message Format - see Binance API docs for all types - - """ - stream_name = '/'.join([s.lower() for s in streams]) - stream_path = f'streams={stream_name}' - return self._get_options_socket(stream_path, prefix='stream?') - - def futures_multiplex_socket(self, streams: List[str], futures_type: FuturesType = FuturesType.USD_M): - """Start a multiplexed socket using a list of socket names. - User stream sockets can not be included. - - Symbols in socket name must be lowercase i.e bnbbtc@aggTrade, neobtc@ticker - - Combined stream events are wrapped as follows: {"stream":"","data":} - - https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md - - :param streams: list of stream names in lower case - :param futures_type: use USD-M or COIN-M futures default USD-M - - :returns: connection key string if successful, False otherwise - - Message Format - see Binance API docs for all types - - """ - path = f'streams={"/".join(streams)}' - return self._get_futures_socket(path, prefix='stream?', futures_type=futures_type) - - def futures_depth_socket(self, symbol: str, depth: str = '10', futures_type: FuturesType = FuturesType.USD_M): - """Subscribe to a depth data stream - - https://binance-docs.github.io/apidocs/futures/en/#partial-book-depth-streams - - :param symbol: required - :type symbol: str - :param depth: optional Number of depth entries to return, default 10. - :type depth: str - """ - return self._get_futures_socket(symbol.lower() + '@depth' + str(depth), futures_type=futures_type) - - def user_socket(self): - """Start a websocket for user data - - https://github.com/binance-exchange/binance-official-api-docs/blob/master/user-data-stream.md - https://binance-docs.github.io/apidocs/spot/en/#listen-key-spot - - :returns: connection key string if successful, False otherwise - - Message Format - see Binance API docs for all types - """ - return self._get_account_socket('user') - - def futures_user_socket(self): - """Start a websocket for coin futures user data - - https://binance-docs.github.io/apidocs/futures/en/#user-data-streams - - :returns: connection key string if successful, False otherwise - - Message Format - see Binanace API docs for all types - """ - - return self._get_account_socket('futures', stream_url=self.FSTREAM_URL) - - def margin_socket(self): - """Start a websocket for cross-margin data - - https://binance-docs.github.io/apidocs/spot/en/#listen-key-margin - - :returns: connection key string if successful, False otherwise - - Message Format - see Binance API docs for all types - """ - return self._get_account_socket('margin') - - def futures_socket(self): - """Start a websocket for futures data - - https://binance-docs.github.io/apidocs/futures/en/#websocket-market-streams - - :returns: connection key string if successful, False otherwise - - Message Format - see Binance API docs for all types - """ - return self._get_account_socket('futures', stream_url=self.FSTREAM_URL) - - def coin_futures_socket(self): - """Start a websocket for coin futures data - - https://binance-docs.github.io/apidocs/delivery/en/#websocket-market-streams - - :returns: connection key string if successful, False otherwise - - Message Format - see Binance API docs for all types - """ - return self._get_account_socket('coin_futures', stream_url=self.DSTREAM_URL) - - def isolated_margin_socket(self, symbol: str): - """Start a websocket for isolated margin data - - https://binance-docs.github.io/apidocs/spot/en/#listen-key-isolated-margin - - :param symbol: required - symbol for the isolated margin account - :type symbol: str - - :returns: connection key string if successful, False otherwise - - Message Format - see Binance API docs for all types - """ - return self._get_account_socket(symbol) - - def options_ticker_socket(self, symbol: str): - """Subscribe to a 24 hour ticker info stream - - https://binance-docs.github.io/apidocs/voptions/en/#market-streams-payload-24-hour-ticker - - :param symbol: required - :type symbol: str - """ - return self._get_options_socket(symbol.lower() + '@ticker') - - def options_recent_trades_socket(self, symbol: str): - """Subscribe to a latest completed trades stream - - https://binance-docs.github.io/apidocs/voptions/en/#market-streams-payload-latest-completed-trades - - :param symbol: required - :type symbol: str - """ - return self._get_options_socket(symbol.lower() + '@trade') - - def options_kline_socket(self, symbol: str, interval=AsyncClient.KLINE_INTERVAL_1MINUTE): - """Subscribe to a candlestick data stream - - https://binance-docs.github.io/apidocs/voptions/en/#market-streams-payload-candle - - :param symbol: required - :type symbol: str - :param interval: Kline interval, default KLINE_INTERVAL_1MINUTE - :type interval: str - """ - return self._get_options_socket(symbol.lower() + '@kline_' + interval) - - def options_depth_socket(self, symbol: str, depth: str = '10'): - """Subscribe to a depth data stream - - https://binance-docs.github.io/apidocs/voptions/en/#market-streams-payload-depth - - :param symbol: required - :type symbol: str - :param depth: optional Number of depth entries to return, default 10. - :type depth: str - """ - return self._get_options_socket(symbol.lower() + '@depth' + str(depth)) - - async def _stop_socket(self, conn_key): - """Stop a websocket given the connection key - - :param conn_key: Socket connection key - :type conn_key: string - - :returns: None - """ - if conn_key not in self._conns: - return - - del (self._conns[conn_key]) - - -class ThreadedWebsocketManager(ThreadedApiManager): - - def __init__( - self, api_key: Optional[str] = None, api_secret: Optional[str] = None, - requests_params: Dict[str, str] = None, tld: str = 'com', - testnet: bool = False - ): - super().__init__(api_key, api_secret, requests_params, tld, testnet) - self._bsm: Optional[BinanceSocketManager] = None - - async def _before_socket_listener_start(self): - assert self._client - self._bsm = BinanceSocketManager(client=self._client, loop=self._loop) - - def _start_async_socket( - self, callback: Callable, socket_name: str, params: Dict[str, Any], path: Optional[str] = None - ) -> str: - while not self._bsm: - time.sleep(0.1) - socket = getattr(self._bsm, socket_name)(**params) - path = path or socket._path # noqa - self._socket_running[path] = True - self._loop.call_soon_threadsafe(asyncio.create_task, self.start_listener(socket, socket._path, callback)) - return path - - def start_depth_socket( - self, callback: Callable, symbol: str, depth: Optional[str] = None, interval: Optional[int] = None - ) -> str: - return self._start_async_socket( - callback=callback, - socket_name='depth_socket', - params={ - 'symbol': symbol, - 'depth': depth, - 'interval': interval, - } - ) - - def start_kline_socket(self, callback: Callable, symbol: str, interval=AsyncClient.KLINE_INTERVAL_1MINUTE) -> str: - return self._start_async_socket( - callback=callback, - socket_name='kline_socket', - params={ - 'symbol': symbol, - 'interval': interval, - } - ) - - def start_kline_futures_socket(self, callback: Callable, symbol: str, - interval=AsyncClient.KLINE_INTERVAL_1MINUTE, - futures_type: FuturesType = FuturesType.USD_M, - contract_type: ContractType = ContractType.PERPETUAL) -> str: - return self._start_async_socket( - callback=callback, - socket_name='kline_futures_socket', - params={ - 'symbol': symbol, - 'interval': interval, - 'futures_type': futures_type, - 'contract_type': contract_type - } - ) - - def start_miniticker_socket(self, callback: Callable, update_time: int = 1000) -> str: - return self._start_async_socket( - callback=callback, - socket_name='miniticker_socket', - params={ - 'update_time': update_time, - } - ) - - def start_trade_socket(self, callback: Callable, symbol: str) -> str: - return self._start_async_socket( - callback=callback, - socket_name='trade_socket', - params={ - 'symbol': symbol, - } - ) - - def start_aggtrade_socket(self, callback: Callable, symbol: str) -> str: - return self._start_async_socket( - callback=callback, - socket_name='aggtrade_socket', - params={ - 'symbol': symbol, - } - ) - - def start_aggtrade_futures_socket( - self, callback: Callable, symbol: str, futures_type: FuturesType = FuturesType.USD_M - ) -> str: - return self._start_async_socket( - callback=callback, - socket_name='aggtrade_futures_socket', - params={ - 'symbol': symbol, - 'futures_type': futures_type, - } - ) - - def start_symbol_miniticker_socket(self, callback: Callable, symbol: str) -> str: - return self._start_async_socket( - callback=callback, - socket_name='symbol_miniticker_socket', - params={ - 'symbol': symbol, - } - ) - - def start_symbol_ticker_socket(self, callback: Callable, symbol: str) -> str: - return self._start_async_socket( - callback=callback, - socket_name='symbol_ticker_socket', - params={ - 'symbol': symbol, - } - ) - - def start_ticker_socket(self, callback: Callable) -> str: - return self._start_async_socket( - callback=callback, - socket_name='ticker_socket', - params={} - ) - - def start_index_price_socket(self, callback: Callable, symbol: str, fast: bool = True) -> str: - return self._start_async_socket( - callback=callback, - socket_name='index_price_socket', - params={ - 'symbol': symbol, - 'fast': fast - } - ) - - def start_symbol_mark_price_socket( - self, callback: Callable, symbol: str, fast: bool = True, futures_type: FuturesType = FuturesType.USD_M - ) -> str: - return self._start_async_socket( - callback=callback, - socket_name='symbol_mark_price_socket', - params={ - 'symbol': symbol, - 'fast': fast, - 'futures_type': futures_type - } - ) - - def start_all_mark_price_socket( - self, callback: Callable, fast: bool = True, futures_type: FuturesType = FuturesType.USD_M - ) -> str: - return self._start_async_socket( - callback=callback, - socket_name='all_mark_price_socket', - params={ - 'fast': fast, - 'futures_type': futures_type - } - ) - - def start_symbol_ticker_futures_socket( - self, callback: Callable, symbol: str, futures_type: FuturesType = FuturesType.USD_M - ) -> str: - return self._start_async_socket( - callback=callback, - socket_name='symbol_ticker_futures_socket', - params={ - 'symbol': symbol, - 'futures_type': futures_type - } - ) - - def start_individual_symbol_ticker_futures_socket( - self, callback: Callable, symbol: str, futures_type: FuturesType = FuturesType.USD_M - ) -> str: - return self._start_async_socket( - callback=callback, - socket_name='individual_symbol_ticker_futures_socket', - params={ - 'symbol': symbol, - 'futures_type': futures_type - } - ) - - def start_all_ticker_futures_socket(self, callback: Callable, futures_type: FuturesType = FuturesType.USD_M) -> str: - return self._start_async_socket( - callback=callback, - socket_name='all_ticker_futures_socket', - params={ - 'futures_type': futures_type - } - ) - - def start_symbol_book_ticker_socket(self, callback: Callable, symbol: str) -> str: - return self._start_async_socket( - callback=callback, - socket_name='symbol_book_ticker_socket', - params={ - 'symbol': symbol - } - ) - - def start_book_ticker_socket(self, callback: Callable) -> str: - return self._start_async_socket( - callback=callback, - socket_name='book_ticker_socket', - params={} - ) - - def start_multiplex_socket(self, callback: Callable, streams: List[str]) -> str: - return self._start_async_socket( - callback=callback, - socket_name='multiplex_socket', - params={ - 'streams': streams - } - ) - - def start_options_multiplex_socket(self, callback: Callable, streams: List[str]) -> str: - return self._start_async_socket( - callback=callback, - socket_name='options_multiplex_socket', - params={ - 'streams': streams - } - ) - - def start_futures_multiplex_socket( - self, callback: Callable, streams: List[str], futures_type: FuturesType = FuturesType.USD_M - ) -> str: - return self._start_async_socket( - callback=callback, - socket_name='futures_multiplex_socket', - params={ - 'streams': streams, - 'futures_type': futures_type - } - ) - - def start_user_socket(self, callback: Callable) -> str: - return self._start_async_socket( - callback=callback, - socket_name='user_socket', - params={} - ) - - def start_margin_socket(self, callback: Callable) -> str: - return self._start_async_socket( - callback=callback, - socket_name='margin_socket', - params={} - ) - - def start_futures_socket(self, callback: Callable) -> str: - return self._start_async_socket( - callback=callback, - socket_name='futures_socket', - params={} - ) - - def start_coin_futures_socket(self, callback: Callable) -> str: - return self._start_async_socket( - callback=callback, - socket_name='coin_futures_socket', - params={} - ) - - def start_isolated_margin_socket(self, callback: Callable, symbol: str) -> str: - return self._start_async_socket( - callback=callback, - socket_name='isolated_margin_socket', - params={ - 'symbol': symbol - } - ) - - def start_options_ticker_socket(self, callback: Callable, symbol: str) -> str: - return self._start_async_socket( - callback=callback, - socket_name='options_ticker_socket', - params={ - 'symbol': symbol - } - ) - - def start_options_recent_trades_socket(self, callback: Callable, symbol: str) -> str: - return self._start_async_socket( - callback=callback, - socket_name='options_recent_trades_socket', - params={ - 'symbol': symbol - } - ) - - def start_options_kline_socket( - self, callback: Callable, symbol: str, interval=AsyncClient.KLINE_INTERVAL_1MINUTE - ) -> str: - return self._start_async_socket( - callback=callback, - socket_name='options_kline_socket', - params={ - 'symbol': symbol, - 'interval': interval - } - ) - - def start_options_depth_socket(self, callback: Callable, symbol: str, depth: str = '10') -> str: - return self._start_async_socket( - callback=callback, - socket_name='options_depth_socket', - params={ - 'symbol': symbol, - 'depth': depth - } - ) +import asyncio +import gzip +import json +import logging +import time +from asyncio import sleep +from enum import Enum +from random import random +from socket import gaierror +from typing import Optional, List, Dict, Callable, Any + +import websockets as ws +from websockets.exceptions import ConnectionClosedError + +from .client import AsyncClient +from .enums import FuturesType +from .exceptions import BinanceWebsocketUnableToConnect +from .enums import ContractType +from .threaded_stream import ThreadedApiManager + +KEEPALIVE_TIMEOUT = 5 * 60 # 5 minutes + + +class WSListenerState(Enum): + INITIALISING = 'Initialising' + STREAMING = 'Streaming' + RECONNECTING = 'Reconnecting' + EXITING = 'Exiting' + + +class BinanceSocketType(str, Enum): + SPOT = 'Spot' + USD_M_FUTURES = 'USD_M_Futures' + COIN_M_FUTURES = 'Coin_M_Futures' + OPTIONS = 'Vanilla_Options' + ACCOUNT = 'Account' + + +class ReconnectingWebsocket: + MAX_RECONNECTS = 5 + MAX_RECONNECT_SECONDS = 60 + MIN_RECONNECT_WAIT = 0.1 + TIMEOUT = 10 + NO_MESSAGE_RECONNECT_TIMEOUT = 60 + MAX_QUEUE_SIZE = 10000 + + def __init__( + self, loop, url: str, path: Optional[str] = None, prefix: str = 'ws/', is_binary: bool = False, exit_coro=None + ): + self._loop = loop or asyncio.get_event_loop() + self._log = logging.getLogger(__name__) + self._path = path + self._url = url + self._exit_coro = exit_coro + self._prefix = prefix + self._reconnects = 0 + self._is_binary = is_binary + self._conn = None + self._socket = None + self.ws: Optional[ws.WebSocketClientProtocol] = None + self.ws_state = WSListenerState.INITIALISING + self._queue = asyncio.Queue(loop=self._loop) + self._handle_read_loop = None + + async def __aenter__(self): + await self.connect() + return self + + async def __aexit__(self, exc_type, exc_val, exc_tb): + if self._exit_coro: + await self._exit_coro(self._path) + self.ws_state = WSListenerState.EXITING + if self.ws: + self.ws.fail_connection() + if self._conn and hasattr(self._conn, 'protocol'): + await self._conn.__aexit__(exc_type, exc_val, exc_tb) + self.ws = None + if not self._handle_read_loop: + self._log.error("CANCEL read_loop") + await self._kill_read_loop() + + async def connect(self): + await self._before_connect() + assert self._path + self.ws_state = WSListenerState.STREAMING + ws_url = self._url + self._prefix + self._path + self._conn = ws.connect(ws_url, close_timeout=0.1) + try: + self.ws = await self._conn.__aenter__() + except: # noqa + await self._reconnect() + return + self._reconnects = 0 + await self._after_connect() + # To manage the "cannot call recv while another coroutine is already waiting for the next message" + if not self._handle_read_loop: + self._handle_read_loop = self._loop.call_soon_threadsafe(asyncio.create_task, self._read_loop()) + + async def _kill_read_loop(self): + self.ws_state = WSListenerState.EXITING + while self._handle_read_loop: + await sleep(0.1) + + async def _before_connect(self): + pass + + async def _after_connect(self): + pass + + def _handle_message(self, evt): + if self._is_binary: + try: + evt = gzip.decompress(evt) + except (ValueError, OSError): + return None + try: + return json.loads(evt) + except ValueError: + self._log.debug(f'error parsing evt json:{evt}') + return None + + async def _read_loop(self): + try: + while True: + try: + if self.ws_state == WSListenerState.RECONNECTING: + await self._run_reconnect() + + if not self.ws or self.ws_state != WSListenerState.STREAMING: + await self._wait_for_reconnect() + break + elif self.ws_state == WSListenerState.EXITING: + break + elif self.ws.state == ws.protocol.State.CLOSING: + await asyncio.sleep(0.1) + continue + elif self.ws.state == ws.protocol.State.CLOSED: + await self._reconnect() + elif self.ws_state == WSListenerState.STREAMING: + res = await asyncio.wait_for(self.ws.recv(), timeout=self.TIMEOUT) + res = self._handle_message(res) + if res: + if self._queue.qsize() < self.MAX_QUEUE_SIZE: + await self._queue.put(res) + else: + self._log.debug(f"Queue overflow {self.MAX_QUEUE_SIZE}. Message not filled") + await self._queue.put({ + 'e': 'error', + 'm': 'Queue overflow. Message not filled' + }) + raise BinanceWebsocketUnableToConnect + except asyncio.TimeoutError: + self._log.debug(f"no message in {self.TIMEOUT} seconds") + # _no_message_received_reconnect + except asyncio.CancelledError as e: + self._log.debug(f"cancelled error {e}") + break + except asyncio.IncompleteReadError as e: + self._log.debug(f"incomplete read error ({e})") + except ConnectionClosedError as e: + self._log.debug(f"connection close error ({e})") + except gaierror as e: + self._log.debug(f"DNS Error ({e})") + except BinanceWebsocketUnableToConnect as e: + self._log.debug(f"BinanceWebsocketUnableToConnect ({e})") + break + except Exception as e: + self._log.debug(f"Unknown exception ({e})") + continue + finally: + self._handle_read_loop = None # Signal the coro is stopped + self._reconnects = 0 + + async def _run_reconnect(self): + await self.before_reconnect() + if self._reconnects < self.MAX_RECONNECTS: + reconnect_wait = self._get_reconnect_wait(self._reconnects) + self._log.debug( + f"websocket reconnecting. {self.MAX_RECONNECTS - self._reconnects} reconnects left - " + f"waiting {reconnect_wait}" + ) + await asyncio.sleep(reconnect_wait) + await self.connect() + else: + self._log.error(f'Max reconnections {self.MAX_RECONNECTS} reached:') + # Signal the error + await self._queue.put({ + 'e': 'error', + 'm': 'Max reconnect retries reached' + }) + raise BinanceWebsocketUnableToConnect + + async def recv(self): + res = None + while not res: + try: + res = await asyncio.wait_for(self._queue.get(), timeout=self.TIMEOUT) + except asyncio.TimeoutError: + self._log.debug(f"no message in {self.TIMEOUT} seconds") + return res + + async def _wait_for_reconnect(self): + while self.ws_state != WSListenerState.STREAMING and self.ws_state != WSListenerState.EXITING: + await sleep(0.1) + + def _get_reconnect_wait(self, attempts: int) -> int: + expo = 2 ** attempts + return round(random() * min(self.MAX_RECONNECT_SECONDS, expo - 1) + 1) + + async def before_reconnect(self): + if self.ws: + await self._conn.__aexit__(None, None, None) + self.ws = None + self._reconnects += 1 + + def _no_message_received_reconnect(self): + self._log.debug('No message received, reconnecting') + self.ws_state = WSListenerState.RECONNECTING + + async def _reconnect(self): + self.ws_state = WSListenerState.RECONNECTING + + +class KeepAliveWebsocket(ReconnectingWebsocket): + + def __init__( + self, client: AsyncClient, loop, url, keepalive_type, prefix='ws/', is_binary=False, exit_coro=None, + user_timeout=None + ): + super().__init__(loop=loop, path=None, url=url, prefix=prefix, is_binary=is_binary, exit_coro=exit_coro) + self._keepalive_type = keepalive_type + self._client = client + self._user_timeout = user_timeout or KEEPALIVE_TIMEOUT + self._timer = None + + async def __aexit__(self, *args, **kwargs): + if not self._path: + return + if self._timer: + self._timer.cancel() + self._timer = None + await super().__aexit__(*args, **kwargs) + + async def _before_connect(self): + if not self._path: + self._path = await self._get_listen_key() + + async def _after_connect(self): + self._start_socket_timer() + + def _start_socket_timer(self): + self._timer = self._loop.call_later( + self._user_timeout, + asyncio.create_task, + self._keepalive_socket() + ) + + async def _get_listen_key(self): + if self._keepalive_type == 'user': + listen_key = await self._client.stream_get_listen_key() + elif self._keepalive_type == 'margin': # cross-margin + listen_key = await self._client.margin_stream_get_listen_key() + elif self._keepalive_type == 'futures': + listen_key = await self._client.futures_stream_get_listen_key() + elif self._keepalive_type == 'coin_futures': + listen_key = await self._client.futures_coin_stream_get_listen_key() + else: # isolated margin + # Passing symbol for isolated margin + listen_key = await self._client.isolated_margin_stream_get_listen_key(self._keepalive_type) + return listen_key + + async def _keepalive_socket(self): + try: + listen_key = await self._get_listen_key() + if listen_key != self._path: + self._log.debug("listen key changed: reconnect") + self._path = listen_key + await self._reconnect() + else: + self._log.debug("listen key same: keepalive") + if self._keepalive_type == 'user': + await self._client.stream_keepalive(self._path) + elif self._keepalive_type == 'margin': # cross-margin + await self._client.margin_stream_keepalive(self._path) + elif self._keepalive_type == 'futures': + await self._client.futures_stream_keepalive(self._path) + elif self._keepalive_type == 'coin_futures': + await self._client.futures_coin_stream_keepalive(self._path) + else: # isolated margin + # Passing symbol for isolated margin + await self._client.isolated_margin_stream_keepalive(self._keepalive_type, self._path) + except Exception: + pass # Ignore + finally: + self._start_socket_timer() + + +class BinanceSocketManager: + STREAM_URL = 'wss://stream.binance.{}:9443/' + STREAM_TESTNET_URL = 'wss://testnet.binance.vision/' + FSTREAM_URL = 'wss://fstream.binance.{}/' + FSTREAM_TESTNET_URL = 'wss://stream.binancefuture.com/' + DSTREAM_URL = 'wss://dstream.binance.{}/' + DSTREAM_TESTNET_URL = 'wss://dstream.binancefuture.com/' + VSTREAM_URL = 'wss://vstream.binance.{}/' + VSTREAM_TESTNET_URL = 'wss://testnetws.binanceops.{}/' + + WEBSOCKET_DEPTH_5 = '5' + WEBSOCKET_DEPTH_10 = '10' + WEBSOCKET_DEPTH_20 = '20' + + def __init__(self, client: AsyncClient, loop=None, user_timeout=KEEPALIVE_TIMEOUT): + """Initialise the BinanceSocketManager + + :param client: Binance API client + :type client: binance.AsyncClient + + """ + self.STREAM_URL = self.STREAM_URL.format(client.tld) + self.FSTREAM_URL = self.FSTREAM_URL.format(client.tld) + self.DSTREAM_URL = self.DSTREAM_URL.format(client.tld) + self.VSTREAM_URL = self.VSTREAM_URL.format(client.tld) + self.VSTREAM_TESTNET_URL = self.VSTREAM_TESTNET_URL.format(client.tld) + + self._conns = {} + self._loop = loop or asyncio.get_event_loop() + self._client = client + self._user_timeout = user_timeout + + self.testnet = self._client.testnet + + def _get_stream_url(self, stream_url: Optional[str] = None): + if stream_url: + return stream_url + stream_url = self.STREAM_URL + if self.testnet: + stream_url = self.STREAM_TESTNET_URL + return stream_url + + def _get_socket( + self, path: str, stream_url: Optional[str] = None, prefix: str = 'ws/', is_binary: bool = False, + socket_type: BinanceSocketType = BinanceSocketType.SPOT + ) -> str: + conn_id = f'{socket_type}_{path}' + if conn_id not in self._conns: + self._conns[conn_id] = ReconnectingWebsocket( + loop=self._loop, + path=path, + url=self._get_stream_url(stream_url), + prefix=prefix, + exit_coro=self._exit_socket, + is_binary=is_binary + ) + + return self._conns[conn_id] + + def _get_account_socket( + self, path: str, stream_url: Optional[str] = None, prefix: str = 'ws/', is_binary: bool = False + ): + conn_id = f'{BinanceSocketType.ACCOUNT}_{path}' + if conn_id not in self._conns: + self._conns[conn_id] = KeepAliveWebsocket( + client=self._client, + loop=self._loop, + url=self._get_stream_url(stream_url), + keepalive_type=path, + prefix=prefix, + exit_coro=self._exit_socket, + is_binary=is_binary, + user_timeout=self._user_timeout + ) + + return self._conns[conn_id] + + def _get_futures_socket(self, path: str, futures_type: FuturesType, prefix: str = 'stream?streams='): + socket_type: BinanceSocketType = BinanceSocketType.USD_M_FUTURES + if futures_type == FuturesType.USD_M: + stream_url = self.FSTREAM_URL + if self.testnet: + stream_url = self.FSTREAM_TESTNET_URL + else: + stream_url = self.DSTREAM_URL + if self.testnet: + stream_url = self.DSTREAM_TESTNET_URL + return self._get_socket(path, stream_url, prefix, socket_type=socket_type) + + def _get_options_socket(self, path: str, prefix: str = 'ws/'): + stream_url = self.VSTREAM_URL + if self.testnet: + stream_url = self.VSTREAM_TESTNET_URL + return self._get_socket(path, stream_url, prefix, is_binary=True, socket_type=BinanceSocketType.OPTIONS) + + async def _exit_socket(self, path: str): + await self._stop_socket(path) + + def depth_socket(self, symbol: str, depth: Optional[str] = None, interval: Optional[int] = None): + """Start a websocket for symbol market depth returning either a diff or a partial book + + https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md#partial-book-depth-streams + + :param symbol: required + :type symbol: str + :param depth: optional Number of depth entries to return, default None. If passed returns a partial book instead of a diff + :type depth: str + :param interval: optional interval for updates, default None. If not set, updates happen every second. Must be 0, None (1s) or 100 (100ms) + :type interval: int + + :returns: connection key string if successful, False otherwise + + Partial Message Format + + .. code-block:: python + + { + "lastUpdateId": 160, # Last update ID + "bids": [ # Bids to be updated + [ + "0.0024", # price level to be updated + "10", # quantity + [] # ignore + ] + ], + "asks": [ # Asks to be updated + [ + "0.0026", # price level to be updated + "100", # quantity + [] # ignore + ] + ] + } + + + Diff Message Format + + .. code-block:: python + + { + "e": "depthUpdate", # Event type + "E": 123456789, # Event time + "s": "BNBBTC", # Symbol + "U": 157, # First update ID in event + "u": 160, # Final update ID in event + "b": [ # Bids to be updated + [ + "0.0024", # price level to be updated + "10", # quantity + [] # ignore + ] + ], + "a": [ # Asks to be updated + [ + "0.0026", # price level to be updated + "100", # quantity + [] # ignore + ] + ] + } + + """ + socket_name = symbol.lower() + '@depth' + if depth and depth != '1': + socket_name = f'{socket_name}{depth}' + if interval: + if interval in [0, 100]: + socket_name = f'{socket_name}@{interval}ms' + else: + raise ValueError("Websocket interval value not allowed. Allowed values are [0, 100]") + return self._get_socket(socket_name) + + def kline_socket(self, symbol: str, interval=AsyncClient.KLINE_INTERVAL_1MINUTE): + """Start a websocket for symbol kline data + + https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md#klinecandlestick-streams + + :param symbol: required + :type symbol: str + :param interval: Kline interval, default KLINE_INTERVAL_1MINUTE + :type interval: str + + :returns: connection key string if successful, False otherwise + + Message Format + + .. code-block:: python + + { + "e": "kline", # event type + "E": 1499404907056, # event time + "s": "ETHBTC", # symbol + "k": { + "t": 1499404860000, # start time of this bar + "T": 1499404919999, # end time of this bar + "s": "ETHBTC", # symbol + "i": "1m", # interval + "f": 77462, # first trade id + "L": 77465, # last trade id + "o": "0.10278577", # open + "c": "0.10278645", # close + "h": "0.10278712", # high + "l": "0.10278518", # low + "v": "17.47929838", # volume + "n": 4, # number of trades + "x": false, # whether this bar is final + "q": "1.79662878", # quote volume + "V": "2.34879839", # volume of active buy + "Q": "0.24142166", # quote volume of active buy + "B": "13279784.01349473" # can be ignored + } + } + """ + path = f'{symbol.lower()}@kline_{interval}' + return self._get_socket(path) + + def kline_futures_socket(self, symbol: str, interval=AsyncClient.KLINE_INTERVAL_1MINUTE, + futures_type: FuturesType = FuturesType.USD_M, + contract_type: ContractType = ContractType.PERPETUAL): + """Start a websocket for symbol kline data for the perpeual futures stream + + https://binance-docs.github.io/apidocs/futures/en/#continuous-contract-kline-candlestick-streams + + :param symbol: required + :type symbol: str + :param interval: Kline interval, default KLINE_INTERVAL_1MINUTE + :type interval: str + :param futures_type: use USD-M or COIN-M futures default USD-M + :param contract_type: use PERPETUAL or CURRENT_QUARTER or NEXT_QUARTER default PERPETUAL + + :returns: connection key string if successful, False otherwise + + Message Format + + .. code-block:: python + + { + "e":"continuous_kline", // Event type + "E":1607443058651, // Event time + "ps":"BTCUSDT", // Pair + "ct":"PERPETUAL" // Contract type + "k":{ + "t":1607443020000, // Kline start time + "T":1607443079999, // Kline close time + "i":"1m", // Interval + "f":116467658886, // First trade ID + "L":116468012423, // Last trade ID + "o":"18787.00", // Open price + "c":"18804.04", // Close price + "h":"18804.04", // High price + "l":"18786.54", // Low price + "v":"197.664", // volume + "n": 543, // Number of trades + "x":false, // Is this kline closed? + "q":"3715253.19494", // Quote asset volume + "V":"184.769", // Taker buy volume + "Q":"3472925.84746", //Taker buy quote asset volume + "B":"0" // Ignore + } + } + _@continuousKline_ + """ + + path = f'{symbol.lower()}_{contract_type.value}@continuousKline_{interval}' + return self._get_futures_socket(path, prefix='ws/', futures_type=futures_type) + + def miniticker_socket(self, update_time: int = 1000): + """Start a miniticker websocket for all trades + + This is not in the official Binance api docs, but this is what + feeds the right column on a ticker page on Binance. + + :param update_time: time between callbacks in milliseconds, must be 1000 or greater + :type update_time: int + + :returns: connection key string if successful, False otherwise + + Message Format + + .. code-block:: python + + [ + { + 'e': '24hrMiniTicker', # Event type + 'E': 1515906156273, # Event time + 's': 'QTUMETH', # Symbol + 'c': '0.03836900', # close + 'o': '0.03953500', # open + 'h': '0.04400000', # high + 'l': '0.03756000', # low + 'v': '147435.80000000', # volume + 'q': '5903.84338533' # quote volume + } + ] + """ + + return self._get_socket(f'!miniTicker@arr@{update_time}ms') + + def trade_socket(self, symbol: str): + """Start a websocket for symbol trade data + + https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md#trade-streams + + :param symbol: required + :type symbol: str + + :returns: connection key string if successful, False otherwise + + Message Format + + .. code-block:: python + + { + "e": "trade", # Event type + "E": 123456789, # Event time + "s": "BNBBTC", # Symbol + "t": 12345, # Trade ID + "p": "0.001", # Price + "q": "100", # Quantity + "b": 88, # Buyer order Id + "a": 50, # Seller order Id + "T": 123456785, # Trade time + "m": true, # Is the buyer the market maker? + "M": true # Ignore. + } + + """ + + return self._get_socket(symbol.lower() + '@trade') + + def aggtrade_socket(self, symbol: str): + """Start a websocket for symbol trade data + + https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md#aggregate-trade-streams + + :param symbol: required + :type symbol: str + + :returns: connection key string if successful, False otherwise + + Message Format + + .. code-block:: python + + { + "e": "aggTrade", # event type + "E": 1499405254326, # event time + "s": "ETHBTC", # symbol + "a": 70232, # aggregated tradeid + "p": "0.10281118", # price + "q": "8.15632997", # quantity + "f": 77489, # first breakdown trade id + "l": 77489, # last breakdown trade id + "T": 1499405254324, # trade time + "m": false, # whether buyer is a maker + "M": true # can be ignored + } + + """ + return self._get_socket(symbol.lower() + '@aggTrade') + + def aggtrade_futures_socket(self, symbol: str, futures_type: FuturesType = FuturesType.USD_M): + """Start a websocket for aggregate symbol trade data for the futures stream + + :param symbol: required + :param futures_type: use USD-M or COIN-M futures default USD-M + + :returns: connection key string if successful, False otherwise + + Message Format + + .. code-block:: python + + { + "e": "aggTrade", // Event type + "E": 123456789, // Event time + "s": "BTCUSDT", // Symbol + "a": 5933014, // Aggregate trade ID + "p": "0.001", // Price + "q": "100", // Quantity + "f": 100, // First trade ID + "l": 105, // Last trade ID + "T": 123456785, // Trade time + "m": true, // Is the buyer the market maker? + } + + """ + return self._get_futures_socket(symbol.lower() + '@aggTrade', futures_type=futures_type) + + def symbol_miniticker_socket(self, symbol: str): + """Start a websocket for a symbol's miniTicker data + + https://binance-docs.github.io/apidocs/spot/en/#individual-symbol-mini-ticker-stream + + :param symbol: required + :type symbol: str + + :returns: connection key string if successful, False otherwise + + Message Format + + .. code-block:: python + + { + "e": "24hrMiniTicker", // Event type + "E": 123456789, // Event time + "s": "BNBBTC", // Symbol + "c": "0.0025", // Close price + "o": "0.0010", // Open price + "h": "0.0025", // High price + "l": "0.0010", // Low price + "v": "10000", // Total traded base asset volume + "q": "18" // Total traded quote asset volume + } + + """ + return self._get_socket(symbol.lower() + '@miniTicker') + + def symbol_ticker_socket(self, symbol: str): + """Start a websocket for a symbol's ticker data + + https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md#individual-symbol-ticker-streams + + :param symbol: required + :type symbol: str + + :returns: connection key string if successful, False otherwise + + Message Format + + .. code-block:: python + + { + "e": "24hrTicker", # Event type + "E": 123456789, # Event time + "s": "BNBBTC", # Symbol + "p": "0.0015", # Price change + "P": "250.00", # Price change percent + "w": "0.0018", # Weighted average price + "x": "0.0009", # Previous day's close price + "c": "0.0025", # Current day's close price + "Q": "10", # Close trade's quantity + "b": "0.0024", # Best bid price + "B": "10", # Bid bid quantity + "a": "0.0026", # Best ask price + "A": "100", # Best ask quantity + "o": "0.0010", # Open price + "h": "0.0025", # High price + "l": "0.0010", # Low price + "v": "10000", # Total traded base asset volume + "q": "18", # Total traded quote asset volume + "O": 0, # Statistics open time + "C": 86400000, # Statistics close time + "F": 0, # First trade ID + "L": 18150, # Last trade Id + "n": 18151 # Total number of trades + } + + """ + return self._get_socket(symbol.lower() + '@ticker') + + def ticker_socket(self): + """Start a websocket for all ticker data + + By default all markets are included in an array. + + https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md#all-market-tickers-stream + + :param coro: callback function to handle messages + :type coro: function + + :returns: connection key string if successful, False otherwise + + Message Format + + .. code-block:: python + + [ + { + 'F': 278610, + 'o': '0.07393000', + 's': 'BCCBTC', + 'C': 1509622420916, + 'b': '0.07800800', + 'l': '0.07160300', + 'h': '0.08199900', + 'L': 287722, + 'P': '6.694', + 'Q': '0.10000000', + 'q': '1202.67106335', + 'p': '0.00494900', + 'O': 1509536020916, + 'a': '0.07887800', + 'n': 9113, + 'B': '1.00000000', + 'c': '0.07887900', + 'x': '0.07399600', + 'w': '0.07639068', + 'A': '2.41900000', + 'v': '15743.68900000' + } + ] + """ + return self._get_socket('!ticker@arr') + + def index_price_socket(self, symbol: str, fast: bool = True): + """Start a websocket for a symbol's futures mark price + https://binance-docs.github.io/apidocs/delivery/en/#index-price-stream + :param symbol: required + :param fast: use faster or 1s default + :returns: connection key string if successful, False otherwise + + Message Format + .. code-block:: python + { + "e": "indexPriceUpdate", // Event type + "E": 1591261236000, // Event time + "i": "BTCUSD", // Pair + "p": "9636.57860000", // Index Price + } + """ + stream_name = '@indexPrice@1s' if fast else '@indexPrice' + return self._get_futures_socket(symbol.lower() + stream_name, futures_type=FuturesType.COIN_M) + + def symbol_mark_price_socket(self, symbol: str, fast: bool = True, futures_type: FuturesType = FuturesType.USD_M): + """Start a websocket for a symbol's futures mark price + https://binance-docs.github.io/apidocs/futures/en/#mark-price-stream + :param symbol: required + :param fast: use faster or 1s default + :param futures_type: use USD-M or COIN-M futures default USD-M + :returns: connection key string if successful, False otherwise + Message Format + .. code-block:: python + { + "e": "markPriceUpdate", // Event type + "E": 1562305380000, // Event time + "s": "BTCUSDT", // Symbol + "p": "11185.87786614", // Mark price + "r": "0.00030000", // Funding rate + "T": 1562306400000 // Next funding time + } + """ + stream_name = '@markPrice@1s' if fast else '@markPrice' + return self._get_futures_socket(symbol.lower() + stream_name, futures_type=futures_type) + + def all_mark_price_socket(self, fast: bool = True, futures_type: FuturesType = FuturesType.USD_M): + """Start a websocket for all futures mark price data + By default all symbols are included in an array. + https://binance-docs.github.io/apidocs/futures/en/#mark-price-stream-for-all-market + :param fast: use faster or 1s default + :param futures_type: use USD-M or COIN-M futures default USD-M + :returns: connection key string if successful, False otherwise + Message Format + .. code-block:: python + + [ + { + "e": "markPriceUpdate", // Event type + "E": 1562305380000, // Event time + "s": "BTCUSDT", // Symbol + "p": "11185.87786614", // Mark price + "r": "0.00030000", // Funding rate + "T": 1562306400000 // Next funding time + } + ] + """ + stream_name = '!markPrice@arr@1s' if fast else '!markPrice@arr' + return self._get_futures_socket(stream_name, futures_type=futures_type) + + def symbol_ticker_futures_socket(self, symbol: str, futures_type: FuturesType = FuturesType.USD_M): + """Start a websocket for a symbol's ticker data + By default all markets are included in an array. + https://binance-docs.github.io/apidocs/futures/en/#individual-symbol-book-ticker-streams + :param symbol: required + :param futures_type: use USD-M or COIN-M futures default USD-M + :returns: connection key string if successful, False otherwise + .. code-block:: python + [ + { + "u":400900217, // order book updateId + "s":"BNBUSDT", // symbol + "b":"25.35190000", // best bid price + "B":"31.21000000", // best bid qty + "a":"25.36520000", // best ask price + "A":"40.66000000" // best ask qty + } + ] + """ + return self._get_futures_socket(symbol.lower() + '@bookTicker', futures_type=futures_type) + + def individual_symbol_ticker_futures_socket(self, symbol: str, futures_type: FuturesType = FuturesType.USD_M): + """Start a futures websocket for a single symbol's ticker data + https://binance-docs.github.io/apidocs/futures/en/#individual-symbol-ticker-streams + :param symbol: required + :type symbol: str + :param futures_type: use USD-M or COIN-M futures default USD-M + :returns: connection key string if successful, False otherwise + .. code-block:: python + { + "e": "24hrTicker", // Event type + "E": 123456789, // Event time + "s": "BTCUSDT", // Symbol + "p": "0.0015", // Price change + } + """ + return self._get_futures_socket(symbol.lower() + '@ticker', futures_type=futures_type) + + def all_ticker_futures_socket(self, futures_type: FuturesType = FuturesType.USD_M): + """Start a websocket for all ticker data + By default all markets are included in an array. + https://binance-docs.github.io/apidocs/futures/en/#all-book-tickers-stream + :param futures_type: use USD-M or COIN-M futures default USD-M + :returns: connection key string if successful, False otherwise + Message Format + .. code-block:: python + [ + { + "u":400900217, // order book updateId + "s":"BNBUSDT", // symbol + "b":"25.35190000", // best bid price + "B":"31.21000000", // best bid qty + "a":"25.36520000", // best ask price + "A":"40.66000000" // best ask qty + } + ] + """ + + return self._get_futures_socket('!bookTicker', futures_type=futures_type) + + def symbol_book_ticker_socket(self, symbol: str): + """Start a websocket for the best bid or ask's price or quantity for a specified symbol. + + https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md#individual-symbol-book-ticker-streams + + :param symbol: required + :type symbol: str + + :returns: connection key string if successful, False otherwise + + Message Format + + .. code-block:: python + + { + "u":400900217, // order book updateId + "s":"BNBUSDT", // symbol + "b":"25.35190000", // best bid price + "B":"31.21000000", // best bid qty + "a":"25.36520000", // best ask price + "A":"40.66000000" // best ask qty + } + + """ + return self._get_socket(symbol.lower() + '@bookTicker') + + def book_ticker_socket(self): + """Start a websocket for the best bid or ask's price or quantity for all symbols. + + https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md#all-book-tickers-stream + + :returns: connection key string if successful, False otherwise + + Message Format + + .. code-block:: python + + { + // Same as @bookTicker payload + } + + """ + return self._get_socket('!bookTicker') + + def multiplex_socket(self, streams: List[str]): + """Start a multiplexed socket using a list of socket names. + User stream sockets can not be included. + + Symbols in socket name must be lowercase i.e bnbbtc@aggTrade, neobtc@ticker + + Combined stream events are wrapped as follows: {"stream":"","data":} + + https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md + + :param streams: list of stream names in lower case + :type streams: list + + :returns: connection key string if successful, False otherwise + + Message Format - see Binance API docs for all types + + """ + path = f'streams={"/".join(streams)}' + return self._get_socket(path, prefix='stream?') + + def options_multiplex_socket(self, streams: List[str]): + """Start a multiplexed socket using a list of socket names. + User stream sockets can not be included. + + Symbols in socket name must be lowercase i.e bnbbtc@aggTrade, neobtc@ticker + + Combined stream events are wrapped as follows: {"stream":"","data":} + + https://binance-docs.github.io/apidocs/voptions/en/#account-and-trading-interface + + :param streams: list of stream names in lower case + :type streams: list + + :returns: connection key string if successful, False otherwise + + Message Format - see Binance API docs for all types + + """ + stream_name = '/'.join([s.lower() for s in streams]) + stream_path = f'streams={stream_name}' + return self._get_options_socket(stream_path, prefix='stream?') + + def futures_multiplex_socket(self, streams: List[str], futures_type: FuturesType = FuturesType.USD_M): + """Start a multiplexed socket using a list of socket names. + User stream sockets can not be included. + + Symbols in socket name must be lowercase i.e bnbbtc@aggTrade, neobtc@ticker + + Combined stream events are wrapped as follows: {"stream":"","data":} + + https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md + + :param streams: list of stream names in lower case + :param futures_type: use USD-M or COIN-M futures default USD-M + + :returns: connection key string if successful, False otherwise + + Message Format - see Binance API docs for all types + + """ + path = f'streams={"/".join(streams)}' + return self._get_futures_socket(path, prefix='stream?', futures_type=futures_type) + + def futures_depth_socket(self, symbol: str, depth: str = '10', futures_type: FuturesType = FuturesType.USD_M): + """Subscribe to a depth data stream + + https://binance-docs.github.io/apidocs/futures/en/#partial-book-depth-streams + + :param symbol: required + :type symbol: str + :param depth: optional Number of depth entries to return, default 10. + :type depth: str + """ + return self._get_futures_socket(symbol.lower() + '@depth' + str(depth), futures_type=futures_type) + + def user_socket(self): + """Start a websocket for user data + + https://github.com/binance-exchange/binance-official-api-docs/blob/master/user-data-stream.md + https://binance-docs.github.io/apidocs/spot/en/#listen-key-spot + + :returns: connection key string if successful, False otherwise + + Message Format - see Binance API docs for all types + """ + return self._get_account_socket('user') + + def futures_user_socket(self): + """Start a websocket for coin futures user data + + https://binance-docs.github.io/apidocs/futures/en/#user-data-streams + + :returns: connection key string if successful, False otherwise + + Message Format - see Binanace API docs for all types + """ + + return self._get_account_socket('futures', stream_url=self.FSTREAM_URL) + + def margin_socket(self): + """Start a websocket for cross-margin data + + https://binance-docs.github.io/apidocs/spot/en/#listen-key-margin + + :returns: connection key string if successful, False otherwise + + Message Format - see Binance API docs for all types + """ + return self._get_account_socket('margin') + + def futures_socket(self): + """Start a websocket for futures data + + https://binance-docs.github.io/apidocs/futures/en/#websocket-market-streams + + :returns: connection key string if successful, False otherwise + + Message Format - see Binance API docs for all types + """ + return self._get_account_socket('futures', stream_url=self.FSTREAM_URL) + + def coin_futures_socket(self): + """Start a websocket for coin futures data + + https://binance-docs.github.io/apidocs/delivery/en/#websocket-market-streams + + :returns: connection key string if successful, False otherwise + + Message Format - see Binance API docs for all types + """ + return self._get_account_socket('coin_futures', stream_url=self.DSTREAM_URL) + + def isolated_margin_socket(self, symbol: str): + """Start a websocket for isolated margin data + + https://binance-docs.github.io/apidocs/spot/en/#listen-key-isolated-margin + + :param symbol: required - symbol for the isolated margin account + :type symbol: str + + :returns: connection key string if successful, False otherwise + + Message Format - see Binance API docs for all types + """ + return self._get_account_socket(symbol) + + def options_ticker_socket(self, symbol: str): + """Subscribe to a 24 hour ticker info stream + + https://binance-docs.github.io/apidocs/voptions/en/#market-streams-payload-24-hour-ticker + + :param symbol: required + :type symbol: str + """ + return self._get_options_socket(symbol.lower() + '@ticker') + + def options_recent_trades_socket(self, symbol: str): + """Subscribe to a latest completed trades stream + + https://binance-docs.github.io/apidocs/voptions/en/#market-streams-payload-latest-completed-trades + + :param symbol: required + :type symbol: str + """ + return self._get_options_socket(symbol.lower() + '@trade') + + def options_kline_socket(self, symbol: str, interval=AsyncClient.KLINE_INTERVAL_1MINUTE): + """Subscribe to a candlestick data stream + + https://binance-docs.github.io/apidocs/voptions/en/#market-streams-payload-candle + + :param symbol: required + :type symbol: str + :param interval: Kline interval, default KLINE_INTERVAL_1MINUTE + :type interval: str + """ + return self._get_options_socket(symbol.lower() + '@kline_' + interval) + + def options_depth_socket(self, symbol: str, depth: str = '10'): + """Subscribe to a depth data stream + + https://binance-docs.github.io/apidocs/voptions/en/#market-streams-payload-depth + + :param symbol: required + :type symbol: str + :param depth: optional Number of depth entries to return, default 10. + :type depth: str + """ + return self._get_options_socket(symbol.lower() + '@depth' + str(depth)) + + async def _stop_socket(self, conn_key): + """Stop a websocket given the connection key + + :param conn_key: Socket connection key + :type conn_key: string + + :returns: None + """ + if conn_key not in self._conns: + return + + del (self._conns[conn_key]) + + +class ThreadedWebsocketManager(ThreadedApiManager): + + def __init__( + self, api_key: Optional[str] = None, api_secret: Optional[str] = None, + requests_params: Dict[str, str] = None, tld: str = 'com', + testnet: bool = False + ): + super().__init__(api_key, api_secret, requests_params, tld, testnet) + self._bsm: Optional[BinanceSocketManager] = None + + async def _before_socket_listener_start(self): + assert self._client + self._bsm = BinanceSocketManager(client=self._client, loop=self._loop) + + def _start_async_socket( + self, callback: Callable, socket_name: str, params: Dict[str, Any], path: Optional[str] = None + ) -> str: + while not self._bsm: + time.sleep(0.1) + socket = getattr(self._bsm, socket_name)(**params) + path = path or socket._path # noqa + self._socket_running[path] = True + self._loop.call_soon_threadsafe(asyncio.create_task, self.start_listener(socket, socket._path, callback)) + return path + + def start_depth_socket( + self, callback: Callable, symbol: str, depth: Optional[str] = None, interval: Optional[int] = None + ) -> str: + return self._start_async_socket( + callback=callback, + socket_name='depth_socket', + params={ + 'symbol': symbol, + 'depth': depth, + 'interval': interval, + } + ) + + def start_kline_socket(self, callback: Callable, symbol: str, interval=AsyncClient.KLINE_INTERVAL_1MINUTE) -> str: + return self._start_async_socket( + callback=callback, + socket_name='kline_socket', + params={ + 'symbol': symbol, + 'interval': interval, + } + ) + + def start_kline_futures_socket(self, callback: Callable, symbol: str, + interval=AsyncClient.KLINE_INTERVAL_1MINUTE, + futures_type: FuturesType = FuturesType.USD_M, + contract_type: ContractType = ContractType.PERPETUAL) -> str: + return self._start_async_socket( + callback=callback, + socket_name='kline_futures_socket', + params={ + 'symbol': symbol, + 'interval': interval, + 'futures_type': futures_type, + 'contract_type': contract_type + } + ) + + def start_miniticker_socket(self, callback: Callable, update_time: int = 1000) -> str: + return self._start_async_socket( + callback=callback, + socket_name='miniticker_socket', + params={ + 'update_time': update_time, + } + ) + + def start_trade_socket(self, callback: Callable, symbol: str) -> str: + return self._start_async_socket( + callback=callback, + socket_name='trade_socket', + params={ + 'symbol': symbol, + } + ) + + def start_aggtrade_socket(self, callback: Callable, symbol: str) -> str: + return self._start_async_socket( + callback=callback, + socket_name='aggtrade_socket', + params={ + 'symbol': symbol, + } + ) + + def start_aggtrade_futures_socket( + self, callback: Callable, symbol: str, futures_type: FuturesType = FuturesType.USD_M + ) -> str: + return self._start_async_socket( + callback=callback, + socket_name='aggtrade_futures_socket', + params={ + 'symbol': symbol, + 'futures_type': futures_type, + } + ) + + def start_symbol_miniticker_socket(self, callback: Callable, symbol: str) -> str: + return self._start_async_socket( + callback=callback, + socket_name='symbol_miniticker_socket', + params={ + 'symbol': symbol, + } + ) + + def start_symbol_ticker_socket(self, callback: Callable, symbol: str) -> str: + return self._start_async_socket( + callback=callback, + socket_name='symbol_ticker_socket', + params={ + 'symbol': symbol, + } + ) + + def start_ticker_socket(self, callback: Callable) -> str: + return self._start_async_socket( + callback=callback, + socket_name='ticker_socket', + params={} + ) + + def start_index_price_socket(self, callback: Callable, symbol: str, fast: bool = True) -> str: + return self._start_async_socket( + callback=callback, + socket_name='index_price_socket', + params={ + 'symbol': symbol, + 'fast': fast + } + ) + + def start_symbol_mark_price_socket( + self, callback: Callable, symbol: str, fast: bool = True, futures_type: FuturesType = FuturesType.USD_M + ) -> str: + return self._start_async_socket( + callback=callback, + socket_name='symbol_mark_price_socket', + params={ + 'symbol': symbol, + 'fast': fast, + 'futures_type': futures_type + } + ) + + def start_all_mark_price_socket( + self, callback: Callable, fast: bool = True, futures_type: FuturesType = FuturesType.USD_M + ) -> str: + return self._start_async_socket( + callback=callback, + socket_name='all_mark_price_socket', + params={ + 'fast': fast, + 'futures_type': futures_type + } + ) + + def start_symbol_ticker_futures_socket( + self, callback: Callable, symbol: str, futures_type: FuturesType = FuturesType.USD_M + ) -> str: + return self._start_async_socket( + callback=callback, + socket_name='symbol_ticker_futures_socket', + params={ + 'symbol': symbol, + 'futures_type': futures_type + } + ) + + def start_individual_symbol_ticker_futures_socket( + self, callback: Callable, symbol: str, futures_type: FuturesType = FuturesType.USD_M + ) -> str: + return self._start_async_socket( + callback=callback, + socket_name='individual_symbol_ticker_futures_socket', + params={ + 'symbol': symbol, + 'futures_type': futures_type + } + ) + + def start_all_ticker_futures_socket(self, callback: Callable, futures_type: FuturesType = FuturesType.USD_M) -> str: + return self._start_async_socket( + callback=callback, + socket_name='all_ticker_futures_socket', + params={ + 'futures_type': futures_type + } + ) + + def start_symbol_book_ticker_socket(self, callback: Callable, symbol: str) -> str: + return self._start_async_socket( + callback=callback, + socket_name='symbol_book_ticker_socket', + params={ + 'symbol': symbol + } + ) + + def start_book_ticker_socket(self, callback: Callable) -> str: + return self._start_async_socket( + callback=callback, + socket_name='book_ticker_socket', + params={} + ) + + def start_multiplex_socket(self, callback: Callable, streams: List[str]) -> str: + return self._start_async_socket( + callback=callback, + socket_name='multiplex_socket', + params={ + 'streams': streams + } + ) + + def start_options_multiplex_socket(self, callback: Callable, streams: List[str]) -> str: + return self._start_async_socket( + callback=callback, + socket_name='options_multiplex_socket', + params={ + 'streams': streams + } + ) + + def start_futures_multiplex_socket( + self, callback: Callable, streams: List[str], futures_type: FuturesType = FuturesType.USD_M + ) -> str: + return self._start_async_socket( + callback=callback, + socket_name='futures_multiplex_socket', + params={ + 'streams': streams, + 'futures_type': futures_type + } + ) + + def start_user_socket(self, callback: Callable) -> str: + return self._start_async_socket( + callback=callback, + socket_name='user_socket', + params={} + ) + + def start_margin_socket(self, callback: Callable) -> str: + return self._start_async_socket( + callback=callback, + socket_name='margin_socket', + params={} + ) + + def start_futures_socket(self, callback: Callable) -> str: + return self._start_async_socket( + callback=callback, + socket_name='futures_socket', + params={} + ) + + def start_coin_futures_socket(self, callback: Callable) -> str: + return self._start_async_socket( + callback=callback, + socket_name='coin_futures_socket', + params={} + ) + + def start_isolated_margin_socket(self, callback: Callable, symbol: str) -> str: + return self._start_async_socket( + callback=callback, + socket_name='isolated_margin_socket', + params={ + 'symbol': symbol + } + ) + + def start_options_ticker_socket(self, callback: Callable, symbol: str) -> str: + return self._start_async_socket( + callback=callback, + socket_name='options_ticker_socket', + params={ + 'symbol': symbol + } + ) + + def start_options_recent_trades_socket(self, callback: Callable, symbol: str) -> str: + return self._start_async_socket( + callback=callback, + socket_name='options_recent_trades_socket', + params={ + 'symbol': symbol + } + ) + + def start_options_kline_socket( + self, callback: Callable, symbol: str, interval=AsyncClient.KLINE_INTERVAL_1MINUTE + ) -> str: + return self._start_async_socket( + callback=callback, + socket_name='options_kline_socket', + params={ + 'symbol': symbol, + 'interval': interval + } + ) + + def start_options_depth_socket(self, callback: Callable, symbol: str, depth: str = '10') -> str: + return self._start_async_socket( + callback=callback, + socket_name='options_depth_socket', + params={ + 'symbol': symbol, + 'depth': depth + } + )