예제 #1
0
def test_transfer():

    exchange = mock.Mock()
    price = Decimal(9750.19).quantize(Decimal(10)**-2)
    exchange.quote_price = lambda pair: price
    exchange.name = "bitfinex"

    order = mock.Mock()
    order.path_id = "fake_id"

    exchange_pair = ExchangePair(exchange, USD / BTC)

    source = Wallet(exchange, 18903.89 * USD)
    source.lock(917.07 * USD, order, "test")

    target = Wallet(exchange, 3.79283997 * BTC)

    quantity = (256.19 * USD).lock_for("fake_id")
    commission = (2.99 * USD).lock_for("fake_id")

    Wallet.transfer(source, target, quantity, commission, exchange_pair,
                    "transfer")

    source = Wallet(exchange, 3.79283997 * BTC)
    source.lock(3.00000029 * BTC, order, "test")

    target = Wallet(exchange, 18903.89 * USD)

    quantity = (2.19935873 * BTC).lock_for("fake_id")
    commission = (0.00659732 * BTC).lock_for("fake_id")

    Wallet.transfer(source, target, quantity, commission, exchange_pair,
                    "transfer")
예제 #2
0
def execute_sell_order(order: 'Order', base_wallet: 'Wallet',
                       quote_wallet: 'Wallet', current_price: float,
                       options: 'ExchangeOptions', clock: 'Clock') -> 'Trade':
    """Executes a sell order on the exchange.

    Parameters
    ----------
    order : `Order`
        The order that is being filled.
    base_wallet : `Wallet`
        The wallet of the base instrument.
    quote_wallet : `Wallet`
        The wallet of the quote instrument.
    current_price : float
        The current price of the exchange pair.
    options : `ExchangeOptions`
        The exchange options.
    clock : `Clock`
        The clock for the trading process..

    Returns
    -------
    `Trade`
        The executed trade that was made.
    """
    if order.type == TradeType.LIMIT and order.price > current_price:
        return None

    filled = order.remaining.contain(order.exchange_pair)

    commission = options.commission * filled
    quantity = filled - commission

    if commission.size < Decimal(10)**-quantity.instrument.precision:
        logging.warning(
            "Commission is less than instrument precision. Canceling order. "
            "Consider defining a custom instrument with a higher precision.")
        order.cancel("COMMISSION IS LESS THAN PRECISION.")
        return None

    # Transfer Funds from Quote Wallet to Base Wallet
    transfer = Wallet.transfer(source=quote_wallet,
                               target=base_wallet,
                               quantity=quantity,
                               commission=commission,
                               exchange_pair=order.exchange_pair,
                               reason="SELL")

    trade = Trade(order_id=order.id,
                  step=clock.step,
                  exchange_pair=order.exchange_pair,
                  side=TradeSide.SELL,
                  trade_type=order.type,
                  quantity=transfer.quantity,
                  price=transfer.price,
                  commission=transfer.commission)

    return trade
