def on_ping(self, msg):
        try:
            if msg in self.books_following:
                book = self.get_order_book(msg)
                internal_book = {'bids': [], 'asks': []}

                bids = book['Z']
                asks = book['S']

                for bid in bids:
                    internal_book['bids'].append(
                        [str(bid['R']), str(bid['Q'])])
                for ask in asks:
                    internal_book['asks'].append(
                        [str(ask['R']), str(ask['Q'])])

                base, quote = OrderBookSocket.to_base_quote(msg)
                internal_book['base'] = base
                internal_book['quote'] = quote
                internal_book['exchange'] = 'bittrex'

                self.owner.notify_callbacks('order_book', data=internal_book)
        except Exception as e:
            traceback.print_exc(file=sys.stdout)
            logger().error('bittrex order book socket failed with error: ' +
                           str(e))
 def create_order(self,
                  base,
                  quote,
                  price,
                  quantity,
                  side,
                  order_type,
                  internal_order_id,
                  request_id=None,
                  requester_id=None,
                  **kwargs):
     try:
         self.client.create_order(symbol=base + quote,
                                  side=side,
                                  type=order_type,
                                  timeInForce='GTC',
                                  quantity=quantity,
                                  price=price,
                                  newClientOrderId=internal_order_id)
         message = dict()
         message['internal_order_id'] = internal_order_id
         message['request_id'] = request_id
         message['requester_id'] = requester_id
         message['action'] = 'order_sent'
         message['exchange'] = self.name
         self.notify_callbacks('trade_lifecycle',
                               trade_lifecycle_type='sent',
                               data=message)
     except BinanceAPIException as e:
         logger().error(
             'Failed to create order. Exception was: {}'.format(e))
 def get_balances(self):
     try:
         account = self.client.get_account()
         self.notify_callbacks('account',
                               account_type='balance',
                               data=account['balances'])
         return account['balances']
     except BinanceAPIException as e:
         logger().error(
             'Failed to get balances.  Exception was: {}'.format(e))
 def follow_order_book(self, base, quote):
     cross = base + quote
     if cross not in self.order_book_services:
         logger().info('Subscribing to ' + cross)
         self.order_book_services[cross] = OrderBookService(
             self.client, base, quote, self.notify_callbacks, self.name)
         self.order_book_services[cross].start()
         return True
     else:
         logger().warning('Already subscribed to ' + base + quote)
         pass
    def cancel_all(self, base, quote):
        product_id = self.get_product_id(base, quote)
        live_orders = self.client.get_orders(product_id=product_id,
                                             status='live')
        partially_filled_orders = self.client.get_orders(
            product_id=product_id, status='partially_filled')
        orders = live_orders['models'] + partially_filled_orders['models']

        for order in orders:
            try:
                self.client.cancel_order(order['id'])
            except Exception as e:
                logger().error('Failed to cancel order with error: {}'.format(
                    str(e)))

        time.sleep(2)
 def cancel_order(self,
                  base,
                  quote,
                  internal_order_id,
                  request_id,
                  requester_id=None,
                  exchange_order_id=None):
     try:
         self.client.cancel_order(symbol=base + quote,
                                  origClientOrderId=internal_order_id)
         message = dict()
         message['action'] = 'cancel_sent'
         message['internal_order_id'] = internal_order_id
         message['request_id'] = request_id
         message['exchange'] = self.name
         self.user_data_service.pending_cancel[internal_order_id] = True
         self.notify_callbacks('trade_lifecycle',
                               trade_lifecycle_type='cancel_sent',
                               data=message)
     except BinanceAPIException as e:
         logger().error(
             'Failed to cancel order. Exception was: {}'.format(e))
         if str(e.code) == '-2011':
             self.notify_callbacks('trade_lifecycle',
                                   data={
                                       'action':
                                       'CANCEL_FAILED',
                                       'reason':
                                       'order_not_found',
                                       'base':
                                       base,
                                       'quote':
                                       quote,
                                       'exchange':
                                       self.name,
                                       'exchange_order_id':
                                       exchange_order_id,
                                       'internal_order_id':
                                       internal_order_id,
                                       'order_status':
                                       'UNKNOWN',
                                       'server_ms':
                                       int(round(time.time() * 1000)),
                                       'received_ms':
                                       int(round(time.time() * 1000))
                                   })
