def _curl_bitmex(self, path, query=None, postdict=None, timeout=None, verb=None, rethrow_errors=False, max_retries=None):
    'Send a request to BitMEX Servers.'
    url = (self.base_url + path)
    if (timeout is None):
        timeout = self.timeout
    if (not verb):
        verb = ('POST' if postdict else 'GET')
    if (max_retries is None):
        max_retries = (0 if (verb in ['POST', 'PUT']) else 3)
    auth = APIKeyAuthWithExpires(self.apiKey, self.apiSecret)

    def exit_or_throw(e):
        if rethrow_errors:
            raise e
        else:
            exit(1)

    def retry():
        self.retries += 1
        if (self.retries > max_retries):
            raise Exception(('Max retries on %s (%s) hit, raising.' % (path, json.dumps((postdict or '')))))
        return self._curl_bitmex(path, query, postdict, timeout, verb, rethrow_errors, max_retries)
    response = None
    try:
        logger.info(('sending req to %s: %s' % (url, json.dumps((postdict or query or '')))))
        req = requests.Request(verb, url, json=postdict, auth=auth, params=query)
        prepped = self.session.prepare_request(req)
        response = self.session.send(prepped, timeout=timeout)
        response.raise_for_status()
    except requests.exceptions.HTTPError as e:
        if (response is None):
            raise e
        if (response.status_code == 401):
            logger.error('API Key or Secret incorrect, please check and restart.')
            logger.error(('Error: ' + response.text))
            if postdict:
                logger.error(postdict)
            exit(1)
        elif (response.status_code == 404):
            if (verb == 'DELETE'):
                logger.error(('Order not found: %s' % postdict['orderID']))
                return
            logger.error(('Unable to contact the BitMEX API (404). ' + ('Request: %s \n %s' % (url, json.dumps(postdict)))))
            exit_or_throw(e)
        elif (response.status_code == 429):
            logger.error((('Ratelimited on current request. Sleeping, then trying again. Try fewer ' + 'order pairs or contact example@example.com to raise your limits. ') + ('Request: %s \n %s' % (url, json.dumps(postdict)))))
            ratelimit_reset = response.headers['X-RateLimit-Reset']
            to_sleep = (int(ratelimit_reset) - int(time.time()))
            reset_str = datetime.datetime.fromtimestamp(int(ratelimit_reset)).strftime('%X')
            logger.warning('Canceling all known orders in the meantime.')
            self.cancel([o['orderID'] for o in self.open_orders()])
            logger.error(('Your ratelimit will reset at %s. Sleeping for %d seconds.' % (reset_str, to_sleep)))
            time.sleep(to_sleep)
            return retry()
        elif (response.status_code == 503):
            logger.warning(('Unable to contact the BitMEX API (503), retrying. ' + ('Request: %s \n %s' % (url, json.dumps(postdict)))))
            time.sleep(3)
            return retry()
        elif (response.status_code == 400):
            error = response.json()['error']
            message = (error['message'].lower() if error else '')
            if ('duplicate clordid' in message):
                orders = (postdict['orders'] if ('orders' in postdict) else postdict)
                IDs = json.dumps({'clOrdID': [order['clOrdID'] for order in orders]})
                orderResults = self._curl_bitmex('/order', query={'filter': IDs}, verb='GET')
                for (i, order) in enumerate(orderResults):
                    if ((order['orderQty'] != abs(postdict['orderQty'])) or (order['side'] != ('Buy' if (postdict['orderQty'] > 0) else 'Sell')) or (order['price'] != postdict['price']) or (order['symbol'] != postdict['symbol'])):
                        raise Exception(('Attempted to recover from duplicate clOrdID, but order returned from API ' + ('did not match POST.\nPOST data: %s\nReturned order: %s' % (json.dumps(orders[i]), json.dumps(order)))))
                return orderResults
            elif ('insufficient available balance' in message):
                logger.error(('Account out of funds. The message: %s' % error['message']))
                exit_or_throw(Exception('Insufficient Funds'))
        logger.error(('Unhandled Error: %s: %s' % (e, response.text)))
        logger.error(('Endpoint was: %s %s: %s' % (verb, path, json.dumps(postdict))))
        exit_or_throw(e)
    except requests.exceptions.Timeout as e:
        logger.warning(('Timed out on request: %s (%s), retrying...' % (path, json.dumps((postdict or '')))))
        return retry()
    except requests.exceptions.ConnectionError as e:
        logger.warning(('Unable to contact the BitMEX API (%s). Please check the URL. Retrying. ' + ('Request: %s %s \n %s' % (e, url, json.dumps(postdict)))))
        time.sleep(1)
        return retry()
    self.retries = 0
    return response.json()