예제 #3
0
    def execute_buy_order(order: 'Order', base_wallet: 'Wallet',
                          quote_wallet: 'Wallet', current_price: float,
                          options: 'ExchangeOptions',
                          clock: 'Clock') -> 'Trade':
        """Executes a buy order on the exchange.

        Parameters
        ----------
        order : `Order`
            The order that is being filled.
        base_wallet : `Wallet`
            The wallet of the base instrument.
        quote_wallet : `Wallet`
            The wallet of the quote instrument.
        current_price : float
            The current price of the exchange pair.
        options : `ExchangeOptions`
            The exchange options.
        clock : `Clock`
            The clock for the trading process..

        Returns
        -------
        `Trade`
            The executed trade that was made.
        """
        if order.type == TradeType.LIMIT and order.price < current_price:
            return None

        filled = order.remaining.contain(order.exchange_pair)

        if order.type == TradeType.MARKET:
            scale = order.price / max(current_price, order.price)
            filled = scale * filled

        commission = options.commission * filled
        quantity = filled - commission

        if commission.size < Decimal(10)**-quantity.instrument.precision:
            logging.warning(
                "Commission is less than instrument precision. Canceling order. "
                "Consider defining a custom instrument with a higher precision."
            )
            order.cancel("COMMISSION IS LESS THAN PRECISION.")
            return None

        transfer = Wallet.transfer(source=base_wallet,
                                   target=quote_wallet,
                                   quantity=quantity,
                                   commission=commission,
                                   exchange_pair=order.exchange_pair,
                                   reason="BUY")

        trade = Trade(order_id=order.id,
                      step=clock.step,
                      exchange_pair=order.exchange_pair,
                      side=TradeSide.BUY,
                      trade_type=order.type,
                      quantity=transfer.quantity,
                      price=transfer.price,
                      commission=transfer.commission)

        # n_order = self.check_all_open_order(SIDE_BUY)
        # if n_order>0: print(' ======>> There are more than {} existing buy orders, not placing further order'.format(n_order))

        if self.isLive:
            order = self.client.create_order(symbol=order.exchange_pair,
                                             side=SIDE_BUY,
                                             type=ORDER_TYPE_LIMIT,
                                             timeInForce=TIME_IN_FORCE_GTC,
                                             quantity=transfer.quantity,
                                             price=transfer.price)

            print('  =============== Placing buy order ============== \n',
                  order)
        else:
            order = self.client.create_test_order(
                symbol=order.exchange_pair,
                side=SIDE_BUY,
                type=ORDER_TYPE_LIMIT,
                timeInForce=TIME_IN_FORCE_GTC,
                quantity=transfer.quantity,
                price=transfer.price)

            print('  =============== Placing test buy order ============== \n',
                  order)

        return trade
예제 #4
0
def execute_sell_order(order: 'Order', base_wallet: 'Wallet',
                       quote_wallet: 'Wallet', current_price: float,
                       options: 'ExchangeOptions', clock: 'Clock') -> 'Trade':
    """Executes a sell order on the exchange.

    Parameters
    ----------
    order : `Order`
        The order that is being filled.
    base_wallet : `Wallet`
        The wallet of the base instrument.
    quote_wallet : `Wallet`
        The wallet of the quote instrument.
    current_price : float
        The current price of the exchange pair.
    options : `ExchangeOptions`
        The exchange options.
    clock : `Clock`
        The clock for the trading process..

    Returns
    -------
    `Trade`
        The executed trade that was made.
    """
    if order.type == TradeType.LIMIT and order.price < current_price:
        return None

    filled = order.remaining.contain(order.exchange_pair)

    if order.type == TradeType.MARKET:
        scale = order.price / max(current_price, order.price)
        filled = scale * filled

    commission = options.commission * filled
    quantity = filled - commission

    if commission.size < Decimal(10)**-quantity.instrument.precision:
        logging.warning(
            "Commission is less than instrument precision. Canceling order. "
            "Consider defining a custom instrument with a higher precision.")
        order.cancel("COMMISSION IS LESS THAN PRECISION.")
        return None

    # Todo: Fill Order with Position-Data got by Broker
    if quantity.instrument == order.exchange_pair.pair.base:
        instrument = order.exchange_pair.pair.quote
        converted_size = quantity.size / order.price
    else:
        instrument = order.exchange_pair.pair.base
        converted_size = quantity.size * order.price
    converted = Quantity(instrument, converted_size,
                         quantity.path_id).quantize()
    position = Position(
        id=order.id,  # to be replaced by borker-id
        order=order,
        quantity=converted,
    )
    quote_wallet.add_position(position)

    transfer = Wallet.transfer(source=base_wallet,
                               target=quote_wallet,
                               quantity=quantity,
                               commission=commission,
                               exchange_pair=order.exchange_pair,
                               reason="SELL")

    trade = Trade(order_id=order.id,
                  step=clock.step,
                  exchange_pair=order.exchange_pair,
                  side=TradeSide.SELL,
                  trade_type=order.type,
                  quantity=transfer.quantity,
                  price=transfer.price,
                  commission=transfer.commission)

    return trade