Exemplo n.º 7
0
 def cancel_all(self, base, quote):
     market = base + '/' + quote
     exchange_orders, error = self.client.get_openorders(market)
     for exchange_order in exchange_orders:
         try:
             exchange_order_id = str(exchange_order['OrderId'])
             resp, error = self.client.cancel_trade('Trade',
                                                    exchange_order_id, None)
             if exchange_order_id in self.open_orders_by_exchange_id:
                 self.open_orders_by_exchange_id.pop(
                     exchange_order_id, None)
                 internal_id = self.external_to_internal_id.pop(
                     exchange_order, None)
                 self.internal_to_external_id.pop(internal_id, None)
             if error is not None:
                 raise Exception(
                     'Failed to cancel order with reason: {}'.format(
                         str(error)))
         except Exception as e:
             traceback.print_exc(file=sys.stdout)
             logger().error('cancel_all failed with error: ' + str(e))
Exemplo n.º 8
0
    def on_tick(self):
        try:
            logger().info('tick')
            if len(self.callbacks) > 0 and len(self.markets_following) > 0:
                for market in self.markets_following.copy().values():
                    base = market['base']
                    quote = market['quote']
                    self._send_executions_to_cb(base, quote)
                    self._send_order_book_to_cb(base, quote)
            else:
                logger().info('Not following any markets')
        except Exception as e:
            traceback.print_exc(file=sys.stdout)
            logger().error('on_tick failed with error: ' + str(e))

        logger().info('tock')

        threading.Timer(self.poll_time_s, self.on_tick).start()
    def get_fees_paid(self, base, quote, start_s, end_s):
        if start_s > end_s:
            logger().error('Start time cannot be after end time')
            return Decimal(0)

        product_id = self.get_product_id(base, quote)
        response = self.client.get_orders(product_id=product_id, limit=100)
        # Find start page via binary search

        total_pages = self.find_actual_total_pages(product_id,
                                                   response['total_pages'],
                                                   response['total_pages'] + 1,
                                                   0)

        first_page = self.find_first_or_last_page_of_orders(
            product_id, int(total_pages / 2), start_s, end_s, 'first',
            total_pages)
        if first_page == -1:
            logger().warn(
                'Unable to find any orders on or after epoch time: {}'.format(
                    start_s))
            return Decimal('0')

        last_page = self.find_first_or_last_page_of_orders(
            product_id, int(total_pages / 2), start_s, end_s, 'last',
            total_pages)
        if last_page == -1:
            logger().warn(
                'Unable to find any orders on or before epoch time: {}'.format(
                    end_s))
            return Decimal('0')

        # Request all pages in range [start, end]
        orders_in_range_with_fills = []
        for page in range(first_page, last_page + 1):
            response = self.client.get_orders(product_id=product_id,
                                              page=page,
                                              limit=100)
            orders = response['models']
            for order in orders:
                if start_s <= order['created_at'] <= end_s and order[
                        'filled_quantity'] != '0.0':
                    orders_in_range_with_fills.append(order)

        fees_in_quote_currency = Decimal('0')
        for order in orders_in_range_with_fills:
            fees_in_quote_currency += order['order_fee']

        return fees_in_quote_currency
    def on_tick(self):
        logger().info('tick')

        if len(self.callbacks) > 0:
            for product_id, details in self.markets_following.copy().items():
                try:
                    base = details['base']
                    quote = details['quote']

                    self._send_executions_to_cb(base, quote)
                    self._send_order_book_to_cb(base, quote)
                except Exception as e:
                    traceback.print_exc(file=sys.stdout)
                    logger().error('on_tick failed with error: ' + str(e))

        logger().info('tock')
        if len(self.markets_following) > 0:
            threading.Timer(self.poll_time_s, self.on_tick).start()
