Пример #1
0
def _check_for_liquidations(candle: np.ndarray, exchange: str, symbol: str) -> None:
    p: Position = selectors.get_position(exchange, symbol)

    if not p:
        return

    # for now, we only support the isolated mode:
    if p.mode != 'isolated':
        return

    if candle_includes_price(candle, p.liquidation_price):
        closing_order_side = jh.closing_side(p.type)

        # create the market order that is used as the liquidation order
        order = Order({
            'id': jh.generate_unique_id(),
            'symbol': symbol,
            'exchange': exchange,
            'side': closing_order_side,
            'type': order_types.MARKET,
            'flag': order_flags.REDUCE_ONLY,
            'qty': jh.prepare_qty(p.qty, closing_order_side),
            'price': p.bankruptcy_price,
            'role': order_roles.CLOSE_POSITION
        })

        store.orders.add_order(order)

        store.app.total_liquidations += 1

        logger.info(f'{p.symbol} liquidated at {p.liquidation_price}')

        order.execute()
Пример #2
0
    def _on_updated_position(self, order: Order) -> None:
        """
        Handles the after-effect of the executed order

        Note that it assumes that the position has already been affected
        by the executed order.

        Arguments:
            order {Order} -- the executed order object
        """
        role = order.role

        if role == order_roles.OPEN_POSITION and abs(self.position.qty) != abs(
                order.qty):
            order.role = order_roles.INCREASE_POSITION
            role = order_roles.INCREASE_POSITION

        if role == order_roles.CLOSE_POSITION and self.position.is_open:
            order.role = order_roles.REDUCE_POSITION
            role = order_roles.REDUCE_POSITION

        self._log_position_update(order, role)

        if role == order_roles.OPEN_POSITION:
            self._on_open_position(order)
        elif role == order_roles.CLOSE_POSITION and order in self._take_profit_orders:
            self._on_take_profit(order)
        elif role == order_roles.CLOSE_POSITION and order in self._stop_loss_orders:
            self._on_stop_loss(order)
        elif role == order_roles.INCREASE_POSITION:
            self._on_increased_position(order)
        elif role == order_roles.REDUCE_POSITION:
            self._on_reduced_position(order)
Пример #3
0
def fake_order(attributes=None):
    if attributes is None:
        attributes = {}

    global first_timestamp
    first_timestamp += 60000
    exchange = exchanges.SANDBOX
    symbol = 'BTCUSD'
    side = sides.BUY
    order_type = order_types.LIMIT
    price = randint(40, 100)
    qty = randint(1, 10)
    status = order_statuses.ACTIVE
    created_at = first_timestamp

    return Order({
        "id": jh.generate_unique_id(),
        'symbol': attributes.get('symbol', symbol),
        'exchange': attributes.get('exchange', exchange),
        'side': attributes.get('side', side),
        'type': attributes.get('type', order_type),
        'qty': attributes.get('qty', qty),
        'price': attributes.get('price', price),
        'status': attributes.get('status', status),
        'created_at': attributes.get('created_at', created_at),
    })
Пример #4
0
    def stop_order(self, symbol, qty, price, side, role, flags):
        """

        :param symbol:
        :param qty:
        :param price:
        :param side:
        :param role:
        :param flags:
        :return:
        """
        order = Order({
            'id': jh.generate_unique_id(),
            'symbol': symbol,
            'exchange': self.name,
            'side': side,
            'type': order_types.STOP,
            'flag': self.get_exec_inst(flags),
            'qty': jh.prepare_qty(qty, side),
            'price': price,
            'role': role
        })

        store.orders.add_order(order)

        return order
Пример #5
0
    def market_order(self, symbol, qty, current_price, side, role, flags):
        """

        :param symbol:
        :param qty:
        :param current_price:
        :param side:
        :param role:
        :param flags:
        :return:
        """
        order = Order({
            'id': jh.generate_unique_id(),
            'symbol': symbol,
            'exchange': self.name,
            'side': side,
            'type': order_types.MARKET,
            'flag': self.get_exec_inst(flags),
            'qty': jh.prepare_qty(qty, side),
            'price': current_price,
            'role': role
        })

        store.orders.add_order(order)

        store.orders.to_execute.append(order)

        return order