Send a request to BitMEX Servers.
def _curl_bitmex(self, path, query=None, postdict=None, timeout=None, verb=None, rethrow_errors=False, max_retries=None):
    
    url = (self.base_url + path)
    if (timeout is None):
        timeout = self.timeout
    if (not verb):
        verb = ('POST' if postdict else 'GET')
    if (max_retries is None):
        max_retries = (0 if (verb in ['POST', 'PUT']) else 3)
    auth = APIKeyAuthWithExpires(self.apiKey, self.apiSecret)

    def exit_or_throw(e):
        if rethrow_errors:
            raise e
        else:
            exit(1)

    def retry():
        self.retries += 1
        if (self.retries > max_retries):
            raise Exception(('Max retries on %s (%s) hit, raising.' % (path, json.dumps((postdict or )))))
        return self._curl_bitmex(path, query, postdict, timeout, verb, rethrow_errors, max_retries)
    response = None
    try:
        logger.info(('sending req to %s: %s' % (url, json.dumps((postdict or query or )))))
        req = requests.Request(verb, url, json=postdict, auth=auth, params=query)
        prepped = self.session.prepare_request(req)
        response = self.session.send(prepped, timeout=timeout)
        response.raise_for_status()
    except requests.exceptions.HTTPError as e:
        if (response is None):
            raise e
        if (response.status_code == 401):
            logger.error('API Key or Secret incorrect, please check and restart.')
            logger.error(('Error: ' + response.text))
            if postdict:
                logger.error(postdict)
            exit(1)
        elif (response.status_code == 404):
            if (verb == 'DELETE'):
                logger.error(('Order not found: %s' % postdict['orderID']))
                return
            logger.error(('Unable to contact the BitMEX API (404). ' + ('Request: %s \n %s' % (url, json.dumps(postdict)))))
            exit_or_throw(e)
        elif (response.status_code == 429):
            logger.error((('Ratelimited on current request. Sleeping, then trying again. Try fewer ' + 'order pairs or contact example@example.com to raise your limits. ') + ('Request: %s \n %s' % (url, json.dumps(postdict)))))
            ratelimit_reset = response.headers['X-RateLimit-Reset']
            to_sleep = (int(ratelimit_reset) - int(time.time()))
            reset_str = datetime.datetime.fromtimestamp(int(ratelimit_reset)).strftime('%X')
            logger.warning('Canceling all known orders in the meantime.')
            self.cancel([o['orderID'] for o in self.open_orders()])
            logger.error(('Your ratelimit will reset at %s. Sleeping for %d seconds.' % (reset_str, to_sleep)))
            time.sleep(to_sleep)
            return retry()
        elif (response.status_code == 503):
            logger.warning(('Unable to contact the BitMEX API (503), retrying. ' + ('Request: %s \n %s' % (url, json.dumps(postdict)))))
            time.sleep(3)
            return retry()
        elif (response.status_code == 400):
            error = response.json()['error']
            message = (error['message'].lower() if error else )
            if ('duplicate clordid' in message):
                orders = (postdict['orders'] if ('orders' in postdict) else postdict)
                IDs = json.dumps({'clOrdID': [order['clOrdID'] for order in orders]})
                orderResults = self._curl_bitmex('/order', query={'filter': IDs}, verb='GET')
                for (i, order) in enumerate(orderResults):
                    if ((order['orderQty'] != abs(postdict['orderQty'])) or (order['side'] != ('Buy' if (postdict['orderQty'] > 0) else 'Sell')) or (order['price'] != postdict['price']) or (order['symbol'] != postdict['symbol'])):
                        raise Exception(('Attempted to recover from duplicate clOrdID, but order returned from API ' + ('did not match POST.\nPOST data: %s\nReturned order: %s' % (json.dumps(orders[i]), json.dumps(order)))))
                return orderResults
            elif ('insufficient available balance' in message):
                logger.error(('Account out of funds. The message: %s' % error['message']))
                exit_or_throw(Exception('Insufficient Funds'))
        logger.error(('Unhandled Error: %s: %s' % (e, response.text)))
        logger.error(('Endpoint was: %s %s: %s' % (verb, path, json.dumps(postdict))))
        exit_or_throw(e)
    except requests.exceptions.Timeout as e:
        logger.warning(('Timed out on request: %s (%s), retrying...' % (path, json.dumps((postdict or )))))
        return retry()
    except requests.exceptions.ConnectionError as e:
        logger.warning(('Unable to contact the BitMEX API (%s). Please check the URL. Retrying. ' + ('Request: %s %s \n %s' % (e, url, json.dumps(postdict)))))
        time.sleep(1)
        return retry()
    self.retries = 0
    return response.json()