Exemplo n.º 11
0
    def on_private(self, msg):
        try:
            if 'TY' in msg:
                update_type = msg['TY']
                if update_type == 1 or update_type == 2:
                    order = msg['o']
                    market = order['E']
                    base, quote = ExecutionsSocket.to_base_quote(market)

                    if market in self.markets_following:
                        exchange_order_id = str(order['OU'])
                        internal_order = self.owner.get_order_by_exchange_id(
                            exchange_order_id)
                        if internal_order is not None:
                            quantity = Decimal(str(order['Q']))
                            quantity_remaining = Decimal(str(order['q']))
                            price = str(order['PU'])
                            if update_type == 1:
                                status = 'PARTIALLY_FILLED'
                            else:
                                status = 'FILLED'
                            new_fill_amount = str(
                                quantity - quantity_remaining - Decimal(
                                    str(internal_order['cum_quantity_filled']))
                            )
                            internal_order['cum_quantity_filled'] = str(
                                Decimal(str(internal_order['quantity'])) -
                                quantity_remaining)
                            message = {
                                'action':
                                'EXECUTION',
                                'exchange':
                                self.owner.name,
                                'base':
                                base,
                                'quote':
                                quote,
                                'exchange_order_id':
                                str(internal_order['exchange_order_id']),
                                'internal_order_id':
                                str(internal_order['internal_order_id']),
                                'side':
                                internal_order['side'],
                                'quantity':
                                internal_order['quantity'],
                                'price':
                                internal_order['price'],
                                'cum_quantity_filled':
                                internal_order['cum_quantity_filled'],
                                'order_status':
                                status,
                                'server_ms':
                                int(round(time() * 1000)),
                                'received_ms':
                                int(round(time() * 1000)),
                                'last_executed_quantity':
                                new_fill_amount,
                                'last_executed_price':
                                price,
                                'fee_base':
                                0,
                                'fee_quote':
                                0,
                                'trade_id':
                                '-1'
                            }

                            if status == 'FILLED':
                                index_to_del = None
                                i = 0

                                for order in self.owner.open_orders:
                                    if order[
                                            'exchange_order_id'] == exchange_order_id:
                                        index_to_del = i
                                        break
                                    i += 1

                                if index_to_del is not None:
                                    self.owner.open_orders.pop(index_to_del)

                            self.owner.notify_callbacks(
                                'trade_lifecycle',
                                trade_lifecycle_type=message['action'],
                                data=message)
                        else:
                            logger().error(
                                'Failed to get order with exchange id: ' +
                                exchange_order_id)
        except Exception as e:
            traceback.print_exc(file=sys.stdout)
            logger().error('bittrex execution socket failed with error: ' +
                           str(e))
    def create_order(self,
                     base,
                     quote,
                     price,
                     quantity,
                     side,
                     order_type,
                     internal_order_id,
                     request_id=None,
                     requester_id=None,
                     **kwargs):
        product_id = self.get_product_id(base, quote)
        if product_id is None:
            raise LookupError(
                'Could not find a product with a base [{}] and quote [{}]'.
                format(base, quote))

        try:
            exchange_side = self.client.SIDE_BUY if str.lower(
                side) == 'buy' else self.client.SIDE_SELL
            response = self.client.create_order(order_type,
                                                product_id,
                                                exchange_side,
                                                str(quantity),
                                                price=str(price))

            if ('message' in response and len(response['message']) > 0) or \
                    ('errors' in response and len(response['errors']) > 0):
                self.notify_callbacks('trade_lifecycle',
                                      data={
                                          'action':
                                          'CREATE_FAILED',
                                          'reason':
                                          'Unknown exception type',
                                          'exchange':
                                          self.name,
                                          'base':
                                          base,
                                          'quote':
                                          quote,
                                          'internal_order_id':
                                          str(internal_order_id),
                                          'side':
                                          side,
                                          'quantity':
                                          quantity,
                                          'price':
                                          price,
                                          'cum_quantity_filled':
                                          0,
                                          'received_ms':
                                          int(round(time.time() * 1000))
                                      })
                return
        except QuoineAPIException as e:
            logger().error('Failed to create order due to error: {}'.format(e))
            self.notify_callbacks('trade_lifecycle',
                                  data={
                                      'action': 'CREATE_FAILED',
                                      'reason': 'Unknown exception type',
                                      'exchange': self.name,
                                      'base': base,
                                      'quote': quote,
                                      'internal_order_id':
                                      str(internal_order_id),
                                      'side': side,
                                      'quantity': quantity,
                                      'price': price,
                                      'cum_quantity_filled': 0,
                                      'received_ms':
                                      int(round(time.time() * 1000))
                                  })
            return

        self.internal_to_external_id[str(internal_order_id)] = str(
            response['id'])
        self.external_to_internal_id[str(
            response['id'])] = str(internal_order_id)

        internal_response = {
            'action': 'CREATED',
            'exchange': self.name,
            'base': base,
            'quote': quote,
            'exchange_order_id': str(response['id']),
            'internal_order_id': str(internal_order_id),
            'side': side,
            'quantity': Decimal(str(quantity)),
            'price': Decimal(str(price)),
            'cum_quantity_filled': Decimal('0'),
            'order_status': 'OPEN',
            'server_ms': response['created_at'] * 1000,
            'received_ms': int(round(time.time() * 1000))
        }
        self.open_orders_by_exchange_id[str(
            response['id'])] = internal_response
        self.notify_callbacks('trade_lifecycle', data=internal_response)
    def cancel_order(self,
                     base,
                     quote,
                     internal_order_id,
                     request_id,
                     requester_id=None,
                     exchange_order_id=None):
        try:
            if exchange_order_id is None:
                exchange_order_id = self.get_exchange_id(internal_order_id)
        except LookupError:
            self.notify_callbacks('trade_lifecycle',
                                  data={
                                      'action': 'CANCEL_FAILED',
                                      'base': base,
                                      'quote': quote,
                                      'reason': 'order_not_found',
                                      'exchange': self.name,
                                      'exchange_order_id':
                                      str(exchange_order_id),
                                      'internal_order_id':
                                      str(internal_order_id),
                                      'order_status': 'UNKNOWN',
                                      'server_ms':
                                      int(round(time.time() * 1000)),
                                      'received_ms':
                                      int(round(time.time() * 1000))
                                  })
            return

        try:
            response = self.client.cancel_order(exchange_order_id)

            if ('message' in response and len(response['message']) > 0) or \
                    ('errors' in response and len(response['errors']) > 0):
                self.notify_callbacks('trade_lifecycle',
                                      data={
                                          'action':
                                          'CANCEL_FAILED',
                                          'reason':
                                          'order_not_found',
                                          'base':
                                          base,
                                          'quote':
                                          quote,
                                          'exchange':
                                          self.name,
                                          'exchange_order_id':
                                          str(exchange_order_id),
                                          'internal_order_id':
                                          str(internal_order_id),
                                          'order_status':
                                          'UNKNOWN',
                                          'server_ms':
                                          int(round(time.time() * 1000)),
                                          'received_ms':
                                          int(round(time.time() * 1000))
                                      })
                self.internal_to_external_id.pop(str(internal_order_id), None)
                self.external_to_internal_id.pop(str(exchange_order_id), None)
                self.open_orders_by_exchange_id.pop(str(exchange_order_id),
                                                    None)
                return
        except QuoineAPIException as e:
            logger().error('Failed to cancel order with error: {}'.format(e))
            self.notify_callbacks('trade_lifecycle',
                                  data={
                                      'action': 'CANCEL_FAILED',
                                      'reason': 'Unknown exception type',
                                      'base': base,
                                      'quote': quote,
                                      'exchange': self.name,
                                      'exchange_order_id':
                                      str(exchange_order_id),
                                      'internal_order_id':
                                      str(internal_order_id),
                                      'order_status': 'UNKNOWN',
                                      'server_ms':
                                      int(round(time.time() * 1000)),
                                      'received_ms':
                                      int(round(time.time() * 1000))
                                  })
            # If fails due to "already closed" or "not found", then popping is fine
            # TODO - If it fails due to a rate limit, we probably don't want this here?
            self.internal_to_external_id.pop(str(internal_order_id), None)
            self.external_to_internal_id.pop(str(exchange_order_id), None)
            self.open_orders_by_exchange_id.pop(str(exchange_order_id), None)
            return

        self.internal_to_external_id.pop(str(internal_order_id), None)
        self.external_to_internal_id.pop(str(exchange_order_id), None)
        self.open_orders_by_exchange_id.pop(str(exchange_order_id), None)

        time.sleep(2)

        self.notify_callbacks('trade_lifecycle',
                              data={
                                  'action': 'CANCELED',
                                  'exchange': self.name,
                                  'base': base,
                                  'quote': quote,
                                  'exchange_order_id': str(exchange_order_id),
                                  'internal_order_id': str(internal_order_id),
                                  'order_status': 'CANCELED',
                                  'server_ms': int(round(time.time() * 1000)),
                                  'received_ms': int(round(time.time() * 1000))
                              })