예제 #5
0
def execute_buy_order(order: 'Order',
                      base_wallet: 'Wallet',
                      quote_wallet: 'Wallet',
                      current_price: float,
                      options: 'ExchangeOptions',
                      clock: 'Clock') -> 'Trade':
    """Executes a buy order on the exchange.

    Parameters
    ----------
    order : `Order`
        The order that is being filled.
    base_wallet : `Wallet`
        The wallet of the base instrument.
    quote_wallet : `Wallet`
        The wallet of the quote instrument.
    current_price : float
        The current price of the exchange pair.
    options : `ExchangeOptions`
        The exchange options.
    clock : `Clock`
        The clock for the trading process..

    Returns
    -------
    `Trade`
        The executed trade that was made.
    """
    if order.type == TradeType.LIMIT and order.price < current_price:
        return None

    filled = order.remaining.contain(order.exchange_pair)

    if order.type == TradeType.MARKET:
        scale = order.price / max(current_price, order.price)
        filled = scale * filled

    commission = options.commission * filled
    quantity = filled - commission

    if commission.size < Decimal(10)**-quantity.instrument.precision:
        order.cancel("COMMISSION IS LESS THAN PRECISION.")
        return None

    transfer = Wallet.transfer(
        source=base_wallet,
        target=quote_wallet,
        quantity=quantity,
        commission=commission,
        exchange_pair=order.exchange_pair,
        reason="BUY"
    )

    trade = Trade(
        order_id=order.id,
        step=clock.step,
        exchange_pair=order.exchange_pair,
        side=TradeSide.BUY,
        trade_type=order.type,
        quantity=transfer.quantity,
        price=transfer.price,
        commission=transfer.commission
    )

    return trade
예제 #6
0
    def get_orders(self, action: int, portfolio: 'Portfolio') -> 'List[Order]':

        # HOLD Action
        if action == 0:
            return []

        #(ep, (criteria, proportion, duration, side)) = self.actions[action]
        #ep = self.actions[action][0]
        #(criteria, proportion, duration, side) = self.actions[action][1]
        ep, side = self.actions[action]

        # Empty Orders List
        orders = []

        # check different action
        if (action != self.action):
            # proportion of used balance
            proportion = 1
            duration = None
            criteria = None
            # get base/quote wallets
            quote_wallet = portfolio.get_wallet(ep.exchange.id,
                                                instrument=ep.pair.quote)
            base_wallet = portfolio.get_wallet(ep.exchange.id,
                                               instrument=ep.pair.base)

            # get current price
            price = ep.price

            # create orders to close all already open-position
            positions = quote_wallet.get_positions().values(
            )  # avoid RuntimeError: dictionary changed size during iteration, when remove position from dict.
            for position in positions:
                if position.is_open:
                    #close positions based on last opened orders
                    #quantity = Quantity(instrument=ep.pair.quote, size=position.quantity.size)
                    # adjut worth quantity - if sell-position already open
                    quantity = Quantity(instrument=ep.pair.quote,
                                        size=position.get_worth_quantity())
                    position.is_locked = True
                    order = Order(path_id=position.id,
                                  step=self.clock.step,
                                  side=TradeSide.CLOSE,
                                  trade_type=self._trade_type,
                                  exchange_pair=ep,
                                  price=ep.price,
                                  quantity=quantity,
                                  criteria=criteria,
                                  end=self.clock.step +
                                  duration if duration else None,
                                  portfolio=portfolio)

                    # Transfer Funds from Quote Wallet to Base Wallet
                    transfer = Wallet.transfer(
                        source=quote_wallet,
                        target=base_wallet,
                        quantity=order.quantity,
                        commission=Quantity(instrument=ep.pair.quote, size=0),
                        exchange_pair=order.exchange_pair,
                        reason="CLOSE")
                    self.broker.submit(order)
                    self.broker.update()

            if side != TradeSide.CLOSE:
                # return money to base-wallets
                instrument = side.instrument(ep.pair)

                balance = base_wallet.balance.as_float()
                size = (balance * proportion)
                size = min(balance, size)

                quantity = (size * instrument).quantize()

                value = size * float(price)
                if size < 10 ** -instrument.precision \
                        or value < self.min_order_pct*portfolio.net_worth:
                    return []

                order = Order(step=self.clock.step,
                              side=side,
                              trade_type=self._trade_type,
                              exchange_pair=ep,
                              price=ep.price,
                              quantity=quantity,
                              criteria=criteria,
                              end=self.clock.step +
                              duration if duration else None,
                              portfolio=portfolio)
                orders.append(order)

                if self._order_listener is not None:
                    order.attach(self._order_listener)

            # TODO: Check a way to check: check only when order is completed
            self.action = action

        return orders