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 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 sign(self, path, api='public', method='GET', params={}, headers=None, body=None): if not self.apiKey: raise AuthenticationError(self.id + ' requires apiKey for all requests') url = self.urls['api'][api] + '/' + path if api == 'private': self.check_required_credentials() nonce = self.nonce() body = self.json(self.extend({'nonce': nonce}, params)) headers = { 'Content-Type': 'application/json', 'key': self.apiKey, 'sign': self.hmac(self.encode(body), self.encode(self.secret), hashlib.sha512), } 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 = { 'Code': self.market_id(symbol), 'Way': 'Bid' if (side == 'buy') else 'Ask', 'Amount': amount, } if type == 'limit': order['Price'] = price if self.twofa: if 'ValidationCode' in params: order['ValidationCode'] = params['ValidationCode'] else: raise AuthenticationError( self.id + ' two-factor authentication requires a missing ValidationCode parameter' ) response = await self.privatePostTradeOrders(self.extend( order, params)) return { 'info': response, 'id': response['clOrderId'], }
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))
async def request(self, path, api='public', method='GET', params={}, headers=None, body=None): response = await self.fetch2(path, api, method, params, headers, body) code = self.safe_integer(response, 'code') message = self.safe_string(response, 'message') if code and code != 100 and message: if code == 103: raise AuthenticationError(message) raise ExchangeError(message) return response
def handle_errors(self, statusCode, statusText, url, method, headers, body): if not isinstance(body, basestring): return # fallback to default error handler if len(body) < 2: return # Here is a sample QuadrigaCX response in case of authentication failure: # {"error":{"code":101,"message":"Invalid API Code or Invalid Signature"}} if statusCode == 200 and body.find('Invalid API Code or Invalid Signature') >= 0: raise AuthenticationError(self.id + ' ' + body)
def sign(self, path, api='public', method='GET', params={}, headers=None, body=None): if not self.apiKey: raise AuthenticationError( self.id + ' requires apiKey for all requests, their public API is always busy' ) if not self.uid: raise AuthenticationError( self.id + ' requires uid property for authentication and trading, their public API is always busy' ) url = self.urls['api'] + '/' + self.version if api == 'public': url += '/' + api url += '/' + self.implode_params(path, params) query = self.omit(params, self.extract_params(path)) if api == 'public': if query: url += '?' + self.urlencode(query) else: self.check_required_credentials() headers = {'Accept-Encoding': 'gzip, deflate'} nonce = str(self.nonce()) if method == 'POST': if query: headers['Content-Type'] = 'application/json' body = self.json(query) else: url += '?' + self.urlencode(query) auth = nonce + self.uid + self.apiKey + method + url if body: auth += body signature = self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha256, 'base64') credentials = self.uid + ':' + self.apiKey + ':' + nonce + ':' + self.binary_to_string( signature) headers['Authorization'] = 'HMAC ' + credentials return {'url': url, 'method': method, 'body': body, 'headers': headers}
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) status = self.safe_string(response, 'status') if status == 'error': code = self.safe_string(response, 'code') if code is not None: if code == 'API0005': raise AuthenticationError(self.id + ' invalid signature, use the uid for the main account if you have subaccounts') raise ExchangeError(self.id + ' ' + self.json(response))
def handle_errors(self, code, reason, url, method, headers, body): if code == 429: raise DDoSProtection(self.id + ' ' + body) if code >= 400: if body: if body[0] == '{': response = json.loads(body) if 'error' in response: if 'message' in response['error']: message = self.safe_value(response['error'], 'message') if message is not None: if message == 'Invalid API Key.': raise AuthenticationError(self.id + ' ' + self.json(response)) # stub code, need proper handling raise ExchangeError(self.id + ' ' + self.json(response))
def request(self, path, api='public', method='GET', params={}, headers=None, body=None): response = self.fetch2(path, api, method, params, headers, body) if 'success' in response: success = self.safe_integer(response, 'success') if success == 0: message = self.safe_string(response, 'message') if message == 'Invalid APIKey': raise AuthenticationError(message) raise ExchangeError(message) return response
def request(self, path, api='public', method='GET', params={}, headers=None, body=None): response = self.fetch2(path, api, method, params, headers, body) errors = self.safe_value(response, 'errors') data = self.safe_value(response, 'response') if errors or not data: authErrorKeys = ['Key', 'user_id', 'Sign'] for i in range(0, len(authErrorKeys)): errorKey = authErrorKeys[i] errorMessage = self.safe_string(errors, errorKey) if not errorMessage: continue if errorKey == 'user_id' and errorMessage.find('authorization') < 0: continue raise AuthenticationError(errorMessage) raise ExchangeError(self.json(errors)) return 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 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))