Exemplo n.º 14
0
    def cancel_order(self,
                     base,
                     quote,
                     internal_order_id,
                     request_id,
                     requester_id=None,
                     exchange_order_id=None):
        try:
            if exchange_order_id is None:
                exchange_order_id = self.get_exchange_id(internal_order_id)
        except LookupError:
            self.notify_callbacks('trade_lifecycle',
                                  data={
                                      'action': 'CANCEL_FAILED',
                                      'reason': 'order_not_found',
                                      'base': base,
                                      'quote': quote,
                                      'exchange': self.name,
                                      'exchange_order_id':
                                      str(exchange_order_id),
                                      'internal_order_id':
                                      str(internal_order_id),
                                      'order_status': 'UNKNOWN',
                                      'server_ms':
                                      int(round(time.time() * 1000)),
                                      'received_ms':
                                      int(round(time.time() * 1000))
                                  })
            return

        resp, error = self.client.cancel_trade('Trade', exchange_order_id,
                                               None)

        if error is not None:
            logger().error(
                'Failed to cancel order with error: {}'.format(error))
            reason = str(error)
            if error == 'No matching trades found':
                reason = 'order_not_found'
                self.internal_to_external_id.pop(str(internal_order_id), None)
                self.external_to_internal_id.pop(str(exchange_order_id), None)
                self.open_orders_by_exchange_id.pop(str(exchange_order_id),
                                                    None)

            self.notify_callbacks('trade_lifecycle',
                                  data={
                                      'action': 'CANCEL_FAILED',
                                      'reason': reason,
                                      'base': base,
                                      'quote': quote,
                                      'exchange': self.name,
                                      'exchange_order_id':
                                      str(exchange_order_id),
                                      'internal_order_id':
                                      str(internal_order_id),
                                      'order_status': 'UNKNOWN',
                                      'server_ms':
                                      int(round(time.time() * 1000)),
                                      'received_ms':
                                      int(round(time.time() * 1000))
                                  })

            return

        self.internal_to_external_id.pop(str(internal_order_id), None)
        self.external_to_internal_id.pop(str(exchange_order_id), None)
        self.open_orders_by_exchange_id.pop(str(exchange_order_id), None)

        time.sleep(2)

        self.notify_callbacks('trade_lifecycle',
                              data={
                                  'action': 'CANCELED',
                                  'exchange': self.name,
                                  'base': base,
                                  'quote': quote,
                                  'exchange_order_id': str(exchange_order_id),
                                  'internal_order_id': str(internal_order_id),
                                  'order_status': 'CANCELED',
                                  'server_ms': int(round(time.time() * 1000)),
                                  'received_ms': int(round(time.time() * 1000))
                              })
