Beispiel #1
0
 def handle_errors(self,
                   code,
                   reason,
                   url,
                   method,
                   headers,
                   body,
                   response=None):
     if code == 520:
         raise ExchangeNotAvailable(self.id + ' ' + 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)
     if body[0] == '{':
         response = json.loads(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] in self.exceptions:
                             raise self.exceptions[response['error'][i]](
                                 message)
                     raise ExchangeError(message)
Beispiel #2
0
 def handle_errors(self, code, 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
     fixedJSONString = self.sanitize_broken_json_string(body)
     if fixedJSONString[0] == '{':
         response = json.loads(fixedJSONString)
         if 'Success' in response:
             success = self.safe_value(response, 'Success')
             if success is not None:
                 if not success:
                     error = self.safe_string(response, 'Error')
                     feedback = self.id
                     if isinstance(error, basestring):
                         feedback = feedback + ' ' + error
                         if error.find('Invalid trade amount') >= 0:
                             raise InvalidOrder(feedback)
                         if error.find('No matching trades found') >= 0:
                             raise OrderNotFound(feedback)
                         if error.find('does not exist') >= 0:
                             raise OrderNotFound(feedback)
                         if error.find('Insufficient Funds') >= 0:
                             raise InsufficientFunds(feedback)
                         if error.find('Nonce has already been used') >= 0:
                             raise InvalidNonce(feedback)
                     else:
                         feedback = feedback + ' ' + fixedJSONString
                     raise ExchangeError(feedback)
Beispiel #3
0
 def handle_errors(self, code, reason, url, method, headers, 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)
Beispiel #4
0
 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 == '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))
Beispiel #5
0
 def handle_errors(self, code, reason, url, method, headers, body, response,
                   requestHeaders, requestBody):
     if not response:
         return  # fallback to default error handler
     #
     #     {"usOut":1535877098645376,"usIn":1535877098643364,"usDiff":2012,"testnet":false,
     #     "success":false,"message":"order_not_found","error":10004}
     #
     error = self.safe_string(response, 'error')
     if error is not None and error != '0':
         error_dict = literal_eval(error)
         error_code = self.safe_string(error_dict, 'code')
         message = self.safe_string(error_dict, 'message')
         message = message.lower() if message else message
         feedback = self.id + ' ' + body
         if 'order_not_found' == message:
             raise OrderNotFound(feedback)
         elif ('invalid' in message
               and 'nonce' in message) or ('invalid' in feedback
                                           and 'nonce' in feedback):
             raise InvalidNonce(feedback)
         # elif 'invalid_credentials' in message:
         #     raise AuthenticationError(feedback)
         exceptions = self.exceptions
         if error_code in exceptions:
             raise exceptions[error_code](feedback)
         raise ExchangeError(feedback)  # unknown message
Beispiel #6
0
 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
     # {"error":"Permission denied."}
     if 'error' in response:
         message = response['error']
         feedback = self.id + ' ' + self.json(response)
         exceptions = self.exceptions
         if message in exceptions:
             raise exceptions[message](feedback)
         elif message.find('Total must be at least') >= 0:
             raise InvalidOrder(feedback)
         elif message.find('This account is frozen.') >= 0:
             raise AccountSuspended(feedback)
         elif message.find('Not enough') >= 0:
             raise InsufficientFunds(feedback)
         elif message.find('Nonce must be greater') >= 0:
             raise InvalidNonce(feedback)
         elif message.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))
Beispiel #7
0
 def throw_exception_on_error(self, response):
     # {success: False, code: "ERROR", msg: "Min price:100.0"}
     # {success: True,  code: "OK",    msg: "Operation succeeded."}
     if not('success' in list(response.keys())):
         raise ExchangeError(self.id + ': malformed response: ' + self.json(response))
     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))
