# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- __version__ = '4.5.18' # ----------------------------------------------------------------------------- import asyncio import concurrent.futures import socket import certifi import aiohttp import ssl import sys import yarl import math from typing import Any, List from ccxt.base.types import Int, Str, Num, Strings # ----------------------------------------------------------------------------- from ccxt.async_support.base.throttler import Throttler # ----------------------------------------------------------------------------- from ccxt.base.errors import BaseError, BadSymbol, BadRequest, BadResponse, ExchangeError, ExchangeNotAvailable, RequestTimeout, NotSupported, NullResponse, InvalidAddress, RateLimitExceeded, OperationFailed from ccxt.base.types import ConstructorArgs, OrderType, OrderSide, OrderRequest, CancellationRequest, Order # ----------------------------------------------------------------------------- from ccxt.base.exchange import Exchange as BaseExchange, ArgumentsRequired # ----------------------------------------------------------------------------- from ccxt.async_support.base.ws.functions import inflate, inflate64, gunzip from ccxt.async_support.base.ws.client import Client from ccxt.async_support.base.ws.future import Future from ccxt.async_support.base.ws.order_book import OrderBook, IndexedOrderBook, CountedOrderBook # ----------------------------------------------------------------------------- try: from aiohttp_socks import ProxyConnector as SocksProxyConnector except ImportError: SocksProxyConnector = None # ----------------------------------------------------------------------------- __all__ = [ 'BaseExchange', 'Exchange', ] # ----------------------------------------------------------------------------- # --- PROTO BUF IMPORTS try: from ccxt.protobuf.mexc import PushDataV3ApiWrapper_pb2 from google.protobuf.json_format import MessageToDict except ImportError: PushDataV3ApiWrapper_pb2 = None MessageToDict = None # ----------------------------------------------------------------------------- class Exchange(BaseExchange): synchronous = False streaming = { 'maxPingPongMisses': 2, 'keepAlive': 30000 } ping = None newUpdates = True clients = {} timeout_on_exit = 250 # needed for: https://github.com/ccxt/ccxt/pull/23470 def __init__(self, config: ConstructorArgs = {}): if 'asyncio_loop' in config: self.asyncio_loop = config['asyncio_loop'] self.aiohttp_trust_env = config.get('aiohttp_trust_env', self.aiohttp_trust_env) self.verify = config.get('verify', self.verify) self.own_session = 'session' not in config self.cafile = config.get('cafile', certifi.where()) self.throttler = None super(Exchange, self).__init__(config) self.markets_loading = None self.reloading_markets = False def get_event_loop(self): return self.asyncio_loop def init_throttler(self, cost=None): self.throttler = Throttler(self.tokenBucket, self.asyncio_loop) async def throttle(self, cost=None): return await self.throttler(cost) def get_session(self): return self.session def __del__(self): if self.session is not None or self.socks_proxy_sessions is not None: self.logger.warning(self.id + " requires to release all resources with an explicit call to the .close() coroutine. If you are using the exchange instance with async coroutines, add `await exchange.close()` to your code into a place when you're done with the exchange and don't need the exchange instance anymore (at the end of your async coroutine).") if sys.version_info >= (3, 5): async def __aenter__(self): self.open() return self async def __aexit__(self, exc_type, exc, tb): await self.close() def open(self): if self.asyncio_loop is None: if sys.version_info >= (3, 7): self.asyncio_loop = asyncio.get_running_loop() else: self.asyncio_loop = asyncio.get_event_loop() self.throttler.loop = self.asyncio_loop if self.ssl_context is None: # Create our SSL context object with our CA cert file self.ssl_context = ssl.create_default_context(cafile=self.cafile) if self.verify else self.verify if (self.ssl_context and self.safe_bool(self.options, 'include_OS_certificates', False)): os_default_paths = ssl.get_default_verify_paths() if os_default_paths.cafile and os_default_paths.cafile != self.cafile: self.ssl_context.load_verify_locations(cafile=os_default_paths.cafile) if self.own_session and self.session is None: # Pass this SSL context to aiohttp and create a TCPConnector self.tcp_connector = aiohttp.TCPConnector(ssl=self.ssl_context, loop=self.asyncio_loop, enable_cleanup_closed=True) self.session = aiohttp.ClientSession(loop=self.asyncio_loop, connector=self.tcp_connector, trust_env=self.aiohttp_trust_env) async def close(self): await self.ws_close() if self.session is not None: if self.own_session: await self.session.close() self.session = None await self.close_connector() await self.close_proxy_sessions() await self.sleep(self.timeout_on_exit) async def close_connector(self): if self.tcp_connector is not None: await self.tcp_connector.close() self.tcp_connector = None if self.aiohttp_socks_connector is not None: await self.aiohttp_socks_connector.close() self.aiohttp_socks_connector = None async def close_proxy_sessions(self): if self.socks_proxy_sessions is not None: for url in self.socks_proxy_sessions: await self.socks_proxy_sessions[url].close() self.socks_proxy_sessions = None async def fetch(self, url, method='GET', headers=None, body=None): """Perform a HTTP request and return decoded JSON data""" # ##### PROXY & HEADERS ##### request_headers = self.prepare_request_headers(headers) self.last_request_headers = request_headers # proxy-url proxyUrl = self.check_proxy_url_settings(url, method, headers, body) if proxyUrl is not None: request_headers.update({'Origin': self.origin}) url = proxyUrl + self.url_encoder_for_proxy_url(url) # proxy agents final_proxy = None # set default proxy_session = None httpProxy, httpsProxy, socksProxy = self.check_proxy_settings(url, method, headers, body) if httpProxy: final_proxy = httpProxy elif httpsProxy: final_proxy = httpsProxy elif socksProxy: if SocksProxyConnector is None: raise NotSupported(self.id + ' - to use SOCKS proxy with ccxt, you need "aiohttp_socks" module that can be installed by "pip install aiohttp_socks"') # override session if (self.socks_proxy_sessions is None): self.socks_proxy_sessions = {} if (socksProxy not in self.socks_proxy_sessions): # Create our SSL context object with our CA cert file self.open() # ensure `asyncio_loop` is set proxy_session = self.get_socks_proxy_session(socksProxy) # add aiohttp_proxy for python as exclusion elif self.aiohttp_proxy: final_proxy = self.aiohttp_proxy proxyAgentSet = final_proxy is not None or socksProxy is not None self.checkConflictingProxies(proxyAgentSet, proxyUrl) # avoid old proxies mixing if (self.aiohttp_proxy is not None) and (proxyUrl is not None or httpProxy is not None or httpsProxy is not None or socksProxy is not None): raise NotSupported(self.id + ' you have set multiple proxies, please use one or another') # log if self.verbose: self.log("\nfetch Request:", self.id, method, url, "RequestHeaders:", request_headers, "RequestBody:", body) self.logger.debug("%s %s, Request: %s %s", method, url, headers, body) # end of proxies & headers request_body = body encoded_body = body.encode() if body else None self.open() final_session = proxy_session if proxy_session is not None else self.session session_method = getattr(final_session, method.lower()) http_response = None http_status_code = None http_status_text = None json_response = None try: async with session_method(yarl.URL(url, encoded=True), data=encoded_body, headers=request_headers, timeout=(self.timeout / 1000), proxy=final_proxy) as response: http_response = await response.text(errors='replace') # CIMultiDictProxy raw_headers = response.headers headers = {} for header in raw_headers: if header in headers: headers[header] = headers[header] + ', ' + raw_headers[header] else: headers[header] = raw_headers[header] http_status_code = response.status http_status_text = response.reason http_response = self.on_rest_response(http_status_code, http_status_text, url, method, headers, http_response, request_headers, request_body) json_response = self.parse_json(http_response) if self.enableLastHttpResponse: self.last_http_response = http_response if self.enableLastResponseHeaders: self.last_response_headers = headers if self.enableLastJsonResponse: self.last_json_response = json_response if self.verbose: self.log("\nfetch Response:", self.id, method, url, http_status_code, "ResponseHeaders:", headers, "ResponseBody:", http_response) if json_response and not isinstance(json_response, list) and self.returnResponseHeaders: json_response['responseHeaders'] = headers self.logger.debug("%s %s, Response: %s %s %s", method, url, http_status_code, headers, http_response) except socket.gaierror as e: details = ' '.join([self.id, method, url]) raise ExchangeNotAvailable(details) from e except (concurrent.futures.TimeoutError, asyncio.TimeoutError) as e: details = ' '.join([self.id, method, url]) raise RequestTimeout(details) from e except aiohttp.ClientConnectionError as e: details = ' '.join([self.id, method, url]) raise ExchangeNotAvailable(details) from e except aiohttp.ClientError as e: # base exception class details = ' '.join([self.id, method, url]) raise ExchangeError(details) from e self.handle_errors(http_status_code, http_status_text, url, method, headers, http_response, json_response, request_headers, request_body) self.handle_http_status_code(http_status_code, http_status_text, url, method, http_response) if json_response is not None: return json_response if self.is_text_response(headers): return http_response if http_response == '' or http_response is None: return http_response return response.content def get_socks_proxy_session(self, socksProxy): if (self.socks_proxy_sessions is None): self.socks_proxy_sessions = {} if (socksProxy not in self.socks_proxy_sessions): reverse_dns = socksProxy.startswith('socks5h://') socks_proxy_selected = socksProxy if not reverse_dns else socksProxy.replace('socks5h://', 'socks5://') self.aiohttp_socks_connector = SocksProxyConnector.from_url( socks_proxy_selected, # extra args copied from self.open() ssl=self.ssl_context, loop=self.asyncio_loop, enable_cleanup_closed=True, rdns=reverse_dns if reverse_dns else None ) self.socks_proxy_sessions[socksProxy] = aiohttp.ClientSession(loop=self.asyncio_loop, connector=self.aiohttp_socks_connector, trust_env=self.aiohttp_trust_env) return self.socks_proxy_sessions[socksProxy] async def load_markets_helper(self, reload=False, params={}): if not reload: if self.markets: if not self.markets_by_id: return self.set_markets(self.markets) return self.markets currencies = None if self.has['fetchCurrencies'] is True: currencies = await self.fetch_currencies() self.options['cachedCurrencies'] = currencies markets = await self.fetch_markets(params) if 'cachedCurrencies' in self.options: del self.options['cachedCurrencies'] return self.set_markets(markets, currencies) async def load_markets(self, reload=False, params={}): """ Loads and prepares the markets for trading. Args: reload (bool): If True, the markets will be reloaded from the exchange. params (dict): Additional exchange-specific parameters for the request. Returns: dict: A dictionary of markets. Raises: Exception: If the markets cannot be loaded or prepared. Notes: This method is asynchronous. It ensures that the markets are only loaded once, even if called multiple times. If the markets are already loaded and `reload` is False or not provided, it returns the existing markets. If a reload is in progress, it waits for completion before returning. If an error occurs during loading or preparation, an exception is raised. """ if (reload and not self.reloading_markets) or not self.markets_loading: self.reloading_markets = True coroutine = self.load_markets_helper(reload, params) # coroutines can only be awaited once so we wrap it in a task self.markets_loading = asyncio.ensure_future(coroutine) try: result = await self.markets_loading except asyncio.CancelledError as e: # CancelledError is a base exception so we need to catch it explicitly self.reloading_markets = False self.markets_loading = None raise e except Exception as e: self.reloading_markets = False self.markets_loading = None raise e self.reloading_markets = False return result async def load_fees(self, reload=False): if not reload: if self.loaded_fees != Exchange.loaded_fees: return self.loaded_fees self.loaded_fees = self.deep_extend(self.loaded_fees, await self.fetch_fees()) return self.loaded_fees async def fetch_markets(self, params={}): # markets are returned as a list # currencies are returned as a dict # this is for historical reasons # and may be changed for consistency later return self.to_array(self.markets) async def fetch_currencies(self, params={}): # markets are returned as a list # currencies are returned as a dict # this is for historical reasons # and may be changed for consistency later return self.currencies async def fetchOHLCVC(self, symbol, timeframe='1m', since=None, limit=None, params={}): return await self.fetch_ohlcvc(symbol, timeframe, since, limit, params) async def fetch_full_tickers(self, symbols=None, params={}): return await self.fetch_tickers(symbols, params) async def sleep(self, milliseconds): return await asyncio.sleep(milliseconds / 1000) async def spawn_async(self, method, *args): try: await method(*args) except Exception: # todo: handle spawned errors pass def spawn(self, method, *args): def callback(asyncio_future): exception = asyncio_future.exception() if exception is None: future.resolve(asyncio_future.result()) else: future.reject(exception) future = Future() task = self.asyncio_loop.create_task(method(*args)) task.add_done_callback(callback) return future # ----------------------------------------------------------------------- # WS/PRO code @staticmethod def inflate(data): return inflate(data) @staticmethod def inflate64(data): return inflate64(data) @staticmethod def gunzip(data): return gunzip(data) def order_book(self, snapshot={}, depth=None): return OrderBook(snapshot, depth) def indexed_order_book(self, snapshot={}, depth=None): return IndexedOrderBook(snapshot, depth) def counted_order_book(self, snapshot={}, depth=None): return CountedOrderBook(snapshot, depth) def client(self, url): self.clients = self.clients or {} if url not in self.clients: on_message = self.handle_message on_error = self.on_error on_close = self.on_close on_connected = self.on_connected # decide client type here: aiohttp ws / websockets / signalr / socketio ws_options = self.safe_value(self.options, 'ws', {}) options = self.extend(self.streaming, { 'log': getattr(self, 'log'), 'ping': getattr(self, 'ping', None), 'verbose': self.verbose, 'throttle': Throttler(self.tokenBucket, self.asyncio_loop), 'asyncio_loop': self.asyncio_loop, 'decompressBinary': self.safe_bool(self.options, 'decompressBinary', True), }, ws_options) # we use aiohttp instead of fastClient now because of this # https://github.com/ccxt/ccxt/pull/25995 self.clients[url] = Client(url, on_message, on_error, on_close, on_connected, options) # set http/s proxy (socks proxy should be set in other place) httpProxy, httpsProxy, socksProxy = self.check_ws_proxy_settings() if (httpProxy or httpsProxy): self.clients[url].proxy = httpProxy if httpProxy else httpsProxy return self.clients[url] def delay(self, timeout, method, *args): return self.asyncio_loop.call_later(timeout / 1000, self.spawn, method, *args) def handle_message(self, client, message): always = True if always: raise NotSupported(self.id + '.handle_message() not implemented yet') return {} def watch_multiple(self, url, message_hashes, message=None, subscribe_hashes=None, subscription=None): # base exchange self.open starts the aiohttp Session in an async context self.open() backoff_delay = 0 client = self.client(url) future = Future.race([client.future(message_hash) for message_hash in message_hashes]) missing_subscriptions = [] if subscribe_hashes is not None: for subscribe_hash in subscribe_hashes: if subscribe_hash not in client.subscriptions: missing_subscriptions.append(subscribe_hash) client.subscriptions[subscribe_hash] = subscription or True connected = client.connected if client.connected.done() \ else asyncio.ensure_future(client.connect(self.session, backoff_delay)) def after(fut): # todo: decouple signing from subscriptions options = self.safe_value(self.options, 'ws') cost = self.safe_value(options, 'cost', 1) if message: async def send_message(): if self.enableRateLimit: await client.throttle(cost) try: await client.send(message) except ConnectionError as e: client.on_error(e) except Exception as e: client.on_error(e) asyncio.ensure_future(send_message()) if missing_subscriptions: connected.add_done_callback(after) return future def watch(self, url, message_hash, message=None, subscribe_hash=None, subscription=None): # base exchange self.open starts the aiohttp Session in an async context self.open() backoff_delay = 0 client = self.client(url) if subscribe_hash is None and message_hash in client.futures: return client.futures[message_hash] future = client.future(message_hash) subscribed = client.subscriptions.get(subscribe_hash) if not subscribed: client.subscriptions[subscribe_hash] = subscription or True selected_session = self.session # http/s proxy is being set in other places httpProxy, httpsProxy, socksProxy = self.check_ws_proxy_settings() if (socksProxy): selected_session = self.get_socks_proxy_session(socksProxy) connected = client.connected if client.connected.done() \ else asyncio.ensure_future(client.connect(selected_session, backoff_delay)) def after(fut): # todo: decouple signing from subscriptions options = self.safe_value(self.options, 'ws') cost = self.safe_value(options, 'cost', 1) if message: async def send_message(): if self.enableRateLimit: await client.throttle(cost) try: await client.send(message) except ConnectionError as e: client.on_error(e) except Exception as e: client.on_error(e) asyncio.ensure_future(send_message()) if not subscribed: connected.add_done_callback(after) return future def on_connected(self, client, message=None): # for user hooks # print('Connected to', client.url) pass def on_error(self, client, error): if client.url in self.clients and self.clients[client.url].error: del self.clients[client.url] def on_close(self, client, error): if client.error: # connection closed by the user or due to an error pass else: # server disconnected a working connection if client.url in self.clients: del self.clients[client.url] async def ws_close(self): if self.clients: await asyncio.wait([asyncio.create_task(client.close()) for client in self.clients.values()], return_when=asyncio.ALL_COMPLETED) for url in self.clients.copy(): del self.clients[url] async def load_order_book(self, client, messageHash, symbol, limit=None, params={}): if symbol not in self.orderbooks: client.reject(ExchangeError(self.id + ' loadOrderBook() orderbook is not initiated'), messageHash) return try: maxRetries = self.handle_option('watchOrderBook', 'maxRetries', 3) tries = 0 stored = self.orderbooks[symbol] while tries < maxRetries: cache = stored.cache order_book = await self.fetch_order_book(symbol, limit, params) index = self.get_cache_index(order_book, cache) if index >= 0: stored.reset(order_book) self.handle_deltas(stored, cache[index:]) cache.clear() client.resolve(stored, messageHash) return tries += 1 client.reject(ExchangeError(self.id + ' nonce is behind cache after ' + str(maxRetries) + ' tries.'), messageHash) del self.clients[client.url] except BaseError as e: client.reject(e, messageHash) await self.load_order_book(client, messageHash, symbol, limit, params) def format_scientific_notation_ftx(self, n): if n == 0: return '0e-00' return format(n, 'g') def decode_proto_msg(self, data): if not MessageToDict: raise NotSupported(self.id + ' requires protobuf to decode messages, please install it with `pip install "protobuf==5.29.5"`') message = PushDataV3ApiWrapper_pb2.PushDataV3ApiWrapper() message.ParseFromString(data) dict_msg = MessageToDict(message) # { # "channel":"spot@public.kline.v3.api.pb@BTCUSDT@Min1", # "symbol":"BTCUSDT", # "symbolId":"2fb942154ef44a4ab2ef98c8afb6a4a7", # "createTime":"1754735110559", # "publicSpotKline":{ # "interval":"Min1", # "windowStart":"1754735100", # "openingPrice":"117792.45", # "closingPrice":"117805.32", # "highestPrice":"117814.63", # "lowestPrice":"117792.45", # "volume":"0.13425465", # "amount":"15815.77", # "windowEnd":"1754735160" # } # } return dict_msg # ######################################################################## # ######################################################################## # ######################################################################## # ######################################################################## # ######## ######## ######## # ######## ######## ######## # ######## ######## ######## # ######## ######## ######## # ######## ######################## ######################## # ######## ######################## ######################## # ######## ######################## ######################## # ######## ######################## ######################## # ######## ######## ######## # ######## ######## ######## # ######## ######## ######## # ######## ######## ######## # ######################################################################## # ######################################################################## # ######################################################################## # ######################################################################## # ######## ######## ######## ######## # ######## ######## ######## ######## # ######## ######## ######## ######## # ######## ######## ######## ######## # ################ ######################## ################ # ################ ######################## ################ # ################ ######################## ################ # ################ ######################## ################ # ######## ######## ################ ################ # ######## ######## ################ ################ # ######## ######## ################ ################ # ######## ######## ################ ################ # ######################################################################## # ######################################################################## # ######################################################################## # ######################################################################## # METHODS BELOW THIS LINE ARE TRANSPILED FROM TYPESCRIPT async def fetch_accounts(self, params={}): raise NotSupported(self.id + ' fetchAccounts() is not supported yet') async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' fetchTrades() is not supported yet') async def fetch_trades_ws(self, symbol: str, since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' fetchTradesWs() is not supported yet') async def watch_liquidations(self, symbol: str, since: Int = None, limit: Int = None, params={}): if self.has['watchLiquidationsForSymbols']: return await self.watch_liquidations_for_symbols([symbol], since, limit, params) raise NotSupported(self.id + ' watchLiquidations() is not supported yet') async def watch_liquidations_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' watchLiquidationsForSymbols() is not supported yet') async def watch_my_liquidations(self, symbol: str, since: Int = None, limit: Int = None, params={}): if self.has['watchMyLiquidationsForSymbols']: return self.watch_my_liquidations_for_symbols([symbol], since, limit, params) raise NotSupported(self.id + ' watchMyLiquidations() is not supported yet') async def watch_my_liquidations_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' watchMyLiquidationsForSymbols() is not supported yet') async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' watchTrades() is not supported yet') async def un_watch_orders(self, symbol: Str = None, params={}): raise NotSupported(self.id + ' unWatchOrders() is not supported yet') async def un_watch_trades(self, symbol: str, params={}): raise NotSupported(self.id + ' unWatchTrades() is not supported yet') async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' watchTradesForSymbols() is not supported yet') async def un_watch_trades_for_symbols(self, symbols: List[str], params={}): raise NotSupported(self.id + ' unWatchTradesForSymbols() is not supported yet') async def watch_my_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' watchMyTradesForSymbols() is not supported yet') async def watch_orders_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' watchOrdersForSymbols() is not supported yet') async def watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' watchOHLCVForSymbols() is not supported yet') async def un_watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], params={}): raise NotSupported(self.id + ' unWatchOHLCVForSymbols() is not supported yet') async def watch_order_book_for_symbols(self, symbols: List[str], limit: Int = None, params={}): raise NotSupported(self.id + ' watchOrderBookForSymbols() is not supported yet') async def un_watch_order_book_for_symbols(self, symbols: List[str], params={}): raise NotSupported(self.id + ' unWatchOrderBookForSymbols() is not supported yet') async def un_watch_positions(self, symbols: Strings = None, params={}): raise NotSupported(self.id + ' unWatchPositions() is not supported yet') async def un_watch_ticker(self, symbol: str, params={}): raise NotSupported(self.id + ' unWatchTicker() is not supported yet') async def un_watch_mark_price(self, symbol: str, params={}): raise NotSupported(self.id + ' unWatchMarkPrice() is not supported yet') async def un_watch_mark_prices(self, symbols: Strings = None, params={}): raise NotSupported(self.id + ' unWatchMarkPrices() is not supported yet') async def fetch_deposit_addresses(self, codes: Strings = None, params={}): raise NotSupported(self.id + ' fetchDepositAddresses() is not supported yet') async def fetch_order_book(self, symbol: str, limit: Int = None, params={}): raise NotSupported(self.id + ' fetchOrderBook() is not supported yet') async def fetch_order_book_ws(self, symbol: str, limit: Int = None, params={}): raise NotSupported(self.id + ' fetchOrderBookWs() is not supported yet') async def fetch_margin_mode(self, symbol: str, params={}): if self.has['fetchMarginModes']: marginModes = await self.fetch_margin_modes([symbol], params) return self.safe_dict(marginModes, symbol) else: raise NotSupported(self.id + ' fetchMarginMode() is not supported yet') async def fetch_margin_modes(self, symbols: Strings = None, params={}): raise NotSupported(self.id + ' fetchMarginModes() is not supported yet') async def fetch_rest_order_book_safe(self, symbol, limit=None, params={}): fetchSnapshotMaxRetries = self.handle_option('watchOrderBook', 'maxRetries', 3) for i in range(0, fetchSnapshotMaxRetries): try: orderBook = await self.fetch_order_book(symbol, limit, params) return orderBook except Exception as e: if (i + 1) == fetchSnapshotMaxRetries: raise e return None async def watch_order_book(self, symbol: str, limit: Int = None, params={}): raise NotSupported(self.id + ' watchOrderBook() is not supported yet') async def un_watch_order_book(self, symbol: str, params={}): raise NotSupported(self.id + ' unWatchOrderBook() is not supported yet') async def fetch_time(self, params={}): raise NotSupported(self.id + ' fetchTime() is not supported yet') async def fetch_trading_limits(self, symbols: Strings = None, params={}): raise NotSupported(self.id + ' fetchTradingLimits() is not supported yet') async def fetch_cross_borrow_rates(self, params={}): raise NotSupported(self.id + ' fetchCrossBorrowRates() is not supported yet') async def fetch_isolated_borrow_rates(self, params={}): raise NotSupported(self.id + ' fetchIsolatedBorrowRates() is not supported yet') async def fetch_leverage_tiers(self, symbols: Strings = None, params={}): raise NotSupported(self.id + ' fetchLeverageTiers() is not supported yet') async def fetch_funding_rates(self, symbols: Strings = None, params={}): raise NotSupported(self.id + ' fetchFundingRates() is not supported yet') async def fetch_funding_intervals(self, symbols: Strings = None, params={}): raise NotSupported(self.id + ' fetchFundingIntervals() is not supported yet') async def watch_funding_rate(self, symbol: str, params={}): raise NotSupported(self.id + ' watchFundingRate() is not supported yet') async def watch_funding_rates(self, symbols: List[str], params={}): raise NotSupported(self.id + ' watchFundingRates() is not supported yet') async def watch_funding_rates_for_symbols(self, symbols: List[str], params={}): return await self.watch_funding_rates(symbols, params) async def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}): raise NotSupported(self.id + ' transfer() is not supported yet') async def withdraw(self, code: str, amount: float, address: str, tag: Str = None, params={}): raise NotSupported(self.id + ' withdraw() is not supported yet') async def create_deposit_address(self, code: str, params={}): raise NotSupported(self.id + ' createDepositAddress() is not supported yet') async def set_leverage(self, leverage: int, symbol: Str = None, params={}): raise NotSupported(self.id + ' setLeverage() is not supported yet') async def fetch_leverage(self, symbol: str, params={}): if self.has['fetchLeverages']: leverages = await self.fetch_leverages([symbol], params) return self.safe_dict(leverages, symbol) else: raise NotSupported(self.id + ' fetchLeverage() is not supported yet') async def fetch_leverages(self, symbols: Strings = None, params={}): raise NotSupported(self.id + ' fetchLeverages() is not supported yet') async def set_position_mode(self, hedged: bool, symbol: Str = None, params={}): raise NotSupported(self.id + ' setPositionMode() is not supported yet') async def add_margin(self, symbol: str, amount: float, params={}): raise NotSupported(self.id + ' addMargin() is not supported yet') async def reduce_margin(self, symbol: str, amount: float, params={}): raise NotSupported(self.id + ' reduceMargin() is not supported yet') async def set_margin(self, symbol: str, amount: float, params={}): raise NotSupported(self.id + ' setMargin() is not supported yet') async def fetch_long_short_ratio(self, symbol: str, timeframe: Str = None, params={}): raise NotSupported(self.id + ' fetchLongShortRatio() is not supported yet') async def fetch_long_short_ratio_history(self, symbol: Str = None, timeframe: Str = None, since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' fetchLongShortRatioHistory() is not supported yet') async def fetch_margin_adjustment_history(self, symbol: Str = None, type: Str = None, since: Num = None, limit: Num = None, params={}): """ fetches the history of margin added or reduced from contract isolated positions :param str [symbol]: unified market symbol :param str [type]: "add" or "reduce" :param int [since]: timestamp in ms of the earliest change to fetch :param int [limit]: the maximum amount of changes to fetch :param dict params: extra parameters specific to the exchange api endpoint :returns dict[]: a list of `margin structures ` """ raise NotSupported(self.id + ' fetchMarginAdjustmentHistory() is not supported yet') async def set_margin_mode(self, marginMode: str, symbol: Str = None, params={}): raise NotSupported(self.id + ' setMarginMode() is not supported yet') async def fetch_deposit_addresses_by_network(self, code: str, params={}): raise NotSupported(self.id + ' fetchDepositAddressesByNetwork() is not supported yet') async def fetch_open_interest_history(self, symbol: str, timeframe: str = '1h', since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' fetchOpenInterestHistory() is not supported yet') async def fetch_open_interest(self, symbol: str, params={}): raise NotSupported(self.id + ' fetchOpenInterest() is not supported yet') async def fetch_open_interests(self, symbols: Strings = None, params={}): raise NotSupported(self.id + ' fetchOpenInterests() is not supported yet') async def sign_in(self, params={}): raise NotSupported(self.id + ' signIn() is not supported yet') async def fetch_payment_methods(self, params={}): raise NotSupported(self.id + ' fetchPaymentMethods() is not supported yet') async def fetch_borrow_rate(self, code: str, amount: float, params={}): raise NotSupported(self.id + ' fetchBorrowRate is deprecated, please use fetchCrossBorrowRate or fetchIsolatedBorrowRate instead') async def repay_cross_margin(self, code: str, amount: float, params={}): raise NotSupported(self.id + ' repayCrossMargin is not support yet') async def repay_isolated_margin(self, symbol: str, code: str, amount: float, params={}): raise NotSupported(self.id + ' repayIsolatedMargin is not support yet') async def borrow_cross_margin(self, code: str, amount: float, params={}): raise NotSupported(self.id + ' borrowCrossMargin is not support yet') async def borrow_isolated_margin(self, symbol: str, code: str, amount: float, params={}): raise NotSupported(self.id + ' borrowIsolatedMargin is not support yet') async def borrow_margin(self, code: str, amount: float, symbol: Str = None, params={}): raise NotSupported(self.id + ' borrowMargin is deprecated, please use borrowCrossMargin or borrowIsolatedMargin instead') async def repay_margin(self, code: str, amount: float, symbol: Str = None, params={}): raise NotSupported(self.id + ' repayMargin is deprecated, please use repayCrossMargin or repayIsolatedMargin instead') async def fetch_ohlcv(self, symbol: str, timeframe: str = '1m', since: Int = None, limit: Int = None, params={}): message = '' if self.has['fetchTrades']: message = '. If you want to build OHLCV candles from trade executions data, visit https://github.com/ccxt/ccxt/tree/master/examples/ and see "build-ohlcv-bars" file' raise NotSupported(self.id + ' fetchOHLCV() is not supported yet' + message) async def fetch_ohlcv_ws(self, symbol: str, timeframe: str = '1m', since: Int = None, limit: Int = None, params={}): message = '' if self.has['fetchTradesWs']: message = '. If you want to build OHLCV candles from trade executions data, visit https://github.com/ccxt/ccxt/tree/master/examples/ and see "build-ohlcv-bars" file' raise NotSupported(self.id + ' fetchOHLCVWs() is not supported yet. Try using fetchOHLCV instead.' + message) async def watch_ohlcv(self, symbol: str, timeframe: str = '1m', since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' watchOHLCV() is not supported yet') async def fetch_web_endpoint(self, method, endpointMethod, returnAsJson, startRegex=None, endRegex=None): errorMessage = '' options = self.safe_value(self.options, method, {}) muteOnFailure = self.safe_bool(options, 'webApiMuteFailure', True) try: # if it was not explicitly disabled, then don't fetch if self.safe_bool(options, 'webApiEnable', True) is not True: return None maxRetries = self.safe_value(options, 'webApiRetries', 10) response = None retry = 0 shouldBreak = False while(retry < maxRetries): try: response = await getattr(self, endpointMethod)({}) shouldBreak = True break except Exception as e: retry = retry + 1 if retry == maxRetries: raise e if shouldBreak: break # self is needed because of GO content = response if startRegex is not None: splitted_by_start = content.split(startRegex) content = splitted_by_start[1] # we need second part after start if endRegex is not None: splitted_by_end = content.split(endRegex) content = splitted_by_end[0] # we need first part after start if returnAsJson and (isinstance(content, str)): jsoned = self.parse_json(content.strip()) # content should be trimmed before json parsing if jsoned: return jsoned # if parsing was not successfull, exception should be thrown else: raise BadResponse('could not parse the response into json') else: return content except Exception as e: errorMessage = self.id + ' ' + method + '() failed to fetch correct data from website. Probably webpage markup has been changed, breaking the page custom parser.' if muteOnFailure: return None else: raise BadResponse(errorMessage) async def fetch_l2_order_book(self, symbol: str, limit: Int = None, params={}): orderbook = await self.fetch_order_book(symbol, limit, params) return self.extend(orderbook, { 'asks': self.sort_by(self.aggregate(orderbook['asks']), 0), 'bids': self.sort_by(self.aggregate(orderbook['bids']), 0, True), }) async def load_trading_limits(self, symbols: Strings = None, reload=False, params={}): if self.has['fetchTradingLimits']: if reload or not ('limitsLoaded' in self.options): response = await self.fetch_trading_limits(symbols) for i in range(0, len(symbols)): symbol = symbols[i] self.markets[symbol] = self.deep_extend(self.markets[symbol], response[symbol]) self.options['limitsLoaded'] = self.milliseconds() return self.markets async def fetch2(self, path, api: Any = 'public', method='GET', params={}, headers: Any = None, body: Any = None, config={}): if self.enableRateLimit: cost = self.calculate_rate_limiter_cost(api, method, path, params, config) await self.throttle(cost) retries = None retries, params = self.handle_option_and_params(params, path, 'maxRetriesOnFailure', 0) retryDelay = None retryDelay, params = self.handle_option_and_params(params, path, 'maxRetriesOnFailureDelay', 0) self.lastRestRequestTimestamp = self.milliseconds() request = self.sign(path, api, method, params, headers, body) self.last_request_headers = request['headers'] self.last_request_body = request['body'] self.last_request_url = request['url'] for i in range(0, retries + 1): try: return await self.fetch(request['url'], request['method'], request['headers'], request['body']) except Exception as e: if isinstance(e, OperationFailed): if i < retries: if self.verbose: self.log('Request failed with the error: ' + str(e) + ', retrying ' + (i + str(1)) + ' of ' + str(retries) + '...') if (retryDelay is not None) and (retryDelay != 0): await self.sleep(retryDelay) else: raise e else: raise e return None # self line is never reached, but exists for c# value return requirement async def request(self, path, api: Any = 'public', method='GET', params={}, headers: Any = None, body: Any = None, config={}): return await self.fetch2(path, api, method, params, headers, body, config) async def load_accounts(self, reload=False, params={}): if reload: self.accounts = await self.fetch_accounts(params) else: if self.accounts: return self.accounts else: self.accounts = await self.fetch_accounts(params) self.accountsById = self.index_by(self.accounts, 'id') return self.accounts async def edit_limit_buy_order(self, id: str, symbol: str, amount: float, price: Num = None, params={}): return await self.edit_limit_order(id, symbol, 'buy', amount, price, params) async def edit_limit_sell_order(self, id: str, symbol: str, amount: float, price: Num = None, params={}): return await self.edit_limit_order(id, symbol, 'sell', amount, price, params) async def edit_limit_order(self, id: str, symbol: str, side: OrderSide, amount: float, price: Num = None, params={}): return await self.edit_order(id, symbol, 'limit', side, amount, price, params) async def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}): await self.cancel_order(id, symbol) return await self.create_order(symbol, type, side, amount, price, params) async def edit_order_with_client_order_id(self, clientOrderId: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}): return await self.edit_order('', symbol, type, side, amount, price, self.extend({'clientOrderId': clientOrderId}, params)) async def edit_order_ws(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}): await self.cancel_order_ws(id, symbol) return await self.create_order_ws(symbol, type, side, amount, price, params) async def fetch_position(self, symbol: str, params={}): raise NotSupported(self.id + ' fetchPosition() is not supported yet') async def fetch_position_ws(self, symbol: str, params={}): raise NotSupported(self.id + ' fetchPositionWs() is not supported yet') async def watch_position(self, symbol: Str = None, params={}): raise NotSupported(self.id + ' watchPosition() is not supported yet') async def watch_positions(self, symbols: Strings = None, since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' watchPositions() is not supported yet') async def watch_position_for_symbols(self, symbols: Strings = None, since: Int = None, limit: Int = None, params={}): return await self.watch_positions(symbols, since, limit, params) async def fetch_positions_for_symbol(self, symbol: str, params={}): """ fetches all open positions for specific symbol, unlike fetchPositions(which is designed to work with multiple symbols) so self method might be preffered for one-market position, because of less rate-limit consumption and speed :param str symbol: unified market symbol :param dict params: extra parameters specific to the endpoint :returns dict[]: a list of `position structure ` with maximum 3 items - possible one position for "one-way" mode, and possible two positions(long & short) for "two-way"(a.k.a. hedge) mode """ raise NotSupported(self.id + ' fetchPositionsForSymbol() is not supported yet') async def fetch_positions_for_symbol_ws(self, symbol: str, params={}): """ fetches all open positions for specific symbol, unlike fetchPositions(which is designed to work with multiple symbols) so self method might be preffered for one-market position, because of less rate-limit consumption and speed :param str symbol: unified market symbol :param dict params: extra parameters specific to the endpoint :returns dict[]: a list of `position structure ` with maximum 3 items - possible one position for "one-way" mode, and possible two positions(long & short) for "two-way"(a.k.a. hedge) mode """ raise NotSupported(self.id + ' fetchPositionsForSymbol() is not supported yet') async def fetch_positions(self, symbols: Strings = None, params={}): raise NotSupported(self.id + ' fetchPositions() is not supported yet') async def fetch_positions_ws(self, symbols: Strings = None, params={}): raise NotSupported(self.id + ' fetchPositions() is not supported yet') async def fetch_positions_risk(self, symbols: Strings = None, params={}): raise NotSupported(self.id + ' fetchPositionsRisk() is not supported yet') async def fetch_bids_asks(self, symbols: Strings = None, params={}): raise NotSupported(self.id + ' fetchBidsAsks() is not supported yet') async def fetch_borrow_interest(self, code: Str = None, symbol: Str = None, since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' fetchBorrowInterest() is not supported yet') async def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' fetchLedger() is not supported yet') async def fetch_ledger_entry(self, id: str, code: Str = None, params={}): raise NotSupported(self.id + ' fetchLedgerEntry() is not supported yet') async def fetch_balance(self, params={}): raise NotSupported(self.id + ' fetchBalance() is not supported yet') async def fetch_balance_ws(self, params={}): raise NotSupported(self.id + ' fetchBalanceWs() is not supported yet') async def watch_balance(self, params={}): raise NotSupported(self.id + ' watchBalance() is not supported yet') async def fetch_partial_balance(self, part, params={}): balance = await self.fetch_balance(params) return balance[part] async def fetch_free_balance(self, params={}): return await self.fetch_partial_balance('free', params) async def fetch_used_balance(self, params={}): return await self.fetch_partial_balance('used', params) async def fetch_total_balance(self, params={}): return await self.fetch_partial_balance('total', params) async def fetch_status(self, params={}): raise NotSupported(self.id + ' fetchStatus() is not supported yet') async def fetch_transaction_fee(self, code: str, params={}): if not self.has['fetchTransactionFees']: raise NotSupported(self.id + ' fetchTransactionFee() is not supported yet') return await self.fetch_transaction_fees([code], params) async def fetch_transaction_fees(self, codes: Strings = None, params={}): raise NotSupported(self.id + ' fetchTransactionFees() is not supported yet') async def fetch_deposit_withdraw_fees(self, codes: Strings = None, params={}): raise NotSupported(self.id + ' fetchDepositWithdrawFees() is not supported yet') async def fetch_deposit_withdraw_fee(self, code: str, params={}): if not self.has['fetchDepositWithdrawFees']: raise NotSupported(self.id + ' fetchDepositWithdrawFee() is not supported yet') fees = await self.fetch_deposit_withdraw_fees([code], params) return self.safe_value(fees, code) async def fetch_cross_borrow_rate(self, code: str, params={}): await self.load_markets() if not self.has['fetchBorrowRates']: raise NotSupported(self.id + ' fetchCrossBorrowRate() is not supported yet') borrowRates = await self.fetch_cross_borrow_rates(params) rate = self.safe_value(borrowRates, code) if rate is None: raise ExchangeError(self.id + ' fetchCrossBorrowRate() could not find the borrow rate for currency code ' + code) return rate async def fetch_isolated_borrow_rate(self, symbol: str, params={}): await self.load_markets() if not self.has['fetchBorrowRates']: raise NotSupported(self.id + ' fetchIsolatedBorrowRate() is not supported yet') borrowRates = await self.fetch_isolated_borrow_rates(params) rate = self.safe_dict(borrowRates, symbol) if rate is None: raise ExchangeError(self.id + ' fetchIsolatedBorrowRate() could not find the borrow rate for market symbol ' + symbol) return rate async def fetch_ticker(self, symbol: str, params={}): if self.has['fetchTickers']: await self.load_markets() market = self.market(symbol) symbol = market['symbol'] tickers = await self.fetch_tickers([symbol], params) ticker = self.safe_dict(tickers, symbol) if ticker is None: raise NullResponse(self.id + ' fetchTickers() could not find a ticker for ' + symbol) else: return ticker else: raise NotSupported(self.id + ' fetchTicker() is not supported yet') async def fetch_mark_price(self, symbol: str, params={}): if self.has['fetchMarkPrices']: await self.load_markets() market = self.market(symbol) symbol = market['symbol'] tickers = await self.fetch_mark_prices([symbol], params) ticker = self.safe_dict(tickers, symbol) if ticker is None: raise NullResponse(self.id + ' fetchMarkPrices() could not find a ticker for ' + symbol) else: return ticker else: raise NotSupported(self.id + ' fetchMarkPrices() is not supported yet') async def fetch_ticker_ws(self, symbol: str, params={}): if self.has['fetchTickersWs']: await self.load_markets() market = self.market(symbol) symbol = market['symbol'] tickers = await self.fetch_tickers_ws([symbol], params) ticker = self.safe_dict(tickers, symbol) if ticker is None: raise NullResponse(self.id + ' fetchTickerWs() could not find a ticker for ' + symbol) else: return ticker else: raise NotSupported(self.id + ' fetchTickerWs() is not supported yet') async def watch_ticker(self, symbol: str, params={}): raise NotSupported(self.id + ' watchTicker() is not supported yet') async def fetch_tickers(self, symbols: Strings = None, params={}): raise NotSupported(self.id + ' fetchTickers() is not supported yet') async def fetch_mark_prices(self, symbols: Strings = None, params={}): raise NotSupported(self.id + ' fetchMarkPrices() is not supported yet') async def fetch_tickers_ws(self, symbols: Strings = None, params={}): raise NotSupported(self.id + ' fetchTickers() is not supported yet') async def fetch_order_books(self, symbols: Strings = None, limit: Int = None, params={}): raise NotSupported(self.id + ' fetchOrderBooks() is not supported yet') async def watch_bids_asks(self, symbols: Strings = None, params={}): raise NotSupported(self.id + ' watchBidsAsks() is not supported yet') async def watch_tickers(self, symbols: Strings = None, params={}): raise NotSupported(self.id + ' watchTickers() is not supported yet') async def un_watch_tickers(self, symbols: Strings = None, params={}): raise NotSupported(self.id + ' unWatchTickers() is not supported yet') async def fetch_order(self, id: str, symbol: Str = None, params={}): raise NotSupported(self.id + ' fetchOrder() is not supported yet') async def fetch_order_with_client_order_id(self, clientOrderId: str, symbol: Str = None, params={}): """ create a market order by providing the symbol, side and cost :param str clientOrderId: client order Id :param str symbol: unified symbol of the market to create an order in :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: an `order structure ` """ extendedParams = self.extend(params, {'clientOrderId': clientOrderId}) return await self.fetch_order('', symbol, extendedParams) async def fetch_order_ws(self, id: str, symbol: Str = None, params={}): raise NotSupported(self.id + ' fetchOrderWs() is not supported yet') async def fetch_order_status(self, id: str, symbol: Str = None, params={}): # TODO: TypeScript: change method signature by replacing # Promise with Promise. order = await self.fetch_order(id, symbol, params) return order['status'] async def fetch_unified_order(self, order, params={}): return await self.fetch_order(self.safe_string(order, 'id'), self.safe_string(order, 'symbol'), params) async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}): raise NotSupported(self.id + ' createOrder() is not supported yet') async def create_convert_trade(self, id: str, fromCode: str, toCode: str, amount: Num = None, params={}): raise NotSupported(self.id + ' createConvertTrade() is not supported yet') async def fetch_convert_trade(self, id: str, code: Str = None, params={}): raise NotSupported(self.id + ' fetchConvertTrade() is not supported yet') async def fetch_convert_trade_history(self, code: Str = None, since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' fetchConvertTradeHistory() is not supported yet') async def fetch_position_mode(self, symbol: Str = None, params={}): raise NotSupported(self.id + ' fetchPositionMode() is not supported yet') async def create_trailing_amount_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, trailingAmount: Num = None, trailingTriggerPrice: Num = None, params={}): """ create a trailing order by providing the symbol, type, side, amount, price and trailingAmount :param str symbol: unified symbol of the market to create an order in :param str type: 'market' or 'limit' :param str side: 'buy' or 'sell' :param float amount: how much you want to trade in units of the base currency, or number of contracts :param float [price]: the price for the order to be filled at, in units of the quote currency, ignored in market orders :param float trailingAmount: the quote amount to trail away from the current market price :param float [trailingTriggerPrice]: the price to activate a trailing order, default uses the price argument :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: an `order structure ` """ if trailingAmount is None: raise ArgumentsRequired(self.id + ' createTrailingAmountOrder() requires a trailingAmount argument') params['trailingAmount'] = trailingAmount if trailingTriggerPrice is not None: params['trailingTriggerPrice'] = trailingTriggerPrice if self.has['createTrailingAmountOrder']: return await self.create_order(symbol, type, side, amount, price, params) raise NotSupported(self.id + ' createTrailingAmountOrder() is not supported yet') async def create_trailing_amount_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, trailingAmount: Num = None, trailingTriggerPrice: Num = None, params={}): """ create a trailing order by providing the symbol, type, side, amount, price and trailingAmount :param str symbol: unified symbol of the market to create an order in :param str type: 'market' or 'limit' :param str side: 'buy' or 'sell' :param float amount: how much you want to trade in units of the base currency, or number of contracts :param float [price]: the price for the order to be filled at, in units of the quote currency, ignored in market orders :param float trailingAmount: the quote amount to trail away from the current market price :param float [trailingTriggerPrice]: the price to activate a trailing order, default uses the price argument :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: an `order structure ` """ if trailingAmount is None: raise ArgumentsRequired(self.id + ' createTrailingAmountOrderWs() requires a trailingAmount argument') params['trailingAmount'] = trailingAmount if trailingTriggerPrice is not None: params['trailingTriggerPrice'] = trailingTriggerPrice if self.has['createTrailingAmountOrderWs']: return await self.create_order_ws(symbol, type, side, amount, price, params) raise NotSupported(self.id + ' createTrailingAmountOrderWs() is not supported yet') async def create_trailing_percent_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, trailingPercent: Num = None, trailingTriggerPrice: Num = None, params={}): """ create a trailing order by providing the symbol, type, side, amount, price and trailingPercent :param str symbol: unified symbol of the market to create an order in :param str type: 'market' or 'limit' :param str side: 'buy' or 'sell' :param float amount: how much you want to trade in units of the base currency, or number of contracts :param float [price]: the price for the order to be filled at, in units of the quote currency, ignored in market orders :param float trailingPercent: the percent to trail away from the current market price :param float [trailingTriggerPrice]: the price to activate a trailing order, default uses the price argument :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: an `order structure ` """ if trailingPercent is None: raise ArgumentsRequired(self.id + ' createTrailingPercentOrder() requires a trailingPercent argument') params['trailingPercent'] = trailingPercent if trailingTriggerPrice is not None: params['trailingTriggerPrice'] = trailingTriggerPrice if self.has['createTrailingPercentOrder']: return await self.create_order(symbol, type, side, amount, price, params) raise NotSupported(self.id + ' createTrailingPercentOrder() is not supported yet') async def create_trailing_percent_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, trailingPercent: Num = None, trailingTriggerPrice: Num = None, params={}): """ create a trailing order by providing the symbol, type, side, amount, price and trailingPercent :param str symbol: unified symbol of the market to create an order in :param str type: 'market' or 'limit' :param str side: 'buy' or 'sell' :param float amount: how much you want to trade in units of the base currency, or number of contracts :param float [price]: the price for the order to be filled at, in units of the quote currency, ignored in market orders :param float trailingPercent: the percent to trail away from the current market price :param float [trailingTriggerPrice]: the price to activate a trailing order, default uses the price argument :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: an `order structure ` """ if trailingPercent is None: raise ArgumentsRequired(self.id + ' createTrailingPercentOrderWs() requires a trailingPercent argument') params['trailingPercent'] = trailingPercent if trailingTriggerPrice is not None: params['trailingTriggerPrice'] = trailingTriggerPrice if self.has['createTrailingPercentOrderWs']: return await self.create_order_ws(symbol, type, side, amount, price, params) raise NotSupported(self.id + ' createTrailingPercentOrderWs() is not supported yet') async def create_market_order_with_cost(self, symbol: str, side: OrderSide, cost: float, params={}): """ create a market order by providing the symbol, side and cost :param str symbol: unified symbol of the market to create an order in :param str side: 'buy' or 'sell' :param float cost: how much you want to trade in units of the quote currency :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: an `order structure ` """ if self.has['createMarketOrderWithCost'] or (self.has['createMarketBuyOrderWithCost'] and self.has['createMarketSellOrderWithCost']): return await self.create_order(symbol, 'market', side, cost, 1, params) raise NotSupported(self.id + ' createMarketOrderWithCost() is not supported yet') async def create_market_buy_order_with_cost(self, symbol: str, cost: float, params={}): """ create a market buy order by providing the symbol and cost :param str symbol: unified symbol of the market to create an order in :param float cost: how much you want to trade in units of the quote currency :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: an `order structure ` """ if self.options['createMarketBuyOrderRequiresPrice'] or self.has['createMarketBuyOrderWithCost']: return await self.create_order(symbol, 'market', 'buy', cost, 1, params) raise NotSupported(self.id + ' createMarketBuyOrderWithCost() is not supported yet') async def create_market_sell_order_with_cost(self, symbol: str, cost: float, params={}): """ create a market sell order by providing the symbol and cost :param str symbol: unified symbol of the market to create an order in :param float cost: how much you want to trade in units of the quote currency :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: an `order structure ` """ if self.options['createMarketSellOrderRequiresPrice'] or self.has['createMarketSellOrderWithCost']: return await self.create_order(symbol, 'market', 'sell', cost, 1, params) raise NotSupported(self.id + ' createMarketSellOrderWithCost() is not supported yet') async def create_market_order_with_cost_ws(self, symbol: str, side: OrderSide, cost: float, params={}): """ create a market order by providing the symbol, side and cost :param str symbol: unified symbol of the market to create an order in :param str side: 'buy' or 'sell' :param float cost: how much you want to trade in units of the quote currency :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: an `order structure ` """ if self.has['createMarketOrderWithCostWs'] or (self.has['createMarketBuyOrderWithCostWs'] and self.has['createMarketSellOrderWithCostWs']): return await self.create_order_ws(symbol, 'market', side, cost, 1, params) raise NotSupported(self.id + ' createMarketOrderWithCostWs() is not supported yet') async def create_trigger_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, triggerPrice: Num = None, params={}): """ create a trigger stop order(type 1) :param str symbol: unified symbol of the market to create an order in :param str type: 'market' or 'limit' :param str side: 'buy' or 'sell' :param float amount: how much you want to trade in units of the base currency or the number of contracts :param float [price]: the price to fulfill the order, in units of the quote currency, ignored in market orders :param float triggerPrice: the price to trigger the stop order, in units of the quote currency :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: an `order structure ` """ if triggerPrice is None: raise ArgumentsRequired(self.id + ' createTriggerOrder() requires a triggerPrice argument') params['triggerPrice'] = triggerPrice if self.has['createTriggerOrder']: return await self.create_order(symbol, type, side, amount, price, params) raise NotSupported(self.id + ' createTriggerOrder() is not supported yet') async def create_trigger_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, triggerPrice: Num = None, params={}): """ create a trigger stop order(type 1) :param str symbol: unified symbol of the market to create an order in :param str type: 'market' or 'limit' :param str side: 'buy' or 'sell' :param float amount: how much you want to trade in units of the base currency or the number of contracts :param float [price]: the price to fulfill the order, in units of the quote currency, ignored in market orders :param float triggerPrice: the price to trigger the stop order, in units of the quote currency :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: an `order structure ` """ if triggerPrice is None: raise ArgumentsRequired(self.id + ' createTriggerOrderWs() requires a triggerPrice argument') params['triggerPrice'] = triggerPrice if self.has['createTriggerOrderWs']: return await self.create_order_ws(symbol, type, side, amount, price, params) raise NotSupported(self.id + ' createTriggerOrderWs() is not supported yet') async def create_stop_loss_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, stopLossPrice: Num = None, params={}): """ create a trigger stop loss order(type 2) :param str symbol: unified symbol of the market to create an order in :param str type: 'market' or 'limit' :param str side: 'buy' or 'sell' :param float amount: how much you want to trade in units of the base currency or the number of contracts :param float [price]: the price to fulfill the order, in units of the quote currency, ignored in market orders :param float stopLossPrice: the price to trigger the stop loss order, in units of the quote currency :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: an `order structure ` """ if stopLossPrice is None: raise ArgumentsRequired(self.id + ' createStopLossOrder() requires a stopLossPrice argument') params['stopLossPrice'] = stopLossPrice if self.has['createStopLossOrder']: return await self.create_order(symbol, type, side, amount, price, params) raise NotSupported(self.id + ' createStopLossOrder() is not supported yet') async def create_stop_loss_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, stopLossPrice: Num = None, params={}): """ create a trigger stop loss order(type 2) :param str symbol: unified symbol of the market to create an order in :param str type: 'market' or 'limit' :param str side: 'buy' or 'sell' :param float amount: how much you want to trade in units of the base currency or the number of contracts :param float [price]: the price to fulfill the order, in units of the quote currency, ignored in market orders :param float stopLossPrice: the price to trigger the stop loss order, in units of the quote currency :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: an `order structure ` """ if stopLossPrice is None: raise ArgumentsRequired(self.id + ' createStopLossOrderWs() requires a stopLossPrice argument') params['stopLossPrice'] = stopLossPrice if self.has['createStopLossOrderWs']: return await self.create_order_ws(symbol, type, side, amount, price, params) raise NotSupported(self.id + ' createStopLossOrderWs() is not supported yet') async def create_take_profit_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, takeProfitPrice: Num = None, params={}): """ create a trigger take profit order(type 2) :param str symbol: unified symbol of the market to create an order in :param str type: 'market' or 'limit' :param str side: 'buy' or 'sell' :param float amount: how much you want to trade in units of the base currency or the number of contracts :param float [price]: the price to fulfill the order, in units of the quote currency, ignored in market orders :param float takeProfitPrice: the price to trigger the take profit order, in units of the quote currency :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: an `order structure ` """ if takeProfitPrice is None: raise ArgumentsRequired(self.id + ' createTakeProfitOrder() requires a takeProfitPrice argument') params['takeProfitPrice'] = takeProfitPrice if self.has['createTakeProfitOrder']: return await self.create_order(symbol, type, side, amount, price, params) raise NotSupported(self.id + ' createTakeProfitOrder() is not supported yet') async def create_take_profit_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, takeProfitPrice: Num = None, params={}): """ create a trigger take profit order(type 2) :param str symbol: unified symbol of the market to create an order in :param str type: 'market' or 'limit' :param str side: 'buy' or 'sell' :param float amount: how much you want to trade in units of the base currency or the number of contracts :param float [price]: the price to fulfill the order, in units of the quote currency, ignored in market orders :param float takeProfitPrice: the price to trigger the take profit order, in units of the quote currency :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: an `order structure ` """ if takeProfitPrice is None: raise ArgumentsRequired(self.id + ' createTakeProfitOrderWs() requires a takeProfitPrice argument') params['takeProfitPrice'] = takeProfitPrice if self.has['createTakeProfitOrderWs']: return await self.create_order_ws(symbol, type, side, amount, price, params) raise NotSupported(self.id + ' createTakeProfitOrderWs() is not supported yet') async def create_order_with_take_profit_and_stop_loss(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, takeProfit: Num = None, stopLoss: Num = None, params={}): """ create an order with a stop loss or take profit attached(type 3) :param str symbol: unified symbol of the market to create an order in :param str type: 'market' or 'limit' :param str side: 'buy' or 'sell' :param float amount: how much you want to trade in units of the base currency or the number of contracts :param float [price]: the price to fulfill the order, in units of the quote currency, ignored in market orders :param float [takeProfit]: the take profit price, in units of the quote currency :param float [stopLoss]: the stop loss price, in units of the quote currency :param dict [params]: extra parameters specific to the exchange API endpoint :param str [params.takeProfitType]: *not available on all exchanges* 'limit' or 'market' :param str [params.stopLossType]: *not available on all exchanges* 'limit' or 'market' :param str [params.takeProfitPriceType]: *not available on all exchanges* 'last', 'mark' or 'index' :param str [params.stopLossPriceType]: *not available on all exchanges* 'last', 'mark' or 'index' :param float [params.takeProfitLimitPrice]: *not available on all exchanges* limit price for a limit take profit order :param float [params.stopLossLimitPrice]: *not available on all exchanges* stop loss for a limit stop loss order :param float [params.takeProfitAmount]: *not available on all exchanges* the amount for a take profit :param float [params.stopLossAmount]: *not available on all exchanges* the amount for a stop loss :returns dict: an `order structure ` """ params = self.set_take_profit_and_stop_loss_params(symbol, type, side, amount, price, takeProfit, stopLoss, params) if self.has['createOrderWithTakeProfitAndStopLoss']: return await self.create_order(symbol, type, side, amount, price, params) raise NotSupported(self.id + ' createOrderWithTakeProfitAndStopLoss() is not supported yet') async def create_order_with_take_profit_and_stop_loss_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, takeProfit: Num = None, stopLoss: Num = None, params={}): """ create an order with a stop loss or take profit attached(type 3) :param str symbol: unified symbol of the market to create an order in :param str type: 'market' or 'limit' :param str side: 'buy' or 'sell' :param float amount: how much you want to trade in units of the base currency or the number of contracts :param float [price]: the price to fulfill the order, in units of the quote currency, ignored in market orders :param float [takeProfit]: the take profit price, in units of the quote currency :param float [stopLoss]: the stop loss price, in units of the quote currency :param dict [params]: extra parameters specific to the exchange API endpoint :param str [params.takeProfitType]: *not available on all exchanges* 'limit' or 'market' :param str [params.stopLossType]: *not available on all exchanges* 'limit' or 'market' :param str [params.takeProfitPriceType]: *not available on all exchanges* 'last', 'mark' or 'index' :param str [params.stopLossPriceType]: *not available on all exchanges* 'last', 'mark' or 'index' :param float [params.takeProfitLimitPrice]: *not available on all exchanges* limit price for a limit take profit order :param float [params.stopLossLimitPrice]: *not available on all exchanges* stop loss for a limit stop loss order :param float [params.takeProfitAmount]: *not available on all exchanges* the amount for a take profit :param float [params.stopLossAmount]: *not available on all exchanges* the amount for a stop loss :returns dict: an `order structure ` """ params = self.set_take_profit_and_stop_loss_params(symbol, type, side, amount, price, takeProfit, stopLoss, params) if self.has['createOrderWithTakeProfitAndStopLossWs']: return await self.create_order_ws(symbol, type, side, amount, price, params) raise NotSupported(self.id + ' createOrderWithTakeProfitAndStopLossWs() is not supported yet') async def create_orders(self, orders: List[OrderRequest], params={}): raise NotSupported(self.id + ' createOrders() is not supported yet') async def edit_orders(self, orders: List[OrderRequest], params={}): raise NotSupported(self.id + ' editOrders() is not supported yet') async def create_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}): raise NotSupported(self.id + ' createOrderWs() is not supported yet') async def cancel_order(self, id: str, symbol: Str = None, params={}): raise NotSupported(self.id + ' cancelOrder() is not supported yet') async def cancel_order_with_client_order_id(self, clientOrderId: str, symbol: Str = None, params={}): """ create a market order by providing the symbol, side and cost :param str clientOrderId: client order Id :param str symbol: unified symbol of the market to create an order in :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: an `order structure ` """ extendedParams = self.extend(params, {'clientOrderId': clientOrderId}) return await self.cancel_order('', symbol, extendedParams) async def cancel_order_ws(self, id: str, symbol: Str = None, params={}): raise NotSupported(self.id + ' cancelOrderWs() is not supported yet') async def cancel_orders(self, ids: List[str], symbol: Str = None, params={}): raise NotSupported(self.id + ' cancelOrders() is not supported yet') async def cancel_orders_with_client_order_ids(self, clientOrderIds: List[str], symbol: Str = None, params={}): """ create a market order by providing the symbol, side and cost :param str[] clientOrderIds: client order Ids :param str symbol: unified symbol of the market to create an order in :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: an `order structure ` """ extendedParams = self.extend(params, {'clientOrderIds': clientOrderIds}) return await self.cancel_orders([], symbol, extendedParams) async def cancel_orders_ws(self, ids: List[str], symbol: Str = None, params={}): raise NotSupported(self.id + ' cancelOrdersWs() is not supported yet') async def cancel_all_orders(self, symbol: Str = None, params={}): raise NotSupported(self.id + ' cancelAllOrders() is not supported yet') async def cancel_all_orders_after(self, timeout: Int, params={}): raise NotSupported(self.id + ' cancelAllOrdersAfter() is not supported yet') async def cancel_orders_for_symbols(self, orders: List[CancellationRequest], params={}): raise NotSupported(self.id + ' cancelOrdersForSymbols() is not supported yet') async def cancel_all_orders_ws(self, symbol: Str = None, params={}): raise NotSupported(self.id + ' cancelAllOrdersWs() is not supported yet') async def cancel_unified_order(self, order: Order, params={}): return self.cancel_order(self.safe_string(order, 'id'), self.safe_string(order, 'symbol'), params) async def fetch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}): if self.has['fetchOpenOrders'] and self.has['fetchClosedOrders']: raise NotSupported(self.id + ' fetchOrders() is not supported yet, consider using fetchOpenOrders() and fetchClosedOrders() instead') raise NotSupported(self.id + ' fetchOrders() is not supported yet') async def fetch_orders_ws(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' fetchOrdersWs() is not supported yet') async def fetch_order_trades(self, id: str, symbol: Str = None, since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' fetchOrderTrades() is not supported yet') async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' watchOrders() is not supported yet') async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}): if self.has['fetchOrders']: orders = await self.fetch_orders(symbol, since, limit, params) return self.filter_by(orders, 'status', 'open') raise NotSupported(self.id + ' fetchOpenOrders() is not supported yet') async def fetch_open_orders_ws(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}): if self.has['fetchOrdersWs']: orders = await self.fetch_orders_ws(symbol, since, limit, params) return self.filter_by(orders, 'status', 'open') raise NotSupported(self.id + ' fetchOpenOrdersWs() is not supported yet') async def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}): if self.has['fetchOrders']: orders = await self.fetch_orders(symbol, since, limit, params) return self.filter_by(orders, 'status', 'closed') raise NotSupported(self.id + ' fetchClosedOrders() is not supported yet') async def fetch_canceled_and_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' fetchCanceledAndClosedOrders() is not supported yet') async def fetch_closed_orders_ws(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}): if self.has['fetchOrdersWs']: orders = await self.fetch_orders_ws(symbol, since, limit, params) return self.filter_by(orders, 'status', 'closed') raise NotSupported(self.id + ' fetchClosedOrdersWs() is not supported yet') async def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' fetchMyTrades() is not supported yet') async def fetch_my_liquidations(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' fetchMyLiquidations() is not supported yet') async def fetch_liquidations(self, symbol: str, since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' fetchLiquidations() is not supported yet') async def fetch_my_trades_ws(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' fetchMyTradesWs() is not supported yet') async def watch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' watchMyTrades() is not supported yet') async def fetch_greeks(self, symbol: str, params={}): raise NotSupported(self.id + ' fetchGreeks() is not supported yet') async def fetch_all_greeks(self, symbols: Strings = None, params={}): raise NotSupported(self.id + ' fetchAllGreeks() is not supported yet') async def fetch_option_chain(self, code: str, params={}): raise NotSupported(self.id + ' fetchOptionChain() is not supported yet') async def fetch_option(self, symbol: str, params={}): raise NotSupported(self.id + ' fetchOption() is not supported yet') async def fetch_convert_quote(self, fromCode: str, toCode: str, amount: Num = None, params={}): raise NotSupported(self.id + ' fetchConvertQuote() is not supported yet') async def fetch_deposits_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}): """ fetch history of deposits and withdrawals :param str [code]: unified currency code for the currency of the deposit/withdrawals, default is None :param int [since]: timestamp in ms of the earliest deposit/withdrawal, default is None :param int [limit]: max number of deposit/withdrawals to return, default is None :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: a list of `transaction structures ` """ raise NotSupported(self.id + ' fetchDepositsWithdrawals() is not supported yet') async def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' fetchDeposits() is not supported yet') async def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' fetchWithdrawals() is not supported yet') async def fetch_deposits_ws(self, code: Str = None, since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' fetchDepositsWs() is not supported yet') async def fetch_withdrawals_ws(self, code: Str = None, since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' fetchWithdrawalsWs() is not supported yet') async def fetch_funding_rate_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' fetchFundingRateHistory() is not supported yet') async def fetch_funding_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}): raise NotSupported(self.id + ' fetchFundingHistory() is not supported yet') async def close_position(self, symbol: str, side: OrderSide = None, params={}): raise NotSupported(self.id + ' closePosition() is not supported yet') async def close_all_positions(self, params={}): raise NotSupported(self.id + ' closeAllPositions() is not supported yet') async def fetch_l3_order_book(self, symbol: str, limit: Int = None, params={}): raise BadRequest(self.id + ' fetchL3OrderBook() is not supported yet') async def fetch_deposit_address(self, code: str, params={}): if self.has['fetchDepositAddresses']: depositAddresses = await self.fetch_deposit_addresses([code], params) depositAddress = self.safe_value(depositAddresses, code) if depositAddress is None: raise InvalidAddress(self.id + ' fetchDepositAddress() could not find a deposit address for ' + code + ', make sure you have created a corresponding deposit address in your wallet on the exchange website') else: return depositAddress elif self.has['fetchDepositAddressesByNetwork']: network = self.safe_string(params, 'network') params = self.omit(params, 'network') addressStructures = await self.fetch_deposit_addresses_by_network(code, params) if network is not None: return self.safe_dict(addressStructures, network) else: keys = list(addressStructures.keys()) key = self.safe_string(keys, 0) return self.safe_dict(addressStructures, key) else: raise NotSupported(self.id + ' fetchDepositAddress() is not supported yet') async def create_limit_order(self, symbol: str, side: OrderSide, amount: float, price: float, params={}): return await self.create_order(symbol, 'limit', side, amount, price, params) async def create_limit_order_ws(self, symbol: str, side: OrderSide, amount: float, price: float, params={}): return await self.create_order_ws(symbol, 'limit', side, amount, price, params) async def create_market_order(self, symbol: str, side: OrderSide, amount: float, price: Num = None, params={}): return await self.create_order(symbol, 'market', side, amount, price, params) async def create_market_order_ws(self, symbol: str, side: OrderSide, amount: float, price: Num = None, params={}): return await self.create_order_ws(symbol, 'market', side, amount, price, params) async def create_limit_buy_order(self, symbol: str, amount: float, price: float, params={}): return await self.create_order(symbol, 'limit', 'buy', amount, price, params) async def create_limit_buy_order_ws(self, symbol: str, amount: float, price: float, params={}): return await self.create_order_ws(symbol, 'limit', 'buy', amount, price, params) async def create_limit_sell_order(self, symbol: str, amount: float, price: float, params={}): return await self.create_order(symbol, 'limit', 'sell', amount, price, params) async def create_limit_sell_order_ws(self, symbol: str, amount: float, price: float, params={}): return await self.create_order_ws(symbol, 'limit', 'sell', amount, price, params) async def create_market_buy_order(self, symbol: str, amount: float, params={}): return await self.create_order(symbol, 'market', 'buy', amount, None, params) async def create_market_buy_order_ws(self, symbol: str, amount: float, params={}): return await self.create_order_ws(symbol, 'market', 'buy', amount, None, params) async def create_market_sell_order(self, symbol: str, amount: float, params={}): return await self.create_order(symbol, 'market', 'sell', amount, None, params) async def create_market_sell_order_ws(self, symbol: str, amount: float, params={}): return await self.create_order_ws(symbol, 'market', 'sell', amount, None, params) async def load_time_difference(self, params={}): serverTime = await self.fetch_time(params) after = self.milliseconds() self.options['timeDifference'] = after - serverTime return self.options['timeDifference'] async def fetch_market_leverage_tiers(self, symbol: str, params={}): if self.has['fetchLeverageTiers']: market = self.market(symbol) if not market['contract']: raise BadSymbol(self.id + ' fetchMarketLeverageTiers() supports contract markets only') tiers = await self.fetch_leverage_tiers([symbol]) return self.safe_value(tiers, symbol) else: raise NotSupported(self.id + ' fetchMarketLeverageTiers() is not supported yet') async def create_post_only_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}): if not self.has['createPostOnlyOrder']: raise NotSupported(self.id + ' createPostOnlyOrder() is not supported yet') query = self.extend(params, {'postOnly': True}) return await self.create_order(symbol, type, side, amount, price, query) async def create_post_only_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}): if not self.has['createPostOnlyOrderWs']: raise NotSupported(self.id + ' createPostOnlyOrderWs() is not supported yet') query = self.extend(params, {'postOnly': True}) return await self.create_order_ws(symbol, type, side, amount, price, query) async def create_reduce_only_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}): if not self.has['createReduceOnlyOrder']: raise NotSupported(self.id + ' createReduceOnlyOrder() is not supported yet') query = self.extend(params, {'reduceOnly': True}) return await self.create_order(symbol, type, side, amount, price, query) async def create_reduce_only_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}): if not self.has['createReduceOnlyOrderWs']: raise NotSupported(self.id + ' createReduceOnlyOrderWs() is not supported yet') query = self.extend(params, {'reduceOnly': True}) return await self.create_order_ws(symbol, type, side, amount, price, query) async def create_stop_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, triggerPrice: Num = None, params={}): if not self.has['createStopOrder']: raise NotSupported(self.id + ' createStopOrder() is not supported yet') if triggerPrice is None: raise ArgumentsRequired(self.id + ' create_stop_order() requires a stopPrice argument') query = self.extend(params, {'stopPrice': triggerPrice}) return await self.create_order(symbol, type, side, amount, price, query) async def create_stop_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, triggerPrice: Num = None, params={}): if not self.has['createStopOrderWs']: raise NotSupported(self.id + ' createStopOrderWs() is not supported yet') if triggerPrice is None: raise ArgumentsRequired(self.id + ' createStopOrderWs() requires a stopPrice argument') query = self.extend(params, {'stopPrice': triggerPrice}) return await self.create_order_ws(symbol, type, side, amount, price, query) async def create_stop_limit_order(self, symbol: str, side: OrderSide, amount: float, price: float, triggerPrice: float, params={}): if not self.has['createStopLimitOrder']: raise NotSupported(self.id + ' createStopLimitOrder() is not supported yet') query = self.extend(params, {'stopPrice': triggerPrice}) return await self.create_order(symbol, 'limit', side, amount, price, query) async def create_stop_limit_order_ws(self, symbol: str, side: OrderSide, amount: float, price: float, triggerPrice: float, params={}): if not self.has['createStopLimitOrderWs']: raise NotSupported(self.id + ' createStopLimitOrderWs() is not supported yet') query = self.extend(params, {'stopPrice': triggerPrice}) return await self.create_order_ws(symbol, 'limit', side, amount, price, query) async def create_stop_market_order(self, symbol: str, side: OrderSide, amount: float, triggerPrice: float, params={}): if not self.has['createStopMarketOrder']: raise NotSupported(self.id + ' createStopMarketOrder() is not supported yet') query = self.extend(params, {'stopPrice': triggerPrice}) return await self.create_order(symbol, 'market', side, amount, None, query) async def create_stop_market_order_ws(self, symbol: str, side: OrderSide, amount: float, triggerPrice: float, params={}): if not self.has['createStopMarketOrderWs']: raise NotSupported(self.id + ' createStopMarketOrderWs() is not supported yet') query = self.extend(params, {'stopPrice': triggerPrice}) return await self.create_order_ws(symbol, 'market', side, amount, None, query) async def fetch_last_prices(self, symbols: Strings = None, params={}): raise NotSupported(self.id + ' fetchLastPrices() is not supported yet') async def fetch_trading_fees(self, params={}): raise NotSupported(self.id + ' fetchTradingFees() is not supported yet') async def fetch_trading_fees_ws(self, params={}): raise NotSupported(self.id + ' fetchTradingFeesWs() is not supported yet') async def fetch_trading_fee(self, symbol: str, params={}): if not self.has['fetchTradingFees']: raise NotSupported(self.id + ' fetchTradingFee() is not supported yet') fees = await self.fetch_trading_fees(params) return self.safe_dict(fees, symbol) async def fetch_convert_currencies(self, params={}): raise NotSupported(self.id + ' fetchConvertCurrencies() is not supported yet') async def fetch_funding_rate(self, symbol: str, params={}): if self.has['fetchFundingRates']: await self.load_markets() market = self.market(symbol) symbol = market['symbol'] if not market['contract']: raise BadSymbol(self.id + ' fetchFundingRate() supports contract markets only') rates = await self.fetch_funding_rates([symbol], params) rate = self.safe_value(rates, symbol) if rate is None: raise NullResponse(self.id + ' fetchFundingRate() returned no data for ' + symbol) else: return rate else: raise NotSupported(self.id + ' fetchFundingRate() is not supported yet') async def fetch_funding_interval(self, symbol: str, params={}): if self.has['fetchFundingIntervals']: await self.load_markets() market = self.market(symbol) symbol = market['symbol'] if not market['contract']: raise BadSymbol(self.id + ' fetchFundingInterval() supports contract markets only') rates = await self.fetch_funding_intervals([symbol], params) rate = self.safe_value(rates, symbol) if rate is None: raise NullResponse(self.id + ' fetchFundingInterval() returned no data for ' + symbol) else: return rate else: raise NotSupported(self.id + ' fetchFundingInterval() is not supported yet') async def fetch_mark_ohlcv(self, symbol: str, timeframe: str = '1m', since: Int = None, limit: Int = None, params={}): """ fetches historical mark price candlestick data containing the open, high, low, and close price of a market :param str symbol: unified symbol of the market to fetch OHLCV data for :param str timeframe: the length of time each candle represents :param int [since]: timestamp in ms of the earliest candle to fetch :param int [limit]: the maximum amount of candles to fetch :param dict [params]: extra parameters specific to the exchange API endpoint :returns float[][]: A list of candles ordered, open, high, low, close, None """ if self.has['fetchMarkOHLCV']: request: dict = { 'price': 'mark', } return await self.fetch_ohlcv(symbol, timeframe, since, limit, self.extend(request, params)) else: raise NotSupported(self.id + ' fetchMarkOHLCV() is not supported yet') async def fetch_index_ohlcv(self, symbol: str, timeframe: str = '1m', since: Int = None, limit: Int = None, params={}): """ fetches historical index price candlestick data containing the open, high, low, and close price of a market :param str symbol: unified symbol of the market to fetch OHLCV data for :param str timeframe: the length of time each candle represents :param int [since]: timestamp in ms of the earliest candle to fetch :param int [limit]: the maximum amount of candles to fetch :param dict [params]: extra parameters specific to the exchange API endpoint @returns {} A list of candles ordered, open, high, low, close, None """ if self.has['fetchIndexOHLCV']: request: dict = { 'price': 'index', } return await self.fetch_ohlcv(symbol, timeframe, since, limit, self.extend(request, params)) else: raise NotSupported(self.id + ' fetchIndexOHLCV() is not supported yet') async def fetch_premium_index_ohlcv(self, symbol: str, timeframe: str = '1m', since: Int = None, limit: Int = None, params={}): """ fetches historical premium index price candlestick data containing the open, high, low, and close price of a market :param str symbol: unified symbol of the market to fetch OHLCV data for :param str timeframe: the length of time each candle represents :param int [since]: timestamp in ms of the earliest candle to fetch :param int [limit]: the maximum amount of candles to fetch :param dict [params]: extra parameters specific to the exchange API endpoint :returns float[][]: A list of candles ordered, open, high, low, close, None """ if self.has['fetchPremiumIndexOHLCV']: request: dict = { 'price': 'premiumIndex', } return await self.fetch_ohlcv(symbol, timeframe, since, limit, self.extend(request, params)) else: raise NotSupported(self.id + ' fetchPremiumIndexOHLCV() is not supported yet') async def fetch_transactions(self, code: Str = None, since: Int = None, limit: Int = None, params={}): """ @deprecated *DEPRECATED* use fetchDepositsWithdrawals instead :param str code: unified currency code for the currency of the deposit/withdrawals, default is None :param int [since]: timestamp in ms of the earliest deposit/withdrawal, default is None :param int [limit]: max number of deposit/withdrawals to return, default is None :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: a list of `transaction structures ` """ if self.has['fetchDepositsWithdrawals']: return await self.fetch_deposits_withdrawals(code, since, limit, params) else: raise NotSupported(self.id + ' fetchTransactions() is not supported yet') async def fetch_paginated_call_dynamic(self, method: str, symbol: Str = None, since: Int = None, limit: Int = None, params={}, maxEntriesPerRequest: Int = None, removeRepeated=True): maxCalls = None maxCalls, params = self.handle_option_and_params(params, method, 'paginationCalls', 10) maxRetries = None maxRetries, params = self.handle_option_and_params(params, method, 'maxRetries', 3) paginationDirection = None paginationDirection, params = self.handle_option_and_params(params, method, 'paginationDirection', 'backward') paginationTimestamp = None removeRepeatedOption = removeRepeated removeRepeatedOption, params = self.handle_option_and_params(params, method, 'removeRepeated', removeRepeated) calls = 0 result = [] errors = 0 until = self.safe_integer_n(params, ['until', 'untill', 'till']) # do not omit it from params here maxEntriesPerRequest, params = self.handle_max_entries_per_request_and_params(method, maxEntriesPerRequest, params) if (paginationDirection == 'forward'): if since is None: raise ArgumentsRequired(self.id + ' pagination requires a since argument when paginationDirection set to forward') paginationTimestamp = since while((calls < maxCalls)): calls += 1 try: if paginationDirection == 'backward': # do it backwards, starting from the last # UNTIL filtering is required in order to work if paginationTimestamp is not None: params['until'] = paginationTimestamp - 1 response = await getattr(self, method)(symbol, None, maxEntriesPerRequest, params) responseLength = len(response) if self.verbose: backwardMessage = 'Dynamic pagination call ' + self.number_to_string(calls) + ' method ' + method + ' response length ' + self.number_to_string(responseLength) if paginationTimestamp is not None: backwardMessage += ' timestamp ' + self.number_to_string(paginationTimestamp) self.log(backwardMessage) if responseLength == 0: break errors = 0 result = self.array_concat(result, response) firstElement = self.safe_value(response, 0) paginationTimestamp = self.safe_integer_2(firstElement, 'timestamp', 0) if (since is not None) and (paginationTimestamp <= since): break else: # do it forwards, starting from the since response = await getattr(self, method)(symbol, paginationTimestamp, maxEntriesPerRequest, params) responseLength = len(response) if self.verbose: forwardMessage = 'Dynamic pagination call ' + self.number_to_string(calls) + ' method ' + method + ' response length ' + self.number_to_string(responseLength) if paginationTimestamp is not None: forwardMessage += ' timestamp ' + self.number_to_string(paginationTimestamp) self.log(forwardMessage) if responseLength == 0: break errors = 0 result = self.array_concat(result, response) last = self.safe_value(response, responseLength - 1) paginationTimestamp = self.safe_integer(last, 'timestamp') + 1 if (until is not None) and (paginationTimestamp >= until): break except Exception as e: errors += 1 if errors > maxRetries: raise e uniqueResults = result if removeRepeatedOption: uniqueResults = self.remove_repeated_elements_from_array(result) key = 0 if (method == 'fetchOHLCV') else 'timestamp' return self.filter_by_since_limit(uniqueResults, since, limit, key) async def safe_deterministic_call(self, method: str, symbol: Str = None, since: Int = None, limit: Int = None, timeframe: Str = None, params={}): maxRetries = None maxRetries, params = self.handle_option_and_params(params, method, 'maxRetries', 3) errors = 0 while(errors <= maxRetries): try: if timeframe and method != 'fetchFundingRateHistory': return await getattr(self, method)(symbol, timeframe, since, limit, params) else: return await getattr(self, method)(symbol, since, limit, params) except Exception as e: if isinstance(e, RateLimitExceeded): raise e # if we are rate limited, we should not retry and fail fast errors += 1 if errors > maxRetries: raise e return [] async def fetch_paginated_call_deterministic(self, method: str, symbol: Str = None, since: Int = None, limit: Int = None, timeframe: Str = None, params={}, maxEntriesPerRequest=None): maxCalls = None maxCalls, params = self.handle_option_and_params(params, method, 'paginationCalls', 10) maxEntriesPerRequest, params = self.handle_max_entries_per_request_and_params(method, maxEntriesPerRequest, params) current = self.milliseconds() tasks = [] time = self.parse_timeframe(timeframe) * 1000 step = time * maxEntriesPerRequest currentSince = current - (maxCalls * step) - 1 if since is not None: currentSince = max(currentSince, since) else: currentSince = max(currentSince, 1241440531000) # avoid timestamps older than 2009 until = self.safe_integer_2(params, 'until', 'till') # do not omit it here if until is not None: requiredCalls = int(math.ceil((until - since)) / step) if requiredCalls > maxCalls: raise BadRequest(self.id + ' the number of required calls is greater than the max number of calls allowed, either increase the paginationCalls or decrease the since-until gap. Current paginationCalls limit is ' + str(maxCalls) + ' required calls is ' + str(requiredCalls)) for i in range(0, maxCalls): if (until is not None) and (currentSince >= until): break if currentSince >= current: break tasks.append(self.safe_deterministic_call(method, symbol, currentSince, maxEntriesPerRequest, timeframe, params)) currentSince = self.sum(currentSince, step) - 1 results = await asyncio.gather(*tasks) result = [] for i in range(0, len(results)): result = self.array_concat(result, results[i]) uniqueResults = self.remove_repeated_elements_from_array(result) key = 0 if (method == 'fetchOHLCV') else 'timestamp' return self.filter_by_since_limit(uniqueResults, since, limit, key) async def fetch_paginated_call_cursor(self, method: str, symbol: Str = None, since=None, limit=None, params={}, cursorReceived=None, cursorSent=None, cursorIncrement=None, maxEntriesPerRequest=None): maxCalls = None maxCalls, params = self.handle_option_and_params(params, method, 'paginationCalls', 10) maxRetries = None maxRetries, params = self.handle_option_and_params(params, method, 'maxRetries', 3) maxEntriesPerRequest, params = self.handle_max_entries_per_request_and_params(method, maxEntriesPerRequest, params) cursorValue = None i = 0 errors = 0 result = [] timeframe = self.safe_string(params, 'timeframe') params = self.omit(params, 'timeframe') # reading the timeframe from the method arguments to avoid changing the signature while(i < maxCalls): try: if cursorValue is not None: if cursorIncrement is not None: cursorValue = self.parse_to_int(cursorValue) + cursorIncrement params[cursorSent] = cursorValue response = None if method == 'fetchAccounts': response = await getattr(self, method)(params) elif method == 'getLeverageTiersPaginated' or method == 'fetchPositions': response = await getattr(self, method)(symbol, params) elif method == 'fetchOpenInterestHistory': response = await getattr(self, method)(symbol, timeframe, since, maxEntriesPerRequest, params) else: response = await getattr(self, method)(symbol, since, maxEntriesPerRequest, params) errors = 0 responseLength = len(response) if self.verbose: cursorString = '' if (cursorValue is None) else cursorValue iteration = (i + 1) cursorMessage = 'Cursor pagination call ' + str(iteration) + ' method ' + method + ' response length ' + str(responseLength) + ' cursor ' + cursorString self.log(cursorMessage) if responseLength == 0: break result = self.array_concat(result, response) last = self.safe_dict(response, responseLength - 1) # cursorValue = self.safe_value(last['info'], cursorReceived) cursorValue = None # search for the cursor for j in range(0, responseLength): index = responseLength - j - 1 entry = self.safe_dict(response, index) info = self.safe_dict(entry, 'info') cursor = self.safe_value(info, cursorReceived) if cursor is not None: cursorValue = cursor break if cursorValue is None: break lastTimestamp = self.safe_integer(last, 'timestamp') if lastTimestamp is not None and lastTimestamp < since: break except Exception as e: errors += 1 if errors > maxRetries: raise e i += 1 sorted = self.sort_cursor_paginated_result(result) key = 0 if (method == 'fetchOHLCV') else 'timestamp' return self.filter_by_since_limit(sorted, since, limit, key) async def fetch_paginated_call_incremental(self, method: str, symbol: Str = None, since=None, limit=None, params={}, pageKey=None, maxEntriesPerRequest=None): maxCalls = None maxCalls, params = self.handle_option_and_params(params, method, 'paginationCalls', 10) maxRetries = None maxRetries, params = self.handle_option_and_params(params, method, 'maxRetries', 3) maxEntriesPerRequest, params = self.handle_max_entries_per_request_and_params(method, maxEntriesPerRequest, params) i = 0 errors = 0 result = [] while(i < maxCalls): try: params[pageKey] = i + 1 response = await getattr(self, method)(symbol, since, maxEntriesPerRequest, params) errors = 0 responseLength = len(response) if self.verbose: iteration = (i + str(1)) incrementalMessage = 'Incremental pagination call ' + iteration + ' method ' + method + ' response length ' + str(responseLength) self.log(incrementalMessage) if responseLength == 0: break result = self.array_concat(result, response) except Exception as e: errors += 1 if errors > maxRetries: raise e i += 1 sorted = self.sort_cursor_paginated_result(result) key = 0 if (method == 'fetchOHLCV') else 'timestamp' return self.filter_by_since_limit(sorted, since, limit, key) async def fetch_position_history(self, symbol: str, since: Int = None, limit: Int = None, params={}): """ fetches the history of margin added or reduced from contract isolated positions :param str [symbol]: unified market symbol :param int [since]: timestamp in ms of the position :param int [limit]: the maximum amount of candles to fetch, default=1000 :param dict params: extra parameters specific to the exchange api endpoint :returns dict[]: a list of `position structures ` """ if self.has['fetchPositionsHistory']: positions = await self.fetch_positions_history([symbol], since, limit, params) return positions else: raise NotSupported(self.id + ' fetchPositionHistory() is not supported yet') async def fetch_positions_history(self, symbols: Strings = None, since: Int = None, limit: Int = None, params={}): """ fetches the history of margin added or reduced from contract isolated positions :param str [symbol]: unified market symbol :param int [since]: timestamp in ms of the position :param int [limit]: the maximum amount of candles to fetch, default=1000 :param dict params: extra parameters specific to the exchange api endpoint :returns dict[]: a list of `position structures ` """ raise NotSupported(self.id + ' fetchPositionsHistory() is not supported yet') async def fetch_transfer(self, id: str, code: Str = None, params={}): """ fetches a transfer :param str id: transfer id :param [str] code: unified currency code :param dict params: extra parameters specific to the exchange api endpoint :returns dict: a `transfer structure ` """ raise NotSupported(self.id + ' fetchTransfer() is not supported yet') async def fetch_transfers(self, code: Str = None, since: Int = None, limit: Int = None, params={}): """ fetches a transfer :param str id: transfer id :param int [since]: timestamp in ms of the earliest transfer to fetch :param int [limit]: the maximum amount of transfers to fetch :param dict params: extra parameters specific to the exchange api endpoint :returns dict: a `transfer structure ` """ raise NotSupported(self.id + ' fetchTransfers() is not supported yet') async def un_watch_ohlcv(self, symbol: str, timeframe: str = '1m', params={}): """ watches historical candlestick data containing the open, high, low, and close price, and the volume of a market :param str symbol: unified symbol of the market to fetch OHLCV data for :param str timeframe: the length of time each candle represents :param dict [params]: extra parameters specific to the exchange API endpoint :returns int[][]: A list of candles ordered, open, high, low, close, volume """ raise NotSupported(self.id + ' unWatchOHLCV() is not supported yet') async def watch_mark_price(self, symbol: str, params={}): """ watches a mark price for a specific market :param str symbol: unified symbol of the market to fetch the ticker for :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: a `ticker structure ` """ raise NotSupported(self.id + ' watchMarkPrice() is not supported yet') async def watch_mark_prices(self, symbols: Strings = None, params={}): """ watches the mark price for all markets :param str[] symbols: unified symbol of the market to fetch the ticker for :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: a `ticker structure ` """ raise NotSupported(self.id + ' watchMarkPrices() is not supported yet') async def withdraw_ws(self, code: str, amount: float, address: str, tag: Str = None, params={}): """ make a withdrawal :param str code: unified currency code :param float amount: the amount to withdraw :param str address: the address to withdraw to :param str tag: :param dict [params]: extra parameters specific to the bitvavo api endpoint :returns dict: a `transaction structure ` """ raise NotSupported(self.id + ' withdrawWs() is not supported yet') async def un_watch_my_trades(self, symbol: Str = None, params={}): """ unWatches information on multiple trades made by the user :param str symbol: unified market symbol of the market orders were made in :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict[]: a list of `order structures ` """ raise NotSupported(self.id + ' unWatchMyTrades() is not supported yet') async def create_orders_ws(self, orders: List[OrderRequest], params={}): """ create a list of trade orders :param Array orders: list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: an `order structure ` """ raise NotSupported(self.id + ' createOrdersWs() is not supported yet') async def fetch_orders_by_status_ws(self, status: str, symbol: Str = None, since: Int = None, limit: Int = None, params={}): """ watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data :param str symbol: unified symbol of the market to fetch the order book for :param int [limit]: the maximum amount of order book entries to return :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: A dictionary of `order book structures ` indexed by market symbols """ raise NotSupported(self.id + ' fetchOrdersByStatusWs() is not supported yet') async def un_watch_bids_asks(self, symbols: Strings = None, params={}): """ unWatches best bid & ask for symbols :param str[] symbols: unified symbol of the market to fetch the ticker for :param dict [params]: extra parameters specific to the exchange API endpoint :returns dict: a `ticker structure ` """ raise NotSupported(self.id + ' unWatchBidsAsks() is not supported yet')