Exemplo n.º 15
0
    def create_order(self,
                     base,
                     quote,
                     price,
                     quantity,
                     side,
                     order_type,
                     internal_order_id,
                     request_id=None,
                     requester_id=None,
                     **kwargs):
        market = base + '/' + quote
        response, error = self.client.submit_trade(market, side, str(price),
                                                   str(quantity))

        if error is not None:
            self.notify_callbacks('trade_lifecycle',
                                  data={
                                      'action': 'CREATE_FAILED',
                                      'reason': 'Unknown exception type',
                                      'exchange': self.name,
                                      'base': base,
                                      'quote': quote,
                                      'internal_order_id':
                                      str(internal_order_id),
                                      'side': side,
                                      'quantity': quantity,
                                      'price': price,
                                      'cum_quantity_filled': 0,
                                      'received_ms':
                                      int(round(time.time() * 1000))
                                  })
            logger().error(
                'Failed to create cryptopia order with error: {}'.format(
                    str(error)))
            return

        exchange_order_id = response['OrderId']

        self.internal_to_external_id[str(internal_order_id)] = str(
            exchange_order_id)
        self.external_to_internal_id[str(exchange_order_id)] = str(
            internal_order_id)

        internal_response = {
            'action': 'CREATED',
            'exchange': self.name,
            'base': base,
            'quote': quote,
            'exchange_order_id': str(exchange_order_id),
            'internal_order_id': str(internal_order_id),
            'side': side,
            'quantity': Decimal(str(quantity)),
            'price': Decimal(str(price)),
            'cum_quantity_filled': Decimal('0'),
            'order_status': 'OPEN',
            'server_ms': int(round(time.time() * 1000)),
            'received_ms': int(round(time.time() * 1000))
        }
        self.open_orders_by_exchange_id[str(
            exchange_order_id)] = internal_response
        self.notify_callbacks('trade_lifecycle', data=internal_response)
