def fetch_ticker(self, symbol, params={}): if symbol != 'BTC/USD': raise ExchangeError(self.id + ' ' + self.version + " fetchTicker doesn't support " + symbol + ', use it for BTC/USD only') self.load_markets() ticker = self.publicGetTicker(params) timestamp = int(ticker['timestamp']) * 1000 vwap = self.safe_float(ticker, 'vwap') baseVolume = self.safe_float(ticker, 'volume') quoteVolume = None if baseVolume is not None and vwap is not None: quoteVolume = baseVolume * vwap last = self.safe_float(ticker, 'last') return { 'symbol': symbol, 'timestamp': timestamp, 'datetime': self.iso8601(timestamp), 'high': self.safe_float(ticker, 'high'), 'low': self.safe_float(ticker, 'low'), 'bid': self.safe_float(ticker, 'bid'), 'bidVolume': None, 'ask': self.safe_float(ticker, 'ask'), 'askVolume': None, 'vwap': vwap, 'open': self.safe_float(ticker, 'open'), 'close': last, 'last': last, 'previousClose': None, 'change': None, 'percentage': None, 'average': None, 'baseVolume': baseVolume, 'quoteVolume': quoteVolume, 'info': ticker, }
async def create_order(self, symbol, type, side, amount, price=None, params={}): await self.load_markets() market = self.market(symbol) method = 'privatePost' order = { 'symbol': market['id'], 'type': side, } if market['future']: method += 'Future' order = self.extend(order, { 'contract_type': 'this_week', # next_week, quarter 'match_price': 0, # match best counter party price? 0 or 1, ignores price if 1 'lever_rate': 10, # leverage rate value: 10 or 20(10 by default) 'price': price, 'amount': amount, }) else: if type == 'limit': order['price'] = price order['amount'] = amount else: order['type'] += '_market' if side == 'buy': order['price'] = self.safe_float(params, 'cost') if not order['price']: raise ExchangeError(self.id + ' market buy orders require an additional cost parameter, cost = price * amount') else: order['amount'] = amount params = self.omit(params, 'cost') method += 'Trade' response = await getattr(self, method)(self.extend(order, params)) return { 'info': response, 'id': str(response['order_id']), }
async def fetch_order(self, id, symbol=None, params={}): if not symbol: raise ExchangeError(self.id + ' fetchOrder requires a symbol parameter') await self.load_markets() market = self.market(symbol) method = 'privatePost' request = { 'order_id': id, 'symbol': market['id'], # 'status': 0, # 0 for unfilled orders, 1 for filled orders # 'current_page': 1, # current page number # 'page_length': 200, # number of orders returned per page, maximum 200 } if market['future']: method += 'Future' request['contract_type'] = 'this_week' # next_week, quarter method += 'OrderInfo' response = await getattr(self, method)(self.extend(request, params)) ordersField = self.get_orders_field() numOrders = len(response[ordersField]) if numOrders > 0: return self.parse_order(response[ordersField][0]) raise OrderNotFound(self.id + ' order ' + id + ' not found')
def withdraw(self, code, amount, address, tag=None, params={}): self.check_address(address) self.load_markets() currency = self.currency(code) request = { 'currency': currency['id'], 'amount': amount, } method = 'privatePostWithdrawals' if 'payment_method_id' in params: method += 'PaymentMethod' elif 'coinbase_account_id' in params: method += 'CoinbaseAccount' else: method += 'Crypto' request['crypto_address'] = address response = getattr(self, method)(self.extend(request, params)) if not response: raise ExchangeError(self.id + ' withdraw() error: ' + self.json(response)) return { 'info': response, 'id': response['id'], }
def fetch_transactions(self, code=None, since=None, limit=None, params={}): self.load_markets() self.load_accounts() currency = None id = self.safe_string(params, 'id') # account id if id is None: if code is not None: currency = self.currency(code) accountsByCurrencyCode = self.index_by(self.accounts, 'currency') account = self.safe_value(accountsByCurrencyCode, code) if account is None: raise ExchangeError( self.id + ' fetchTransactions() could not find account id for ' + code) id = account['id'] request = {} if id is not None: request['id'] = id if limit is not None: request['limit'] = limit response = None if id is None: response = self.privateGetTransfers(self.extend(request, params)) for i in range(0, len(response)): account_id = self.safe_string(response[i], 'account_id') account = self.safe_value(self.accountsById, account_id) code = self.safe_string(account, 'currency') response[i]['currency'] = code else: response = self.privateGetAccountsIdTransfers( self.extend(request, params)) for i in range(0, len(response)): response[i]['currency'] = code return self.parse_transactions(response, currency, since, limit)
async def withdraw(self, code, amount, address, tag=None, params={}): self.check_address(address) if self.is_fiat(code): raise NotSupported(self.id + ' fiat withdraw() for ' + code + ' is not implemented yet') name = self.get_currency_name(code) request = { 'amount': amount, 'address': address, } v1 = (code == 'BTC') method = 'v1' if v1 else 'private' # v1 or v2 method += 'Post' + self.capitalize(name) + 'Withdrawal' query = params if code == 'XRP': if tag is not None: request['destination_tag'] = tag query = self.omit(params, 'destination_tag') else: raise ExchangeError(self.id + ' withdraw() requires a destination_tag param for ' + code) response = await getattr(self, method)(self.extend(request, query)) return { 'info': response, 'id': response['id'], }
async def request(self, path, api='public', method='GET', params={}, headers=None, body=None): response = await self.fetch2(path, api, method, params, headers, body) if not isinstance(response, basestring): if 'error' in response: numErrors = len(response['error']) if numErrors: for i in range(0, len(response['error'])): if response['error'][i] == 'EService:Unavailable': raise ExchangeNotAvailable(self.id + ' ' + self.json(response)) if response['error'][i] == 'EDatabase:Internal error': raise ExchangeNotAvailable(self.id + ' ' + self.json(response)) if response['error'][i] == 'EService:Busy': raise DDoSProtection(self.id + ' ' + self.json(response)) raise ExchangeError(self.id + ' ' + self.json(response)) return response
def fetch_my_trades(self, symbol=None, since=None, limit=50, params={}): """ 查询用户某个市场的成交记录 """ if symbol is None: raise ExchangeError(self.id + 'fetch_my_trades requires a symbol parameter') self.load_markets() market = self.market(symbol.upper()) request = { 'marketId': market['id'], 'pageNum': 1, # default pageNum is 1 'pageSize': limit, # default pageSize is 20 } if since: request['startTime'] = since response = self.private_get_exchange_entrust_controller_website_entrustcontroller_gettransactionpage( self.extend(request, params)) entrust_list = response['datas']['list'] print(entrust_list) return self._parse_my_trades(entrust_list, market, since, limit)
def create_order(self, symbol, type, side, amount, price=None, params={}): self.load_markets() market = self.market(symbol) # check if amount can be evenly divided into lots # they want integer quantity in lot units quantity = float(amount) / market['lot'] wholeLots = int(round(quantity)) difference = quantity - wholeLots if abs(difference) > market['step']: raise ExchangeError(self.id + ' order amount should be evenly divisible by lot unit size of ' + str(market['lot'])) clientOrderId = self.milliseconds() order = { 'clientOrderId': str(clientOrderId), 'symbol': market['id'], 'side': side, 'quantity': str(wholeLots), # quantity in integer lot units 'type': type, } if type == 'limit': order['price'] = self.price_to_precision(symbol, price) else: order['timeInForce'] = 'FOK' response = self.tradingPostNewOrder(self.extend(order, params)) return self.parse_order(response['ExecutionReport'], market)
def fetch_orders(self, symbol=None, since=None, limit=None, params={}): if not symbol: raise ExchangeError(self.id + ' fetchOrders requires a symbol param') self.load_markets() market = self.market(symbol) response = self.privatePostGetOpenOrders({ # 'Market': market['id'], 'TradePairId': market['id'], # Cryptopia identifier(not required if 'Market' supplied) # 'Count': 100, # default = 100 }, params) orders = [] for i in range(0, len(response['Data'])): orders.append(self.extend(response['Data'][i], {'status': 'open'})) openOrders = self.parse_orders(orders, market) for j in range(0, len(openOrders)): self.orders[openOrders[j]['id']] = openOrders[j] openOrdersIndexedById = self.index_by(openOrders, 'id') cachedOrderIds = list(self.orders.keys()) result = [] for k in range(0, len(cachedOrderIds)): id = cachedOrderIds[k] if id in openOrdersIndexedById: self.orders[id] = self.extend(self.orders[id], openOrdersIndexedById[id]) else: order = self.orders[id] if order['status'] == 'open': self.orders[id] = self.extend(order, { 'status': 'closed', 'cost': order['amount'] * order['price'], 'filled': order['amount'], 'remaining': 0.0, }) order = self.orders[id] if order['symbol'] == symbol: result.append(order) return self.filter_by_since_limit(result, since, limit)
def fetch_orders(self, symbol=None, since=None, limit=50, params={}): if symbol is None: raise ExchangeError(self.id + 'fetch_orders requires a symbol parameter') self.load_markets() market = self.market(symbol.upper()) request = { 'marketId': market['id'], 'pageIndex': 1, # default pageIndex is 1 'pageSize': limit, # default pageSize is 50 } if since: request['startDateTime'] = since response = self.private_get_exchange_entrust_controller_website_entrustcontroller_getuserentrustlist( self.extend(request, params)) entrust_list = response['datas']['entrustList'] if not entrust_list: return [] return self.parse_orders(entrust_list, market, since, limit)
async def fetch_balance(self, params={}): await self.load_markets() accountName = self.safe_string(params, 'account', 'primary') params = self.omit(params, 'account') request = { 'account': accountName, } response = await self.privateGetAccounts(self.extend(request, params)) # # { # "primary": [ # { # "currency":"ETH", # "balance":0.009, # "available":0.009, # "balance_local":30.82869, # "available_local":30.82869, # "rate":3425.41 # }, # ... # ] # } # balances = self.safe_value(response, accountName) if balances is None: raise ExchangeError(self.id + ' fetchBalance() could not find the "' + accountName + '" account') result = {'info': response} for i in range(0, len(balances)): entry = balances[i] currencyId = self.safe_string(entry, 'currency') code = self.safe_currency_code(currencyId) account = self.account() account['free'] = self.safe_string(entry, 'available') account['total'] = self.safe_string(entry, 'balance') result[code] = account return self.parse_balance(result)
def fetch_transactions(self, code=None, since=None, limit=None, params={}): self.load_markets() if code is None: raise ArgumentsRequired(self.id + ' fetchTransactions() requires a currency code argument') currency = self.currency(code) accountId = None accounts = self.privateGetAccounts() for i in range(0, len(accounts)): account = accounts[i] # todo: use unified common currencies below if account['currency'] == currency['id']: accountId = account['id'] break if accountId is None: raise ExchangeError(self.id + ' fetchTransactions() could not find account id for ' + code) request = { 'id': accountId, } if limit is not None: request['limit'] = limit response = self.privateGetAccountsIdTransfers(self.extend(request, params)) for i in range(0, len(response)): response[i]['currency'] = code return self.parseTransactions(response)
def create_order(self, symbol, type, side, amount, price=None, params={}): if type != 'limit': raise ExchangeError(self.id + ' createOrder() allows limit orders only') self.load_markets() market = self.market(symbol) request = { 'pair': market['id'], 'type': side, 'price': price, } currency = market['baseId'] if side == 'buy': request[market['quoteId']] = amount * price else: request[market['baseId']] = amount request[currency] = amount result = self.privatePostTrade(self.extend(request, params)) data = self.safe_value(result, 'return', {}) id = self.safe_string(data, 'order_id') return { 'info': result, 'id': id, }
def handle_rest_response(self, response, url, method='GET', headers=None, body=None): try: if self.parseJsonResponse: self.last_json_response = json.loads(response) if len(response) > 1 else None return self.last_json_response else: return response except Exception as e: ddos_protection = re.search('(cloudflare|incapsula)', response, flags=re.IGNORECASE) exchange_not_available = re.search('(offline|busy|retry|wait|unavailable|maintain|maintenance|maintenancing)', response, flags=re.IGNORECASE) if ddos_protection: raise DDoSProtection(' '.join([self.id, method, url, response])) if exchange_not_available: message = 'exchange downtime, exchange closed for maintenance or offline, DDoS protection or rate-limiting in effect' raise ExchangeNotAvailable(' '.join([ self.id, method, url, response, message, ])) if isinstance(e, ValueError): raise ExchangeError(' '.join([self.id, method, url, response, str(e)])) raise
def withdraw(self, code, amount, address, tag=None, params={}): tag, params = self.handle_withdraw_tag_and_params(tag, params) self.check_address(address) self.load_markets() currency = self.currency(code) if code == 'JPY': raise ExchangeError(self.id + ' withdraw() does not allow ' + code + ' withdrawals') request = { 'currency': currency['id'], 'amount': amount, 'address': address, # 'message': 'Hi!', # XEM and others # 'opt_fee': 0.003, # BTC and MONA only } if tag is not None: request['message'] = tag result = self.privatePostWithdraw(self.extend(request, params)) # # { # "success": 1, # "return": { # "id": 23634, # "fee": 0.001, # "txid":, # "funds": { # "jpy": 15320, # "btc": 1.392, # "xem": 100.2, # "mona": 2600 # } # } # } # returnData = self.safe_value(result, 'return') return self.parse_transaction(returnData, currency)
async def fetch_my_trades(self, symbol=None, since=None, limit=25, params={}): await self.load_markets() market = self.market(symbol) # the don't support fetching trades starting from a date yet # use the `marker` extra param for that # self is not a typo, the variable name is 'marker'(don't confuse with 'market') markerInParams = ('marker' in params) # warn the user with an exception if the user wants to filter # starting from since timestamp, but does not set the trade id with an extra 'marker' param if (since is not None) and not markerInParams: raise ExchangeError(self.id + ' fetchMyTrades does not support fetching trades starting from a timestamp with the `since` argument, use the `marker` extra param to filter starting from an integer trade id') # convert it to an integer unconditionally if markerInParams: params = self.extend(params, { 'marker': int(params['marker']), }) request = { 'book': market['id'], 'limit': limit, # default = 25, max = 100 # 'sort': 'desc', # default = desc # 'marker': id, # integer id to start from } response = await self.privateGetUserTrades(self.extend(request, params)) return self.parse_trades(response['payload'], market, since, limit)
def withdraw(self, code, amount, address, tag=None, params={}): self.check_address(address) self.load_markets() methods = { 'BTC': 'Bitcoin', 'ETH': 'Ether', 'XRP': 'Ripple', 'BCH': 'Bcash', 'LTC': 'Litecoin', } method = methods[code] if (code in list(methods.keys())) else None if method is None: raise ExchangeError(self.id + ' not valid withdraw coin: ' + code) request = { 'amount': amount, 'address': address, 'destination_tag': tag, } classMethod = 'privatePost' + method + 'Withdrawal' response = getattr(self, classMethod)(self.extend(request, params)) return { 'info': response, 'id': self.safe_string(response['payload'], 'wid'), }
def create_order(self, symbol, type, side, amount, price=None, params={}): if type != 'limit': raise ExchangeError(self.id + ' allows limit orders only') self.load_markets() market = self.market(symbol) base = market['base'] request = { 'symbol': market['id'], 'type': side.upper(), 'price': self.price_to_precision(symbol, price), 'amount': self.truncate(amount, self.currencies[base]['precision']), } price = float(price) amount = float(amount) cost = price * amount response = self.privatePostOrder(self.extend(request, params)) orderId = self.safe_string(response['data'], 'orderOid') order = { 'info': response, 'id': orderId, 'timestamp': None, 'datetime': None, 'type': type, 'side': side, 'amount': amount, 'filled': None, 'remaining': None, 'price': price, 'cost': cost, 'status': 'open', 'fee': None, 'trades': None, } self.orders[orderId] = order return order
async def fetch_tickers(self, symbols=None, params={}): await self.load_markets() ids = None if not symbols: numIds = len(self.ids) if numIds > 256: raise ExchangeError( self.id + ' fetchTickers() requires symbols argument') ids = self.ids else: ids = self.market_ids(symbols) tickers = await self.publicGetTickerPair( self.extend({ 'pair': '-'.join(ids), }, params)) result = {} keys = list(tickers.keys()) for k in range(0, len(keys)): id = keys[k] ticker = tickers[id] market = self.markets_by_id[id] symbol = market['symbol'] result[symbol] = self.parse_ticker(ticker, market) return result
def withdraw(self, code, amount, address, tag=None, params={}): self.check_address(address) self.load_markets() currency = self.currency(code) request = { 'units': amount, 'address': address, 'currency': currency['id'], } if currency == 'XRP' or currency == 'XMR': destination = self.safe_string(params, 'destination') if (tag is None) and (destination is None): raise ExchangeError( self.id + ' ' + code + ' withdraw() requires a tag argument or an extra destination param' ) elif tag is not None: request['destination'] = tag response = self.privatePostTradeBtcWithdrawal( self.extend(request, params)) return { 'info': response, 'id': None, }
async def create_order(self, symbol, type, side, amount, price=None, params={}): if type != 'limit': raise ExchangeError(self.id + ' allows limit orders only') await self.load_markets() market = self.market(symbol) base = market['base'] order = { 'symbol': market['id'], 'type': side.upper(), 'price': self.price_to_precision(symbol, price), 'amount': self.truncate(amount, self.currencies[base]['precision']), } response = await self.privatePostOrder(self.extend(order, params)) return { 'info': response, 'id': self.safe_string(response['data'], 'orderOid'), }
def withdraw(self, code, amount, address, tag=None, params={}): self.check_address(address) self.load_markets() currency = self.currency(code) id = self.safe_string(params, 'id') if id is None: raise ExchangeError( self.id + ' withdraw() requires an extra `id` param(withdraw account id according to withdraws/bind_account_list endpoint' ) request = { 'id': id, 'currency_type': 'coin', # or 'cash' 'currency': currency.lower(), 'body': amount, # 'address': address, # they don't allow withdrawing to direct addresses? } if tag is not None: request['memo'] = tag result = self.privatePostWithdrawsApply(self.extend(request, params)) return { 'info': result, 'id': None, }
async def create_order(self, symbol, type, side, amount, price=None, params={}): await self.load_markets() if type == 'market': raise ExchangeError(self.id + ' allows limit orders only') nonce = self.nonce() request = { 'client_order_id': str(nonce), 'symbol': self.market_id(symbol), 'amount': str(amount), 'price': str(price), 'side': side, 'type': 'exchange limit', # gemini allows limit orders only } response = await self.privatePostOrderNew(self.extend(request, params)) return { 'info': response, 'id': response['order_id'], }
def create_order(self, symbol, type, side, amount, price=None, params={}): if type != 'limit': raise ExchangeError(self.id + ' allows limit orders only') self.load_markets() market = self.market(symbol) method = 'marketGet' + self.capitalize(side) + type order = { 'market': market['id'], 'quantity': self.amount_to_precision(symbol, amount), 'rate': self.price_to_precision(symbol, price), } # if type == 'limit': # order['rate'] = self.price_to_precision(symbol, price) response = getattr(self, method)(self.extend(order, params)) orderIdField = self.get_order_id_field() result = { 'info': response, 'id': response['result'][orderIdField], 'symbol': symbol, 'type': type, 'side': side, 'status': 'open', } return result
async def create_order(self, symbol, type, side, amount, price=None, params={}): if type == 'market': raise ExchangeError(self.id + ' allows limit orders only') await self.load_markets() market = self.market(symbol) request = { 'pair': market['id'], 'type': side, 'amount': self.amount_to_precision(symbol, amount), 'rate': self.price_to_precision(symbol, price), } response = await self.privatePostTrade(self.extend(request, params)) id = self.safe_string(response['return'], self.get_order_id_key()) if not id: id = self.safe_string(response['return'], 'init_order_id') timestamp = self.milliseconds() price = float(price) amount = float(amount) order = { 'id': id, 'timestamp': timestamp, 'datetime': self.iso8601(timestamp), 'status': 'open', 'symbol': symbol, 'type': type, 'side': side, 'price': price, 'cost': price * amount, 'amount': amount, 'remaining': amount, 'filled': 0.0, 'fee': None, # 'trades': self.parse_trades(order['trades'], market), } self.orders[id] = order return self.extend({'info': response}, order)
async def fetch_orders(self, symbol=None, since=None, limit=50, params={}): if symbol is None: raise ExchangeError(self.id + 'fetchOrders requires a symbol parameter') await self.load_markets() market = self.market(symbol) request = { 'currency': market['id'], 'pageIndex': 1, # default pageIndex is 1 'pageSize': limit, # default pageSize is 50 } method = 'privateGetGetOrdersIgnoreTradeType' # tradeType 交易类型1/0[buy/sell] if 'tradeType' in params: method = 'privateGetGetOrdersNew' response = None try: response = await getattr(self, method)(self.extend(request, params)) except Exception as e: if isinstance(e, OrderNotFound): return [] raise e return self.parse_orders(response, market, since, limit)
def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody): if response is None: return # EndPoints Result common pattern # { # "code" : "code_id", # "msg" : "", # "data" : {} # } errorCode = self.safe_string(response, 'code') if errorCode == '0': # success return errorMessages = self.errorMessages message = None message = self.safe_string(response, 'msg') if message is None: message = self.safe_string(errorMessages, errorCode, 'Unknown Error') feedback = self.id + ' ' + message self.throw_exactly_matched_exception(self.exceptions, errorCode, feedback) raise ExchangeError(feedback)
async def fetch_balance(self, params={}): await self.load_markets() balances = await self.privatePostListBalances() if not balances: raise ExchangeError(self.id + ' fetchBalance got an unrecognized response') result = {'info': balances} for b in range(0, len(balances)): balance = balances[b] currencyId = balance['Currency'] uppercase = currencyId.upper() currency = self.currencies_by_id[uppercase] code = currency['code'] free = float(balance['Available']) deposited = float(balance['Deposited']) unconfirmed = float(balance['Unconfirmed']) total = self.sum(deposited, unconfirmed) used = total - free account = { 'free': free, 'used': used, 'total': total, } result[code] = account return self.parse_balance(result)
def handle_errors(self, httpCode, reason, url, method, headers, body): if not isinstance(body, basestring): return # fallback to default error handler if len(body) < 2: return # fallback to default error handler if (body[0] == '{') or (body[0] == '['): response = json.loads(body) # # {"errors":{"detail":"Internal server error"}} # error = self.safe_value(response, 'error') errors = self.safe_value(response, 'errors') data = self.safe_value(response, 'data') if error is not None or errors is not None or data is None: feedback = self.id + ' ' + self.json(response) code = self.safe_integer(error, 'code') exceptions = self.exceptions['codes'] if errors is not None: code = self.safe_string(errors, 'detail') exceptions = self.exceptions['detail'] if code in exceptions: raise exceptions[code](feedback) else: raise ExchangeError(feedback)