Exemple #1
0
    def cancel_order(self, order_id):
        is_instance(order_id, (str, ))
        passes_test(order_id, lambda x: int(x))

        # NOTE: OKEX doesn't provide a way of getting all orders from any
        #       symbol pair. We need to loop through all of them until we find it.
        order = None
        for symbol_pair in currencies.SYMBOL_PAIRS:
            orders = self.get_open_orders(symbol_pair=symbol_pair)
            orders = [
                order for order in orders if int(order.id) == int(order_id)
            ]
            if orders:
                # found order in current symbol pair, no need to keep iterating
                order = orders[0]
                break

        if not order:
            raise ValueError(
                'Could not find order with ID "{}"'.format(order_id))

        path = '/v1/future_cancel.do'
        params = {
            'symbol': order.symbol_pair,
            'contract_type': 'quarter',
            'order_id': int(order_id),
        }
        params['api_key'] = self.api_key
        params['sign'] = self._sign_params(params)
        return self._post(path, params=params)
Exemple #2
0
def volume_weighted_average_price(action, order_book, amount):
    """
    Calculates the weighted average price of an operation (sell/buy)
    for a given `amount` and `order_book`.

    @params:
        * action: exchanges.ACTIONS choice
        * order_book: models.base.OrderBook instance or subclass
        * amount: Decimal or valid numeric argument representing volume to operate.

    @returns:
        a Decimal object representing the weighted average price.
    """
    # validate arguments
    is_restricted_to_values(action, exchanges.ACTIONS)

    is_instance(amount, (Decimal, float, int, str))
    passes_test(amount, lambda x: Decimal(x))

    order_list = order_book.asks if action == exchanges.BUY else order_book.bids

    total_market_depth = sum([t[1] for t in order_list])
    if amount > total_market_depth:
        raise exceptions.InsufficientMarketDepth(
            'Not enough depth in OrderBook to {} {} volume'.format(
                action, amount))

    if action == exchanges.BUY:
        # when checking the "asks" list, we want to
        # iterate orders from cheapest to highest
        order_list = list(reversed(order_list))
    accum = Decimal(0.0)

    # most of the times last used order in the orderbook
    # is partially used. we need to know which was the portion
    # used from that order to calculate the weighted average
    rest = amount

    for index, price_tuple in enumerate(order_list):
        volume = price_tuple[1]
        accum += volume
        if accum >= amount:
            break
        rest -= volume

    # get the sub list representing only the necessary
    # orders to fulfill the amount amount
    sub_list = order_list[:index + 1]

    # change the last used order in the list, to just
    # the needed rest amount
    sub_list[-1] = (sub_list[-1][0], Decimal(rest))

    sub_list_amounts = [t[1] for t in sub_list]
    return sum(x * y for x, y in sub_list) / sum(sub_list_amounts)
Exemple #3
0
    def open_order(self, action, amount, symbol_pair, price, order_type):
        """
        Creates a new Order.

        :action:
            exchanges.ACTIONS choice
        :amount:
            Decimal, float, integer or string representing number value.
        :symbol_pair:
            currencies.SYMBOL_PAIRS choice
        :price:
            Decimal, float, integer or string representing number value.
        :order_type:
            exchanges.ORDER_TYPES choice
        """
        # validate arguments
        is_restricted_to_values(action, exchanges.ACTIONS)

        is_instance(amount, (Decimal, float, int, str))
        passes_test(amount, lambda x: Decimal(x))

        is_restricted_to_values(symbol_pair, currencies.SYMBOL_PAIRS)

        is_instance(price, (Decimal, float, int, str))
        passes_test(price, lambda x: isinstance(Decimal(x), Decimal))

        is_restricted_to_values(order_type, exchanges.ORDER_TYPES)

        path = '/0/private/AddOrder'
        userref = self.get_userref(symbol_pair)
        symbol_pair = self.SYMBOLS_MAPPING[symbol_pair]
        payload = {
            'pair': symbol_pair,
            'type': action,
            'ordertype': order_type,
            'price': Decimal(str(price)),
            'volume': Decimal(str(amount)),
            'leverage': 2,
            'nonce': int(1000 * time.time()),
            'userref': userref,
        }
        headers = {
            'API-Key': self.api_key,
            'API-Sign': self._sign_payload(path, payload)
        }
        return self._post(path,
                          headers=headers,
                          body=payload,
                          transformation=self._transform_new_order,
                          model_class=KrakenOrder)