Пример #6
0
def test_cancel_order():
    order = Order({
        'id': jh.generate_unique_id(),
        'symbol': 'BTCUSD',
        'type': order_types.LIMIT,
        'price': 129.33,
        'qty': 10.2041,
        'side': sides.BUY,
        'status': order_statuses.ACTIVE,
        'created_at': jh.now(),
    })

    assert order.is_canceled is False

    order.cancel()

    assert order.is_canceled is True
    assert order.canceled_at == jh.now()
Пример #7
0
def test_cancel_order():
    set_up()

    order = Order({
        'id': jh.generate_unique_id(),
        'exchange': 'Sandbox',
        'symbol': 'BTC-USDT',
        'type': order_types.LIMIT,
        'price': 129.33,
        'qty': 10.2041,
        'side': sides.BUY,
        'status': order_statuses.ACTIVE,
        'created_at': jh.now_to_timestamp(),
    })

    assert order.is_canceled is False

    order.cancel()

    assert order.is_canceled is True
    assert order.canceled_at == jh.now_to_timestamp()
Пример #8
0
def test_execute_order():
    set_up_without_fee()

    order = Order({
        'id': jh.generate_unique_id(),
        'symbol': 'BTC-USDT',
        'exchange': exchange.name,
        'type': order_types.LIMIT,
        'price': 129.33,
        'qty': 10.2041,
        'side': sides.BUY,
        'status': order_statuses.ACTIVE,
        'created_at': jh.now_to_timestamp(),
    })

    assert order.is_executed is False
    assert order.executed_at is None

    order.execute()

    assert order.is_executed is True
    assert order.executed_at == jh.now_to_timestamp()
Пример #9
0
    def _on_updated_position(self, order: Order) -> None:
        """
        Handles the after-effect of the executed order

        Note that it assumes that the position has already been affected
        by the executed order.

        Arguments:
            order {Order} -- the executed order object
        """
        # in live-mode, sometimes order-update effects and new execution has overlaps, so:
        self._is_handling_updated_order = True

        role = order.role

        # if the order's role is CLOSE_POSITION but the position qty is not the same as this order's qty,
        # then it's increase_position order (because the position was already open before this)
        if self.trade and role == order_roles.OPEN_POSITION and abs(
                self.position.qty) != abs(order.qty):
            order.role = order_roles.INCREASE_POSITION
            role = order_roles.INCREASE_POSITION

        # if the order's role is CLOSE_POSITION but the position is still open, then it's reduce_position order
        if role == order_roles.CLOSE_POSITION and self.position.is_open:
            order.role = order_roles.REDUCE_POSITION
            role = order_roles.REDUCE_POSITION

        self._log_position_update(order, role)

        if role == order_roles.OPEN_POSITION:
            self._on_open_position(order)
        elif role == order_roles.CLOSE_POSITION:
            self._on_close_position(order)
        elif role == order_roles.INCREASE_POSITION:
            self._on_increased_position(order)
        elif role == order_roles.REDUCE_POSITION:
            self._on_reduced_position(order)

        self._is_handling_updated_order = False
Пример #10
0
    def limit_order(self, symbol, qty, price, side, role, flags):
        order = Order({
            'id': jh.generate_unique_id(),
            'symbol': symbol,
            'exchange': self.name,
            'side': side,
            'type': order_types.LIMIT,
            'flag': self.get_exec_inst(flags),
            'qty': jh.prepare_qty(qty, side),
            'price': price,
            'role': role
        })

        store.orders.add_order(order)

        return order
Пример #11
0
    def stop_order(self, symbol: str, qty: float, price: float, side: str, role: str, flags: list) -> Order:
        order = Order({
            'id': jh.generate_unique_id(),
            'symbol': symbol,
            'exchange': self.name,
            'side': side,
            'type': order_types.STOP,
            'flag': self.get_exec_inst(flags),
            'qty': jh.prepare_qty(qty, side),
            'price': price,
            'role': role
        })

        store.orders.add_order(order)

        return order
