def fetch_ticker(self, symbol, params={}): self.load_markets() market = self.market(symbol) method = 'publicGet' request = { 'symbol': market['id'], } if market['future']: method += 'Future' if not params.get('contract_type'): raise ExchangeError( self.id + ' futureTicker requires a contract_type parameter in params' ) request['contract_type'] = params.get('contract_type') method += 'Ticker' response = getattr(self, method)(self.extend(request, params)) ticker = self.safe_value(response, 'ticker') if ticker is None: raise ExchangeError(self.id + ' fetchTicker returned an empty response: ' + self.json(response)) timestamp = self.safe_integer(response, 'date') if timestamp is not None: timestamp *= 1000 ticker = self.extend(ticker, {'timestamp': timestamp}) return self.parse_ticker(ticker, market)
def handle_errors(self, code, reason, url, method, headers, body): if body[0] == '{': response = json.loads(body) # {success: False, message: "message"} success = self.safe_value(response, 'success') if success is None: raise ExchangeError(self.id + ': malformed response: ' + self.json(response)) if isinstance(success, basestring): # bleutrade uses string instead of boolean success = True if (success == 'true') else False if not success: message = self.safe_string(response, 'message') feedback = self.id + ' ' + self.json(response) exceptions = self.exceptions if message in exceptions: raise exceptions[message](feedback) if message == 'APIKEY_INVALID': if self.hasAlreadyAuthenticatedSuccessfully: raise DDoSProtection(feedback) else: raise AuthenticationError(feedback) if message == 'DUST_TRADE_DISALLOWED_MIN_VALUE_50K_SAT': raise InvalidOrder( self.id + ' order cost should be over 50k satoshi ' + self.json(response)) raise ExchangeError(self.id + ' ' + self.json(response))
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) if 'success' in response: # # {"success":false,"error":{"code":104,"message":"Cannot perform request - nonce must be higher than 1520307203724237"}} # success = self.safe_value(response, 'success', False) if isinstance(success, basestring): if (success == 'true') or (success == '1'): success = True else: success = False if not success: feedback = self.id + ' ' + self.json(response) error = self.safe_value(response, 'error') if error is None: raise ExchangeError(feedback) code = self.safe_string(error, 'code') exceptions = self.exceptions if code in exceptions: raise exceptions[code](feedback) else: raise ExchangeError(feedback)
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: message = self.id + ' ' + self.json(response) for i in range(0, len(response['error'])): if response['error'][ i] == 'EFunding:Unknown withdraw key': raise ExchangeError(message) if response['error'][i] == 'EService:Unavailable': raise ExchangeNotAvailable(message) if response['error'][i] == 'EDatabase:Internal error': raise ExchangeNotAvailable(message) if response['error'][i] == 'EService:Busy': raise DDoSProtection(message) raise ExchangeError(message) return response
async def create_order(self, symbol, type, side, amount, price=None, params={}): if type == 'market': raise ExchangeError(self.id + ' allows limit orders only') walletIdInParams = ('walletId' in list(params.keys())) if not walletIdInParams: raise ExchangeError(self.id + ' createOrder requires a walletId parameter') amount = str(amount) price = str(price) market = self.market(symbol) order = { 'side': side, 'type': type, 'currency': market['base'], 'amount': amount, 'display': amount, 'price': price, 'instrument': market['id'], } response = await self.privatePostTradeAdd(self.extend(order, params)) return { 'info': response, 'id': response['id'], }
async def fetch_order(self, id, symbol=None, params={}): if symbol is None: raise ExchangeError(self.id + ' fetchOrder requires a symbol argument') orderType = self.safe_value(params, 'type') if orderType is None: raise ExchangeError( self.id + ' fetchOrder requires a type parameter("BUY" or "SELL")') await self.load_markets() market = self.market(symbol) request = { 'symbol': market['id'], 'type': orderType, 'orderOid': id, } response = await self.privateGetOrderDetail( self.extend(request, params)) if not response['data']: raise OrderNotFound(self.id + ' ' + self.json(response)) # # the caching part to be removed # # order = self.parse_order(response['data'], market) # orderId = order['id'] # if orderId in self.orders: # order['status'] = self.orders[orderId]['status'] # self.orders[orderId] = order # return self.parse_order(response['data'], market)
def handle_errors(self, code, reason, url, method, headers, body): if (code == 418) or (code == 429): raise DDoSProtection(self.id + ' ' + str(code) + ' ' + reason + ' ' + body) # error response in a form: {"code": -1013, "msg": "Invalid quantity."} # following block cointains legacy checks against message patterns in "msg" property # will switch "code" checks eventually, when we know all of them if code >= 400: if body.find('Price * QTY is zero or less') >= 0: raise InvalidOrder(self.id + ' order cost = amount * price is zero or less ' + body) if body.find('LOT_SIZE') >= 0: raise InvalidOrder(self.id + ' order amount should be evenly divisible by lot size, use self.amount_to_lots(symbol, amount) ' + body) if body.find('PRICE_FILTER') >= 0: raise InvalidOrder(self.id + ' order price exceeds allowed price precision or invalid, use self.price_to_precision(symbol, amount) ' + body) if len(body) > 0: if body[0] == '{': response = json.loads(body) # check success value for wapi endpoints # response in format {'msg': 'The coin does not exist.', 'success': True/false} success = self.safe_value(response, 'success', True) if not success: if 'msg' in response: try: response = json.loads(response['msg']) except Exception as e: response = {} # checks against error codes error = self.safe_string(response, 'code') if error is not None: exceptions = self.exceptions if error in exceptions: raise exceptions[error](self.id + ' ' + body) else: raise ExchangeError(self.id + ': unknown error code: ' + body + ' ' + error) if not success: raise ExchangeError(self.id + ': success value False: ' + body)
def fetch_order(self, id, symbol=None, params={}): if not symbol: raise ExchangeError(self.id + ' fetchOrder requires a symbol parameter') 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' if not params.get('contract_type'): raise ExchangeError( self.id + ' futureOrderInfo requires a contract_type parameter in params' ) request['contract_type'] = params.get('contract_type') method += 'OrderInfo' response = 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) if self.password is None: if not ('trade_pwd' in list(params.keys())): raise ExchangeError( self.id + ' withdraw() requires self.password set on the exchange instance or a trade_pwd parameter' ) if not ('totp_code' in list(params.keys())): raise ExchangeError( self.id + ' withdraw() requires a totp_code parameter for 2FA authentication' ) body = { 'trade_pwd': self.password, 'coin_symbol': currency['id'], 'amount': amount, 'addr': address, } if tag is not None: body['address_remark'] = tag response = self.privatePostTransfer({ 'cmd': 'transfer/transferOut', 'body': self.extend(body, params), }) return { 'info': response, 'id': None, }
async def withdraw(self, currency, amount, address, tag=None, params={}): self.check_address(address) await self.load_markets() request = { 'coin': currency, 'quantity': '{:.10f}'.format(amount), 'address': address, } if currency == 'BRL': account_ref = ('account_ref' in list(params.keys())) if not account_ref: raise ExchangeError( self.id + ' requires account_ref parameter to withdraw ' + currency) elif currency != 'LTC': tx_fee = ('tx_fee' in list(params.keys())) if not tx_fee: raise ExchangeError(self.id + ' requires tx_fee parameter to withdraw ' + currency) response = await self.privatePostWithdrawCoin( self.extend(request, params)) return { 'info': response, 'id': response['response_data']['withdrawal']['id'], }
def handle_errors(self, code, reason, url, method, headers, body): if code < 400 or code >= 600: return if body[0] != '{': raise ExchangeError(self.id + ' ' + body) response = json.loads(body) message = self.safe_value(response['error'], 'error_code') raise ExchangeError(self.id + ' ' + message)
def fetch_orders(self, symbol=None, since=None, limit=None, params={}): if not symbol: raise ExchangeError(self.id + ' fetchOrders requires a symbol parameter') self.load_markets() market = self.market(symbol) method = 'privatePost' request = { 'symbol': market['id'], } order_id_in_params = ('order_id' in list(params.keys())) if market['future']: method += 'FutureOrdersInfo' if not params.get('contract_type'): raise ExchangeError( self.id + ' futureOrdersInfo requires a contract_type parameter in params' ) request['contract_type'] = params.get('contract_type') if not order_id_in_params: raise ExchangeError( self.id + ' fetchOrders() requires order_id param for futures market ' + symbol + '(a string of one or more order ids, comma-separated)') else: status = None if 'type' in params: status = params['type'] elif 'status' in params: status = params['status'] else: name = 'type' if order_id_in_params else 'status' raise ExchangeError( self.id + ' fetchOrders() requires ' + name + ' param for spot market ' + symbol + '(0 - for unfilled orders, 1 - for filled/canceled orders)' ) if order_id_in_params: method += 'OrdersInfo' request = self.extend(request, { 'type': status, 'order_id': params['order_id'], }) else: method += 'OrderHistory' request = self.extend( request, { 'status': status, 'current_page': 1, # current page number 'page_length': 200, # number of orders returned per page, maximum 200 }) params = self.omit(params, ['type', 'status']) response = getattr(self, method)(self.extend(request, params)) ordersField = self.get_orders_field() return self.parse_orders(response[ordersField], market, since, limit)
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 api == 'private': if 'code' in response: raise ExchangeError(self.id + ' ' + self.json(response)) if 'result' in response: if not response['result']: raise ExchangeError(self.id + ' ' + self.json(response)) return response
def create_order(self, symbol, type, side, amount, price=None, params={}): if type == 'market': raise ExchangeError(self.id + ' allows limit orders only') self.load_markets() market = self.market(symbol) # price = float(price) # amount = float(amount) request = { 'TradePairId': market['id'], 'Type': self.capitalize(side), # 'Rate': self.price_to_precision(symbol, price), # 'Amount': self.amount_to_precision(symbol, amount), 'Rate': price, 'Amount': amount, } response = self.privatePostSubmitTrade(self.extend(request, params)) if not response: raise ExchangeError(self.id + ' createOrder returned unknown error: ' + self.json(response)) id = None filled = 0.0 if 'Data' in response: if 'OrderId' in response['Data']: if response['Data']['OrderId']: id = str(response['Data']['OrderId']) if 'FilledOrders' in response['Data']: filledOrders = response['Data']['FilledOrders'] filledOrdersLength = len(filledOrders) if filledOrdersLength: filled = None timestamp = self.milliseconds() order = { 'id': id, 'timestamp': timestamp, 'datetime': self.iso8601(timestamp), 'lastTradeTimestamp': None, 'status': 'open', 'symbol': symbol, 'type': type, 'side': side, 'price': price, 'cost': price * amount, 'amount': amount, 'remaining': amount, 'filled': filled, 'fee': None, # 'trades': self.parse_trades(order['trades'], market), } if id: self.orders[id] = order return self.extend({'info': response}, order)
def cancel_order(self, id, symbol=None, params={}): side = ('side' in list(params.keys())) if not side: raise ExchangeError(self.id + ' cancelOrder requires a side parameter(sell or buy) and a currency parameter') side = 'purchase' if (side == 'buy') else 'sales' currency = ('currency' in list(params.keys())) if not currency: raise ExchangeError(self.id + ' cancelOrder requires a currency parameter') return self.privatePostTradeCancel({ 'order_id': id, 'type': params['side'], 'currency': params['currency'], })
async def request(self, path, api='trade', method='GET', params={}, headers=None, body=None): response = await self.fetch2(path, api, method, params, headers, body) if 'status' in response: if response['status'] == 'error': raise ExchangeError(self.id + ' ' + self.json(response)) if 'code' in response: raise ExchangeError(self.id + ' ' + self.json(response)) return response
def request(self, path, api='api', method='GET', params={}, headers=None, body=None): response = self.fetch2(path, api, method, params, headers, body) if 'error' in response: raise ExchangeError(self.id + ' ' + response['error']) if 'success' in response: if not response['success']: raise ExchangeError(self.id + ' ' + self.json(response)) return response
def fetch_order_book(self, symbol, limit=None, params={}): self.load_markets() market = self.market(symbol) response = self.marketGetDepth(self.extend({ 'symbol': market['id'], 'type': 'step0', }, params)) if 'tick' in response: if not response['tick']: raise ExchangeError(self.id + ' fetchOrderBook() returned empty response: ' + self.json(response)) orderbook = response['tick'] timestamp = orderbook['ts'] orderbook['nonce'] = orderbook['version'] return self.parse_order_book(orderbook, timestamp) raise ExchangeError(self.id + ' fetchOrderBook() returned unrecognized response: ' + self.json(response))
def create_order(self, symbol, type, side, amount, price=None, params={}): if type != 'limit': raise ExchangeError(self.id + ' ' + self.version + ' accepts limit orders only') if symbol != 'BTC/USD': raise ExchangeError(self.id + ' v1 supports BTC/USD orders only') method = 'privatePost' + self.capitalize(side) order = { 'amount': amount, 'price': price, } response = getattr(self, method)(self.extend(order, params)) return { 'info': response, 'id': response['id'], }
def handle_errors(self, code, reason, url, method, headers, body): if code == 200: if (body[0] == '{') or (body[0] == '['): response = json.loads(body) if 'result' in response: result = response['result'] if 'errorCode' in result: errorCode = result['errorCode'] if errorCode != 'OK': raise ExchangeError(self.id + ' error returned: ' + body) else: raise ExchangeError(self.id + ' malformed response: no result in response: ' + body) else: # if not a JSON response raise ExchangeError(self.id + ' returned a non-JSON reply: ' + body)
def request(self, path, api='public', method='GET', params={}, headers=None, body=None): response = self.fetch2(path, api, method, params, headers, body) if not response: raise ExchangeError(self.id + ' returned ' + self.json(response)) elif response is True: return response elif 'e' in response: if 'ok' in response: if response['ok'] == 'ok': return response raise ExchangeError(self.id + ' ' + self.json(response)) elif 'error' in response: if response['error']: raise ExchangeError(self.id + ' ' + self.json(response)) return response
def request(self, path, api='public', method='GET', params={}, headers=None, body=None): response = self.fetch2(path, api, method, params, headers, body) if 'warning' in response: if response['warning']: raise ExchangeError(self.id + ' ' + self.json(response)) if 'error' in response: if response['error']: raise ExchangeError(self.id + ' ' + self.json(response)) return response
def handle_errors(self, code, reason, url, method, headers, body): if code == 200: if (body[0] == '{') or (body[0] == '['): response = json.loads(body) if 'success' in response: success = response['success'] if not success: raise ExchangeError(self.id + ' error returned: ' + body) if not('message' in list(response.keys())): raise ExchangeError(self.id + ' malformed response: no "message" in response: ' + body) else: raise ExchangeError(self.id + ' malformed response: no "success" in response: ' + body) else: # if not a JSON response raise ExchangeError(self.id + ' returned a non-JSON reply: ' + body)
def handle_errors(self, code, reason, url, method, headers, body): if not isinstance(body, basestring): return if body[0] == '{': response = json.loads(body) if code >= 300: errorCode = self.safe_string(response, 'errorCode') if errorCode in self.exceptions: ExceptionClass = self.exceptions[errorCode] raise ExceptionClass(self.id + ' ' + body) else: raise ExchangeError(self.id + ' ' + body) # returns status code 200 even if success == False success = self.safe_value(response, 'success', True) if not success: raise ExchangeError(self.id + ' ' + body)
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') ticker = self.publicGetTicker(params) timestamp = int(ticker['timestamp']) * 1000 vwap = float(ticker['vwap']) baseVolume = float(ticker['volume']) quoteVolume = baseVolume * vwap last = float(ticker['last']) return { 'symbol': symbol, 'timestamp': timestamp, 'datetime': self.iso8601(timestamp), 'high': float(ticker['high']), 'low': float(ticker['low']), 'bid': float(ticker['bid']), 'bidVolume': None, 'ask': float(ticker['ask']), 'askVolume': None, 'vwap': vwap, 'open': float(ticker['open']), 'close': last, 'last': last, 'previousClose': None, 'change': None, 'percentage': None, 'average': None, 'baseVolume': baseVolume, 'quoteVolume': quoteVolume, 'info': ticker, }
def sign(self, path, api='public', method='GET', params={}, headers=None, body=None): if self.id == 'cryptocapital': raise ExchangeError(self.id + ' is an abstract base API for _1btcxe') url = self.urls['api'] + '/' + path if api == 'public': if params: url += '?' + self.urlencode(params) else: self.check_required_credentials() query = self.extend( { 'api_key': self.apiKey, 'nonce': self.nonce(), }, params) request = self.json(query) query['signature'] = self.hmac(self.encode(request), self.encode(self.secret)) body = self.json(query) headers = {'Content-Type': 'application/json'} return {'url': url, 'method': method, 'body': body, 'headers': headers}
def sign(self, path, api='public', method='GET', params={}, headers=None, body=None): if self.id == 'btctrader': raise ExchangeError( self.id + ' is an abstract base API for BTCExchange, BTCTurk') url = self.urls['api'] + '/' + path if api == 'public': if params: url += '?' + self.urlencode(params) else: self.check_required_credentials() nonce = str(self.nonce()) body = self.urlencode(params) secret = base64.b64decode(self.secret) auth = self.apiKey + nonce headers = { 'X-PCK': self.apiKey, 'X-Stamp': nonce, 'X-Signature': base64.b64encode( self.hmac(self.encode(auth), secret, hashlib.sha256, 'binary')), 'Content-Type': 'application/x-www-form-urlencoded', } return {'url': url, 'method': method, 'body': body, 'headers': headers}
async def create_order(self, symbol, type, side, amount, price=None, params={}): await self.load_markets() order = { 'PairSymbol': self.market_id(symbol), 'OrderType': 0 if (side == 'buy') else 1, 'OrderMethod': 1 if (type == 'market') else 0, } if type == 'market': if not ('Total' in list(params.keys())): raise ExchangeError( self.id + ' createOrder requires the "Total" extra parameter for market orders(amount and price are both ignored)' ) else: order['Price'] = price order['Amount'] = amount response = await self.privatePostExchange(self.extend(order, params)) return { 'info': response, 'id': response['id'], }
def fetch_closed_orders(self, symbol=None, since=None, limit=200, params={}): if symbol is None: raise ExchangeError( self.id + ' fetchClosedOrders requires a symbol argument') self.load_markets() market = self.market(symbol) response = self.privatePostOrderpending({ 'cmd': 'orderpending/pendingHistoryList', 'body': self.extend( { 'pair': market['id'], 'account_type': 0, # 0 - regular, 1 - margin 'page': 1, 'size': limit, }, params), }) orders = self.safe_value(response['result'], 'items', []) return self.parse_orders(orders, market, since, limit)
async def deposit(self, currency, amount, address, params={}): await self.load_markets() request = { 'currency': currency, 'amount': amount, } method = 'privatePostDeposits' if 'payment_method_id' in params: # deposit from a payment_method, like a bank account method += 'PaymentMethod' elif 'coinbase_account_id' in params: # deposit into GDAX account from a Coinbase account method += 'CoinbaseAccount' else: # deposit methodotherwise we did not receive a supported deposit location # relevant docs link for the Googlers # https://docs.gdax.com/#deposits raise NotSupported( self.id + ' deposit() requires one of `coinbase_account_id` or `payment_method_id` extra params' ) response = await getattr(self, method)(self.extend(request, params)) if not response: raise ExchangeError(self.id + ' deposit() error: ' + self.json(response)) return { 'info': response, 'id': response['id'], }