Exemple #4
0
    def open_order(self, action, amount, symbol_pair, price, order_type,
                   **kwargs):
        """
        Creates a new Order.

        :action:
            exchanges.ACTIONS choice
        :amount:
            Decimal, float, integer or string representing number value.
        :symbol_pair:
            currencies.SYMBOL_PAIRS choice
        :price:
            Decimal, float, integer or string representing number value.
        :order_type:
            exchanges.ORDER_TYPES choice
        """
        # validate arguments
        is_restricted_to_values(action, exchanges.ACTIONS)

        is_instance(amount, (Decimal, float, int, str))
        passes_test(amount, lambda x: Decimal(x))

        is_restricted_to_values(symbol_pair, currencies.SYMBOL_PAIRS)

        is_instance(price, (Decimal, float, int, str))
        passes_test(price, lambda x: isinstance(Decimal(x), Decimal))

        is_restricted_to_values(order_type, exchanges.ORDER_TYPES)

        path = '/v1/order/new'
        symbol_pair = self.SYMBOLS_MAPPING[symbol_pair]
        payload = {
            'request': path,
            'nonce': str(time.time()),
            'side': action,
            'amount': str(amount),
            'symbol': symbol_pair,
            'price': str(price),
            'type': order_type,
        }
        signed_payload = self._sign_payload(payload)
        return self._post(path,
                          headers=signed_payload,
                          model_class=BitfinexOrder,
                          **kwargs)
Exemple #5
0
def worst_order_price(action, order_book, amount):
    """
    Calculates the worst used order price in given `order_book` to fulfill
    an operation (sell/buy) of the given `amount`.

    @params:
        * action: exchanges.ACTIONS choice
        * order_book: models.base.OrderBook instance or subclass
        * amount: Decimal or valid numeric argument representing volume to operate.

    @returns:
        a Decimal object representing the worst order price.
    """
    # validate arguments
    is_restricted_to_values(action, exchanges.ACTIONS)

    is_instance(amount, (Decimal, float, int, str))
    passes_test(amount, lambda x: Decimal(x))

    order_list = order_book.asks if action == exchanges.BUY else order_book.bids

    total_market_depth = sum([t[1] for t in order_list])
    if amount > total_market_depth:
        raise exceptions.InsufficientMarketDepth(
            'Not enough depth in OrderBook to {} {} volume'.format(
                action, amount))

    if action == exchanges.BUY:
        # when checking the "asks" list, we want to
        # iterate orders from cheapest to highest
        order_list = list(reversed(order_list))

    accum = Decimal('0')
    for price_tuple in order_list:
        price, volume = price_tuple
        accum += volume
        if accum >= amount:
            return price
Exemple #6
0
    def open_order(self,
                   action,
                   amount,
                   symbol_pair,
                   price,
                   order_type,
                   amount_in_contracts=False,
                   closing=False):
        """
        Creates a new Order.

        :action:
            exchanges.ACTIONS choice
        :amount:
            Decimal, float, integer or string representing number value.
            If `amount_in_contracts == True`, `amount` needs to be an
            integer number greater or equal to 1.
        :symbol_pair:
            currencies.SYMBOL_PAIRS choice
        :price:
            Decimal, float, integer or string representing number value.
        :order_type:
            exchanges.ORDER_TYPES choice
        :amount_in_contracts:
            (True|False) Whether the `amount`  argument is expressed in cryptos or contracts
        :closing:
            (True|False) Whether the order we are opening is to close an existing position or not
        """
        # validate arguments
        is_restricted_to_values(action, exchanges.ACTIONS)

        is_instance(amount, (Decimal, float, int, str))
        passes_test(amount, lambda x: Decimal(x))
        if amount_in_contracts:
            passes_test(amount, lambda x: Decimal(x) >= 1)

        is_restricted_to_values(symbol_pair, currencies.SYMBOL_PAIRS)

        is_instance(price, (Decimal, float, int, str))
        passes_test(price, lambda x: Decimal(x))

        is_restricted_to_values(order_type, exchanges.ORDER_TYPES)

        is_instance(amount_in_contracts, bool)
        is_instance(closing, bool)

        path = '/v1/future_trade.do'
        symbol_pair = self.SYMBOLS_MAPPING[symbol_pair]
        if closing:
            action = (self.ACTION['close_long'] if action == exchanges.SELL
                      else self.ACTION['close_short'])
        else:
            action = (self.ACTION['open_short'] if action == exchanges.SELL
                      else self.ACTION['open_long'])

        if not amount_in_contracts:
            amount = crypto_to_contracts(
                amount,
                getattr(self, '{}_ticker'.format(symbol_pair)).last,
                self.CONTRACT_UNIT_AMOUNTS[symbol_pair])

        match_price = 1 if order_type == 'market' else 0
        params = {
            'symbol': symbol_pair,
            'contract_type': 'quarter',
            'price': float(Decimal(price)),
            'match_price': match_price,  # if market, 'price' field is ignored
            'amount': int(amount),  # in contracts
            'type': action,
            'lever_rate': 10,  # default
        }
        params['api_key'] = self.api_key
        params['sign'] = self._sign_params(params)
        return self._post(path, params=params, model_class=OkexOrder)