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))
def check_required_credentials(self): keys = list(self.requiredCredentials.keys()) for key in keys: if self.requiredCredentials[key] and not getattr(self, key): raise AuthenticationError(self.id + ' requires `' + key + '`')
def fetch_currencies_private(self, params={}): if not self.apiKey or not self.secret: raise AuthenticationError( self.id + " fetchCurrencies is an authenticated endpoint, therefore it requires 'apiKey' and 'secret' credentials. If you don't need currency details, set exchange.has['fetchCurrencies'] = False before calling its methods." ) request = { 'cmd': 'transfer/coinList', 'body': {}, } response = self.privatePostTransfer(self.extend(request, params)) # # { # "result":[ # { # "totalBalance":"14.57582269", # "balance":"14.57582269", # "freeze":"0.00000000", # "id":60, # "symbol":"USDT", # "icon_url":"/appimg/USDT_icon.png", # "describe_url":"[{\"lang\":\"zh-cn\",\"link\":\"https://bibox.zendesk.com/hc/zh-cn/articles/115004798234\"},{\"lang\":\"en-ww\",\"link\":\"https://bibox.zendesk.com/hc/en-us/articles/115004798234\"}]", # "name":"USDT", # "enable_withdraw":1, # "enable_deposit":1, # "enable_transfer":1, # "confirm_count":2, # "is_erc20":1, # "forbid_info":null, # "describe_summary":"[{\"lang\":\"zh-cn\",\"text\":\"USDT 是 Tether 公司推出的基于稳定价值货币美元(USD)的代币 Tether USD(简称USDT),1USDT=1美元,用户可以随时使用 USDT 与 USD 进行1:1的兑换。\"},{\"lang\":\"en-ww\",\"text\":\"USDT is a cryptocurrency asset issued on the Bitcoin blockchain via the Omni Layer Protocol. Each USDT unit is backed by a U.S Dollar held in the reserves of the Tether Limited and can be redeemed through the Tether Platform.\"}]", # "total_amount":4776930644, # "supply_amount":4642367414, # "price":"--", # "contract_father":"OMNI", # "supply_time":"--", # "comment":null, # "contract":"31", # "original_decimals":8, # "deposit_type":0, # "hasCobo":0, # "BTCValue":"0.00126358", # "CNYValue":"100.93381445", # "USDValue":"14.57524654", # "children":[ # {"type":"OMNI","symbol":"USDT","enable_deposit":1,"enable_withdraw":1,"confirm_count":2}, # {"type":"TRC20","symbol":"tUSDT","enable_deposit":1,"enable_withdraw":1,"confirm_count":20}, # {"type":"ERC20","symbol":"eUSDT","enable_deposit":1,"enable_withdraw":1,"confirm_count":25} # ] # }, # ], # "cmd":"transfer/coinList" # } # currencies = self.safe_value(response, 'result') result = {} for i in range(0, len(currencies)): currency = currencies[i] id = self.safe_string(currency, 'symbol') name = currency[ 'name'] # contains hieroglyphs causing python ASCII bug code = self.safe_currency_code(id) precision = 8 deposit = self.safe_value(currency, 'enable_deposit') withdraw = self.safe_value(currency, 'enable_withdraw') active = (deposit and withdraw) result[code] = { 'id': id, 'code': code, 'info': currency, 'name': name, 'active': active, 'fee': None, 'precision': precision, 'limits': { 'amount': { 'min': math.pow(10, -precision), 'max': math.pow(10, precision), }, 'withdraw': { 'min': None, 'max': math.pow(10, precision), }, }, } return result
async def create_order(self, symbol, type, side, amount, price=None, params={}): await self.load_markets() if not self.password: raise AuthenticationError( self.id + ' createOrder requires exchange.password to be set to user trading password(not login passwordnot )' ) self.check_required_credentials() market = self.market(symbol) orderType = 1 if (type == 'limit') else 2 order = { 'symbol': market['id'], 'side': side.upper(), 'type': orderType, 'volume': self.amount_to_precision(symbol, amount), 'capital_password': self.password, } if (type == 'market') and (side == 'buy'): if price is None: raise InvalidOrder( self.id + ' createOrder requires price argument for market buy orders to calculate total cost according to exchange rules' ) order['volume'] = self.amount_to_precision( symbol, float(amount) * float(price)) if type == 'limit': order['price'] = self.price_to_precision(symbol, price) else: if price is None: order['price'] = self.price_to_precision(symbol, 0) else: order['price'] = self.price_to_precision(symbol, price) response = await self.privatePostOrder(self.extend(order, params)) # # {"order_id":34343} # timestamp = self.milliseconds() return { 'info': response, 'id': str(response['data']['order_id']), 'timestamp': timestamp, 'datetime': self.iso8601(timestamp), 'lastTradeTimestamp': None, 'status': None, 'symbol': symbol, 'type': type, 'side': side, 'price': price, 'amount': amount, 'filled': None, 'remaining': None, 'cost': None, 'trades': None, 'fee': None, }
def handle_errors(self, code, reason, url, method, headers, body, response=None): 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 == 'APIKEY_INVALID': if self.options['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)) if message == 'INVALID_ORDER': # Bittrex will return an ambiguous INVALID_ORDER message # upon canceling already-canceled and closed orders # therefore self special case for cancelOrder # url = 'https://bittrex.com/api/v1.1/market/cancel?apikey=API_KEY&uuid=ORDER_UUID' cancel = 'cancel' indexOfCancel = url.find(cancel) if indexOfCancel >= 0: parts = url.split('&') orderId = None for i in range(0, len(parts)): part = parts[i] keyValue = part.split('=') if keyValue[0] == 'uuid': orderId = keyValue[1] break if orderId is not None: raise OrderNotFound(self.id + ' cancelOrder ' + orderId + ' ' + self.json(response)) else: raise OrderNotFound(self.id + ' cancelOrder ' + self.json(response)) if message in exceptions: raise exceptions[message](feedback) if message is not None: if message.find('throttled. Try again') >= 0: raise DDoSProtection(feedback) if message.find('problem') >= 0: raise ExchangeNotAvailable( feedback ) # 'There was a problem processing your request. If self problem persists, please contact...') raise ExchangeError(feedback)
def handle_errors(self, httpCode, reason, url, method, headers, body, response=None): 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 'code' in response: # # {"code": "100005", "msg": "request sign illegal", "data": null} # code = self.safe_string(response, 'code') if code is not None: message = self.safe_string(response, 'msg') feedback = self.id + ' ' + self.json(response) if code != '0': exceptions = self.exceptions if code in exceptions: if code == '1': # # {"code":"1","msg":"系统错误","data":null} # {“code”:“1",“msg”:“Balance insufficient,余额不足“,”data”:null} # if message.find('Balance insufficient') >= 0: raise InsufficientFunds(feedback) elif code == '2': if message == 'offsetNot Null': raise ExchangeError(feedback) elif message == 'api_keyNot EXIST': raise AuthenticationError(feedback) elif message == 'price precision exceed the limit': raise InvalidOrder(feedback) elif message == 'Parameter error': raise BadRequest(feedback) raise exceptions[code](feedback) else: raise ExchangeError(self.id + ' unknown "error" value: ' + self.json(response)) else: # # Google Translate: # 订单状态不能取消,订单取消失败 = Order status cannot be canceled # 根据订单号没有查询到订单,订单取消失败 = The order was not queried according to the order number # # {"code":"0","msg":"suc","data":{"success":[],"failed":[{"err-msg":"订单状态不能取消,订单取消失败","order-id":32857051,"err-code":"8"}]}} # {"code":"0","msg":"suc","data":{"success":[],"failed":[{"err-msg":"Parameter error","order-id":32857050,"err-code":"2"},{"err-msg":"订单状态不能取消,订单取消失败","order-id":32857050,"err-code":"8"}]}} # {"code":"0","msg":"suc","data":{"success":[],"failed":[{"err-msg":"Parameter error","order-id":98549677,"err-code":"2"},{"err-msg":"根据订单号没有查询到订单,订单取消失败","order-id":98549677,"err-code":"8"}]}} # if feedback.find('订单状态不能取消,订单取消失败') >= 0: if feedback.find('Parameter error') >= 0: raise OrderNotFound(feedback) else: raise InvalidOrder(feedback) elif feedback.find('根据订单号没有查询到订单,订单取消失败') >= 0: raise OrderNotFound(feedback)