Exemplo n.º 16
0
    def __process_user_data(self, event):
        try:
            if event['e'] == 'executionReport':
                symbol = event['s']
                base = symbol[0:3]
                quote = symbol[3:]  # TODO - Do this properly, so SALT/USDT would work
                message = {
                    'action': 'UNKNOWN',
                    'exchange': self.name,
                    'symbol': event['s'],
                    'base': base,
                    'quote': quote,
                    'exchange_order_id': event['i'],
                    'internal_order_id': event['c'],
                    'side': str.lower(event['S']),
                    'quantity': event['q'],
                    'price': event['p'],
                    'cum_quantity_filled': event['z'],
                    'order_status': event['X'],
                    'server_ms': event['T'],
                    'received_ms': int(round(time.time() * 1000))
                }

                if event['x'] == 'TRADE':
                    message['action'] = 'EXECUTION'
                    message['last_executed_quantity'] = event['l']
                    message['last_executed_price'] = event['L']
                    message['trade_id'] = event['t']

                    # TODO Check this logic is correct (both symbol split and if fee is an amount or a percent)
                    commission_amount = event['n']
                    commission_asset = event['N']

                    if commission_asset == base:
                        fee_base = Decimal(commission_amount)
                        fee_quote = Decimal('0')
                        message['fee_base'] = fee_base
                        message['fee_quote'] = fee_quote
                    if commission_asset == quote:
                        fee_base = Decimal('0')
                        fee_quote = Decimal(commission_amount)
                        message['fee_base'] = fee_base
                        message['fee_quote'] = fee_quote

                    if message['cum_quantity_filled'] == message['quantity']:
                        self.open_orders.pop(message['exchange_order_id'], None)
                        self.pending_cancel.pop(message['internal_order_id'], None)
                        self.internal_to_external_id.pop(message['internal_order_id'], None)
                elif event['x'] == 'NEW':
                    self.open_orders[message['exchange_order_id']] = message
                    self.internal_to_external_id[message['internal_order_id']] = message['exchange_order_id']
                    message['action'] = 'CREATED'
                elif event['x'] == 'CANCELED':
                    self.open_orders.pop(message['exchange_order_id'], None)
                    self.pending_cancel.pop(message['internal_order_id'], None)
                    self.internal_to_external_id.pop(message['internal_order_id'], None)
                    message['action'] = 'CANCELED'
                elif event['x'] == 'REJECTED':
                    message['action'] = 'REJECTED'
                    # TODO map to internal error code
                    message['rejected_reason'] = event['r']
                elif event['x'] == 'EXPIRED':
                    message['action'] = 'EXPIRED'

                self.callback('trade_lifecycle', trade_lifecycle_type=message['action'], data=message)
        except Exception as e:
            traceback.print_exc(file=sys.stdout)
            logger().error('__process_user_data failed with error: ' + str(e))