Beispiel #8
0
 async def fetch_order_book_snapshot(self, client, symbol, params={}):
     orderbook = self.orderbooks[symbol]
     market = self.market(symbol)
     messageHash = 'l2orderbook' + ':' + market['id']
     subscription = client.subscriptions[messageHash]
     if not subscription['fetchingOrderBookSnapshot']:
         subscription['startTime'] = self.milliseconds()
     subscription['fetchingOrderBookSnapshot'] = True
     maxAttempts = self.safe_integer(self.options, 'fetchOrderBookSnapshotMaxAttempts', 10)
     maxDelay = self.safe_integer(self.options, 'fetchOrderBookSnapshotMaxDelay', 10000)
     try:
         limit = self.safe_integer(subscription, 'limit', 0)
         # 3. Request a level-2 order book snapshot for the market from the REST API Order Books endpoint with limit set to 0.
         snapshot = await self.fetch_order_book(symbol, limit)
         firstBuffered = self.safe_value(orderbook.cache, 0)
         firstData = self.safe_value(firstBuffered, 'data')
         firstNonce = self.safe_integer(firstData, 'u')
         length = len(orderbook.cache)
         lastBuffered = self.safe_value(orderbook.cache, length - 1)
         lastData = self.safe_value(lastBuffered, 'data')
         lastNonce = self.safe_integer(lastData, 'u')
         bothExist = (firstNonce is not None) and (lastNonce is not None)
         # ensure the snapshot is inside the range of our cached messages
         # for example if the snapshot nonce is 100
         # the first nonce must be less than or equal to 101 and the last nonce must be greater than 101
         if bothExist and (firstNonce <= snapshot['nonce'] + 1) and (lastNonce > snapshot['nonce']):
             orderbook.reset(snapshot)
             for i in range(0, len(orderbook.cache)):
                 message = orderbook.cache[i]
                 data = self.safe_value(message, 'data')
                 u = self.safe_integer(data, 'u')
                 if u > orderbook['nonce']:
                     # 5. Discard all order book update messages with sequence numbers less than or equal to the snapshot sequence number.
                     # 6. Apply the remaining buffered order book update messages and any incoming order book update messages to the order book snapshot.
                     self.handle_order_book_message(client, message, orderbook)
             subscription['fetchingOrderBookSnapshot'] = False
             client.resolve(orderbook, messageHash)
         else:
             # 4. If the sequence in the order book snapshot is less than the sequence of the
             #    first buffered order book update message, discard the order book snapshot and retry step 3.
             # self will continue to recurse until we have a buffered message
             # since updates the order book endpoint depend on order events
             # so it will eventually raise if there are no orders on a pair
             subscription['numAttempts'] = subscription['numAttempts'] + 1
             timeElapsed = self.milliseconds() - subscription['startTime']
             maxAttemptsValid = subscription['numAttempts'] < maxAttempts
             timeElapsedValid = timeElapsed < maxDelay
             if maxAttemptsValid and timeElapsedValid:
                 self.delay(self.rateLimit, self.fetch_order_book_snapshot, client, symbol)
             else:
                 endpart = ' in ' + str(maxAttempts) + ' attempts' if (not maxAttemptsValid) else ' after ' + str(maxDelay) + ' milliseconds'
                 raise InvalidNonce(self.id + ' failed to synchronize WebSocket feed with the snapshot for symbol ' + symbol + endpart)
     except Exception as e:
         subscription['fetchingOrderBookSnapshot'] = False
         client.reject(e, messageHash)
Beispiel #9
0
 async def fetch_order_book_snapshot(self, client, message, subscription):
     symbol = self.safe_string(subscription, 'symbol')
     limit = self.safe_integer(subscription, 'limit')
     messageHash = self.safe_string(subscription, 'messageHash')
     try:
         # 2. Initiate a REST request to get the snapshot data of Level 2 order book.
         # todo: self is a synch blocking call in ccxt.php - make it async
         snapshot = await self.fetch_order_book(symbol, limit)
         orderbook = self.orderbooks[symbol]
         messages = orderbook.cache
         # make sure we have at least one delta before fetching the snapshot
         # otherwise we cannot synchronize the feed with the snapshot
         # and that will lead to a bidask cross as reported here
         # https://github.com/ccxt/ccxt/issues/6762
         firstMessage = self.safe_value(messages, 0, {})
         data = self.safe_value(firstMessage, 'data', {})
         sequenceStart = self.safe_integer(data, 'sequenceStart')
         nonce = self.safe_integer(snapshot, 'nonce')
         previousSequence = sequenceStart - 1
         # if the received snapshot is earlier than the first cached delta
         # then we cannot align it with the cached deltas and we need to
         # retry synchronizing in maxAttempts
         if nonce < previousSequence:
             options = self.safe_value(self.options,
                                       'fetchOrderBookSnapshot', {})
             maxAttempts = self.safe_integer(options, 'maxAttempts', 3)
             numAttempts = self.safe_integer(subscription, 'numAttempts', 0)
             # retry to syncrhonize if we haven't reached maxAttempts yet
             if numAttempts < maxAttempts:
                 # safety guard
                 if messageHash in client.subscriptions:
                     numAttempts = self.sum(numAttempts, 1)
                     subscription['numAttempts'] = numAttempts
                     client.subscriptions[messageHash] = subscription
                     self.spawn(self.fetch_order_book_snapshot, client,
                                message, subscription)
             else:
                 # raise upon failing to synchronize in maxAttempts
                 raise InvalidNonce(
                     self.id +
                     ' failed to synchronize WebSocket feed with the snapshot for symbol '
                     + symbol + ' in ' + str(maxAttempts) + ' attempts')
         else:
             orderbook.reset(snapshot)
             # unroll the accumulated deltas
             # 3. Playback the cached Level 2 data flow.
             for i in range(0, len(messages)):
                 message = messages[i]
                 self.handle_order_book_message(client, message, orderbook)
             self.orderbooks[symbol] = orderbook
             client.resolve(orderbook, messageHash)
     except Exception as e:
         client.reject(e, messageHash)