Пример #12
0
    def market_order(self, symbol: str, qty: float, current_price: float, side: str, role: str, flags: list) -> Order:
        order = Order({
            'id': jh.generate_unique_id(),
            'symbol': symbol,
            'exchange': self.name,
            'side': side,
            'type': order_types.MARKET,
            'flag': self.get_exec_inst(flags),
            'qty': jh.prepare_qty(qty, side),
            'price': current_price,
            'role': role
        })

        store.orders.add_order(order)

        store.orders.to_execute.append(order)

        return order
Пример #13
0
    def _log_position_update(self, order: Order, role: str) -> None:
        """
        A log can be either about opening, adding, reducing, or closing the position.

        Arguments:
            order {order} -- the order object
        """
        # set the trade_id for the order if we're in the middle of a trade. Otherwise, it
        # is done at order_roles.OPEN_POSITION
        if self.trade:
            order.trade_id = self.trade.id

        if role == order_roles.OPEN_POSITION:
            self.trade = CompletedTrade()
            self.trade.leverage = self.leverage
            self.trade.orders = [order]
            self.trade.timeframe = self.timeframe
            self.trade.id = jh.generate_unique_id()
            order.trade_id = self.trade.id
            self.trade.strategy_name = self.name
            self.trade.exchange = order.exchange
            self.trade.symbol = order.symbol
            self.trade.type = trade_types.LONG if order.side == sides.BUY else trade_types.SHORT
            self.trade.qty = order.qty
            self.trade.opened_at = jh.now_to_timestamp()
            self.trade.entry_candle_timestamp = self.current_candle[0]
        elif role == order_roles.INCREASE_POSITION:
            self.trade.orders.append(order)
            self.trade.qty += order.qty
        elif role == order_roles.REDUCE_POSITION:
            self.trade.orders.append(order)
            self.trade.qty += order.qty
        elif role == order_roles.CLOSE_POSITION:
            self.trade.exit_candle_timestamp = self.current_candle[0]
            self.trade.orders.append(order)

            # calculate average stop-loss price
            sum_price = 0
            sum_qty = 0
            if self._log_stop_loss is not None:
                for l in self._log_stop_loss:
                    sum_qty += abs(l[0])
                    sum_price += abs(l[0]) * l[1]
                self.trade.stop_loss_at = sum_price / sum_qty
            else:
                self.trade.stop_loss_at = np.nan

            # calculate average take-profit price
            sum_price = 0
            sum_qty = 0
            if self._log_take_profit is not None:
                for l in self._log_take_profit:
                    sum_qty += abs(l[0])
                    sum_price += abs(l[0]) * l[1]
                self.trade.take_profit_at = sum_price / sum_qty
            else:
                self.trade.take_profit_at = np.nan

            # calculate average entry_price price
            sum_price = 0
            sum_qty = 0
            for l in self.trade.orders:
                if not l.is_executed:
                    continue

                if jh.side_to_type(l.side) != self.trade.type:
                    continue

                sum_qty += abs(l.qty)
                sum_price += abs(l.qty) * l.price
            self.trade.entry_price = sum_price / sum_qty

            # calculate average exit_price
            sum_price = 0
            sum_qty = 0
            for l in self.trade.orders:
                if not l.is_executed:
                    continue

                if jh.side_to_type(l.side) == self.trade.type:
                    continue

                sum_qty += abs(l.qty)
                sum_price += abs(l.qty) * l.price
            self.trade.exit_price = sum_price / sum_qty

            self.trade.closed_at = jh.now_to_timestamp()
            self.trade.qty = pydash.sum_by(
                filter(lambda o: o.side == jh.type_to_side(self.trade.type),
                       self.trade.orders), lambda o: abs(o.qty))

            store.completed_trades.add_trade(self.trade)
            if jh.is_livetrading():
                store_completed_trade_into_db(self.trade)
            self.trade = None
            self.trades_count += 1

        if jh.is_livetrading():
            store_order_into_db(order)