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 handle_errors(self, code, reason, url, method, headers, body): if body.find('Invalid order') >= 0: raise InvalidOrder(self.id + ' ' + body) if body.find('Invalid nonce') >= 0: raise InvalidNonce(self.id + ' ' + body) if body.find('Insufficient funds') >= 0: raise InsufficientFunds(self.id + ' ' + body) if body.find('Cancel pending') >= 0: raise CancelPending(self.id + ' ' + body) if body.find('Invalid arguments:volume') >= 0: raise InvalidOrder(self.id + ' ' + body)
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, code, reason, url, method, headers, body): response = None try: response = json.loads(body) except Exception as e: # syntax error, resort to default error handler return if 'error' in response: error = response['error'] feedback = self.id + ' ' + self.json(response) if error == 'Invalid order number, or you are not the person who placed the order.': raise OrderNotFound(feedback) elif error == 'Internal error. Please try again.': raise ExchangeNotAvailable(feedback) elif error == 'Order not found, or you are not the person who placed it.': raise OrderNotFound(feedback) elif error == 'Invalid API key/secret pair.': raise AuthenticationError(feedback) elif error == 'Please do not make more than 8 API calls per second.': raise DDoSProtection(feedback) elif error.find('Total must be at least') >= 0: raise InvalidOrder(feedback) elif error.find('Not enough') >= 0: raise InsufficientFunds(feedback) elif error.find('Nonce must be greater') >= 0: raise InvalidNonce(feedback) elif error.find( 'You have already called cancelOrder or moveOrder on self order.' ) >= 0: raise CancelPending(feedback) else: raise ExchangeError(self.id + ': unknown error: ' + self.json(response))
def handle_errors(self, code, reason, url, method, headers, body): if code == 400: if body[0] == '{': response = json.loads(body) if 'error' in response: if 'message' in response['error']: message = response['error']['message'] if message == 'Order not found': raise OrderNotFound(self.id + ' order not found in active orders') elif message == 'Quantity not a valid number': raise InvalidOrder(self.id + ' ' + body) elif message == 'Insufficient funds': raise InsufficientFunds(self.id + ' ' + body) elif message == 'Duplicate clientOrderId': raise InvalidOrder(self.id + ' ' + body) raise ExchangeError(self.id + ' ' + body)
async def create_order(self, symbol, type, side, amount, price=None, params={}): await self.load_markets() order = { 'pair': self.market_id(symbol), 'type': side, 'amount': amount, } if type == 'limit': order['price'] = price else: # for market buy CEX.io requires the amount of quote currency to spend if side == 'buy': if not price: raise InvalidOrder( 'For market buy orders ' + self.id + " requires the amount of quote currency to spend, to calculate proper costs call createOrder(symbol, 'market', 'buy', amount, price)" ) order['amount'] = amount * price order['order_type'] = type response = await self.privatePostPlaceOrderPair( self.extend(order, params)) return { 'info': response, 'id': response['id'], }
def handle_errors(self, code, reason, url, method, headers, body, response=None): # {success: 0, error: "invalid order."} # or # [{data, ...}, {...}, ...] if response is None: if body[0] == '{' or body[0] == '[': response = json.loads(body) if isinstance(response, list): return # public endpoints may return []-arrays if not ('success' in list(response.keys())): return # no 'success' property on public responses if response['success'] == 1: # {success: 1, return: {orders: []}} if not ('return' in list(response.keys())): raise ExchangeError(self.id + ': malformed response: ' + self.json(response)) else: return message = response['error'] feedback = self.id + ' ' + self.json(response) if message == 'Insufficient balance.': raise InsufficientFunds(feedback) elif message == 'invalid order.': raise OrderNotFound(feedback) # cancelOrder(1) elif message.find('Minimum price ') >= 0: raise InvalidOrder( feedback ) # price < limits.price.min, on createLimitBuyOrder('ETH/BTC', 1, 0) elif message.find('Minimum order ') >= 0: raise InvalidOrder( feedback ) # cost < limits.cost.min on createLimitBuyOrder('ETH/BTC', 0, 1) elif message == 'Invalid credentials. API not found or session has expired.': raise AuthenticationError(feedback) # on bad apiKey elif message == 'Invalid credentials. Bad sign.': raise AuthenticationError(feedback) # on bad secret raise ExchangeError(self.id + ': unknown error: ' + self.json(response))
def handle_errors(self, code, reason, url, method, headers, body): if (code == 400) or (code == 404): if body[0] == '{': response = json.loads(body) message = response['message'] error = self.id + ' ' + message if message.find('price too small') >= 0: raise InvalidOrder(error) elif message.find('price too precise') >= 0: raise InvalidOrder(error) elif message == 'Insufficient funds': raise InsufficientFunds(error) elif message == 'NotFound': raise OrderNotFound(error) elif message == 'Invalid API Key': raise AuthenticationError(error) raise ExchangeError(self.id + ' ' + message) raise ExchangeError(self.id + ' ' + body)
def throw_exception_on_error(self, response): # # API endpoints return the following formats # {success: False, code: "ERROR", msg: "Min price:100.0"} # {success: True, code: "OK", msg: "Operation succeeded."} # # Web OHLCV endpoint returns self: # {s: "ok", o: [], h: [], l: [], c: [], v: []} # # This particular method handles API responses only # if not ('success' in list(response.keys())): return if response['success'] is True: return # not an error if not ('code' in list(response.keys())) or not ('msg' in list( response.keys())): raise ExchangeError(self.id + ': malformed response: ' + self.json(response)) code = self.safe_string(response, 'code') message = self.safe_string(response, 'msg') feedback = self.id + ' ' + self.json(response) if code == 'UNAUTH': if message == 'Invalid nonce': raise InvalidNonce(feedback) raise AuthenticationError(feedback) elif code == 'ERROR': if message.find('The precision of amount') >= 0: raise InvalidOrder( feedback) # amount violates precision.amount if message.find('Min amount each order') >= 0: raise InvalidOrder(feedback) # amount < limits.amount.min if message.find('Min price:') >= 0: raise InvalidOrder(feedback) # price < limits.price.min if message.find('The precision of price') >= 0: raise InvalidOrder(feedback) # price violates precision.price elif code == 'NO_BALANCE': if message.find('Insufficient balance') >= 0: raise InsufficientFunds(feedback) raise ExchangeError(self.id + ': unknown response: ' + self.json(response))
def create_order(self, symbol, type, side, amount, price=None, params={}): if type != 'limit': raise InvalidOrder(self.id + ' allows limit orders only') self.load_markets() order = { 'price': self.price_to_precision(symbol, price), 'amount': self.amount_to_string(symbol, amount), 'tradeType': '1' if (side == 'buy') else '0', 'currency': self.market_id(symbol), } response = self.privateGetOrder(self.extend(order, params)) return { 'info': response, 'id': response['id'], }
async def create_order(self, symbol, type, side, amount, price=None, params={}): await self.load_markets() market = self.market(symbol) method = 'privatePost' + self.capitalize(side) response = await getattr(self, method)( self.extend( { 'market': market['id'], # 'price': self.price_to_precision(symbol, price), # 'amount': self.amount_to_precision(symbol, amount), 'price': price, 'amount': amount, }, params)) success = self.safe_integer(response, 'success') if success != 1: raise InvalidOrder(self.id + ' ' + self.json(response)) parts = response['message'].split(' / ') parts = parts[1:] feeParts = parts[5].split(' ') order = self.parse_order( { 'timestamp': self.milliseconds(), 'order_number': response['order_number'], 'type': parts[0].lower(), 'market': parts[0].lower(), 'amount': parts[2].split(' ')[1], 'price': parts[3].split(' ')[1], 'total': parts[4].split(' ')[1], 'fee': { 'cost': float(feeParts[1]), 'currency': feeParts[2], }, 'progress': '0.0', 'info': response, }, market) id = order['id'] self.orders[id] = order return order
def cancel_order(self, id, symbol=None, params={}): if not symbol: raise ExchangeError(self.id + ' cancelOrder requires a symbol argument') self.load_markets() market = self.market(symbol) currencyPair = market['id'] response = self.privatePostExchangeCancellimit(self.extend({ 'orderId': id, 'currencyPair': currencyPair, }, params)) message = self.safe_string(response, 'message', self.json(response)) if 'success' in response: if not response['success']: raise InvalidOrder(message) elif 'cancelled' in response: if response['cancelled']: return response else: raise OrderNotFound(message) raise ExchangeError(self.id + ' cancelOrder() failed: ' + self.json(response))
def create_order(self, symbol, type, side, amount, price=None, params={}): self.load_markets() market = self.market(symbol) if price is None: raise InvalidOrder( self.id + ' createOrder requires a price argument for both market and limit orders' ) request = { 'pair': market['id'], 'amount': self.amount_to_string(symbol, amount), 'price': self.price_to_precision(symbol, price), 'side': side, 'type': type, } response = self.privatePostUserSpotOrder(self.extend(request, params)) id = response['data']['order_id'] order = self.parse_order(response['data'], market) self.orders[id] = order return order
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: # # 1 - Liqui only returns the integer 'success' key from their private API # # {"success": 1, ...} httpCode == 200 # {"success": 0, ...} httpCode == 200 # # 2 - However, exchanges derived from Liqui, can return non-integers # # It can be a numeric string # {"sucesss": "1", ...} # {"sucesss": "0", ...}, httpCode >= 200(can be 403, 502, etc) # # Or just a string # {"success": "true", ...} # {"success": "false", ...}, httpCode >= 200 # # Or a boolean # {"success": True, ...} # {"success": False, ...}, httpCode >= 200 # # 3 - Oversimplified, Python PEP8 forbids comparison operator(==) of different types # # 4 - We do not want to copy-paste and duplicate the code of self handler to other exchanges derived from Liqui # # To cover points 1, 2, 3 and 4 combined self handler should work like self: # 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: code = self.safe_string(response, 'code') message = self.safe_string(response, 'error') feedback = self.id + ' ' + self.json(response) exceptions = self.exceptions if code in exceptions: raise exceptions[code](feedback) # need a second error map for these messages, apparently... # in fact, we can use the same .exceptions with string-keys to save some loc here if message == 'invalid api key': raise AuthenticationError(feedback) elif message == 'api key dont have trade permission': raise AuthenticationError(feedback) elif message.find( 'invalid parameter' ) >= 0: # errorCode 0, returned on buy(symbol, 0, 0) raise InvalidOrder(feedback) elif message == 'invalid order': raise InvalidOrder(feedback) elif message == 'Requests too often': raise DDoSProtection(feedback) elif message == 'not available': raise DDoSProtection(feedback) elif message == 'data unavailable': raise DDoSProtection(feedback) elif message == 'external service unavailable': raise DDoSProtection(feedback) else: raise ExchangeError(self.id + ' unknown "error" value: ' + self.json(response))