Beispiel #10
0
 def throw_exception_on_error(self, response):
     if 'success' in response:
         if not response['success']:
             if 'code' in response:
                 message = self.safe_string(response, 'msg')
                 if response['code'] == 'UNAUTH':
                     if message == 'Invalid nonce':
                         raise InvalidNonce(self.id + ' ' + message)
                     raise AuthenticationError(self.id + ' ' + self.json(response))
                 elif response['code'] == 'ERROR':
                     if message.find('precision of amount') >= 0:
                         raise InvalidOrder(self.id + ' ' + message)
Beispiel #11
0
 def handle_errors(self, code, reason, url, method, headers, body):
     if code >= 400:
         if body and(body[0] == "{"):
             response = json.loads(body)
             if 'success' in response:
                 if not response['success']:
                     if 'code' in response:
                         if response['code'] == 'UNAUTH':
                             message = self.safe_string(response, 'msg')
                             if message == 'Invalid nonce':
                                 raise InvalidNonce(self.id + ' ' + message)
                             raise AuthenticationError(self.id + ' ' + self.json(response))
                     raise ExchangeError(self.id + ' ' + self.json(response))
         else:
             raise ExchangeError(self.id + ' ' + str(code) + ' ' + reason)
Beispiel #12
0
 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('Max price:') >= 0:
             raise InvalidOrder(feedback)  # price > limits.price.max
         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))
Beispiel #13
0
 async def fetch_order_book_snapshot(self, client, symbol, params={}):
     orderbook = self.orderbooks[symbol]
     market = self.market(symbol)
     messageHash = 'l2orderbook' + ':' + market['id']
     subscription = client.subscriptions[messageHash]
     maxAttempts = self.safe_integer(self.options, 'fetchOrderBookSnapshotMaxAttempts', 3)
     subscription['fetchingOrderBookSnapshot'] = True
     try:
         limit = self.safe_integer(subscription, 'limit', 0)
         # 3. Request a level-2 order book snapshot for the market from the REST API Order Books endpoint with limit set to 0.
         snapshot = await self.fetch_order_book(symbol, limit)
         firstBuffered = self.safe_value(orderbook.cache, 0)
         firstData = self.safe_value(firstBuffered, 'data')
         firstNonce = self.safe_integer(firstData, 'u')
         length = len(orderbook.cache)
         lastBuffered = self.safe_value(orderbook.cache, length - 1)
         lastData = self.safe_value(lastBuffered, 'data')
         lastNonce = self.safe_integer(lastData, 'u')
         # ensure the snapshot is inside the range of our cached messages
         bothExist = (firstNonce is not None) and (lastNonce is not None)
         if bothExist and (snapshot['nonce'] > firstNonce) and (snapshot['nonce'] < lastNonce):
             orderbook.reset(snapshot)
             for i in range(0, len(orderbook.cache)):
                 message = orderbook.cache[i]
                 data = self.safe_value(message, 'data')
                 u = self.safe_integer(data, 'u')
                 if u > orderbook['nonce']:
                     # 5. Discard all order book update messages with sequence numbers less than or equal to the snapshot sequence number.
                     # 6. Apply the remaining buffered order book update messages and any incoming order book update messages to the order book snapshot.
                     self.handle_order_book_message(client, message, orderbook)
             subscription['fetchingOrderBookSnapshot'] = False
             client.resolve(orderbook, messageHash)
         else:
             # 4. If the sequence in the order book snapshot is less than the sequence of the
             #    first buffered order book update message, discard the order book snapshot and retry step 3.
             subscription['numAttempts'] = subscription['numAttempts'] + 1
             if subscription['numAttempts'] < maxAttempts:
                 self.delay(self.rateLimit, self.fetch_order_book_snapshot, client, symbol)
             else:
                 raise InvalidNonce(self.id + ' failed to synchronize WebSocket feed with the snapshot for symbol ' + symbol + ' in ' + str(maxAttempts) + ' attempts')
     except Exception as e:
         subscription['fetchingOrderBookSnapshot'] = False
         client.reject(e, messageHash)
Beispiel #14
0
 def handle_errors(self, code, reason, url, method, headers, body,
                   response):
     if response is None:
         return  # fallback to default error handler
     if 'Success' in response:
         success = self.safe_value(response, 'Success')
         if success is not None:
             if not success:
                 error = self.safe_string(response, 'Error')
                 feedback = self.id + ' ' + body
                 if isinstance(error, basestring):
                     if error.find('Invalid trade amount') >= 0:
                         raise InvalidOrder(feedback)
                     if error.find('No matching trades found') >= 0:
                         raise OrderNotFound(feedback)
                     if error.find('does not exist') >= 0:
                         raise OrderNotFound(feedback)
                     if error.find('Insufficient Funds') >= 0:
                         raise InsufficientFunds(feedback)
                     if error.find('Nonce has already been used') >= 0:
                         raise InvalidNonce(feedback)
                 raise ExchangeError(feedback)