예제 #1
0
 def on_fill_actions(self):
     self.taker_or_maker = ExchangeConstantsMarketPropertyColumns.TAKER.value
     self.origin_price = self.created_last_price
     self.filled_price = self.created_last_price
     self.filled_quantity = self.origin_quantity
     self.total_cost = self.filled_price * self.filled_quantity
     Order.on_fill_actions(self)
예제 #2
0
    async def cancel_order(self,
                           order: Order,
                           is_cancelled_from_exchange: bool = False,
                           ignored_order: Order = None):
        """
        Cancels the given order and its linked orders, and updates the portfolio, publish in order channel
        if order is from a real exchange.
        :param order: Order to cancel
        :param is_cancelled_from_exchange: When True, will not try to cancel this order on real exchange
        :param ignored_order: Order not to cancel if found in linked orders recursive cancels (ex: avoid cancelling
        a filled order)
        :return: None
        """
        if order and not order.is_cancelled() and not order.is_filled():
            async with order.lock:
                # always cancel this order first to avoid infinite loop followed by deadlock
                order.cancel_order()
                for linked_order in order.linked_orders:
                    if linked_order is not ignored_order:
                        await self.cancel_order(linked_order,
                                                ignored_order=ignored_order)
                raw_cancelled_order = await self._handle_order_cancellation(
                    order, is_cancelled_from_exchange)
                self.logger.info(
                    f"{order.symbol} {order.get_name()} at {order.origin_price}"
                    f" (ID : {order.order_id}) cancelled on {self.exchange_manager.exchange_name}"
                )

                # nothing to update in case of a simulated order
                if raw_cancelled_order is not None:
                    await self.exchange_manager.exchange_personal_data.handle_order_update_from_raw(
                        order.symbol, order.order_id, raw_cancelled_order)
예제 #3
0
    async def test_parse_order_type(self):
        _, exchange_manager, trader_inst = await self.init_default()

        order_to_test = Order(trader_inst)

        ccxt_order_buy_market = {
            "side": TradeOrderSide.BUY,
            "type": TradeOrderType.MARKET
        }

        order_to_test.update_from_raw(ccxt_order_buy_market)
        assert order_to_test.order_type == TraderOrderType.BUY_MARKET

        ccxt_order_buy_limit = {
            "side": TradeOrderSide.BUY,
            "type": TradeOrderType.LIMIT
        }
        assert parse_order_type(ccxt_order_buy_limit) == (
            TradeOrderSide.BUY, TraderOrderType.BUY_LIMIT)

        ccxt_order_sell_market = {
            "side": TradeOrderSide.SELL,
            "type": TradeOrderType.MARKET
        }
        assert parse_order_type(ccxt_order_sell_market) == (
            TradeOrderSide.SELL, TraderOrderType.SELL_MARKET)

        ccxt_order_sell_limit = {
            "side": TradeOrderSide.SELL,
            "type": TradeOrderType.LIMIT
        }
        assert parse_order_type(ccxt_order_sell_limit) == (
            TradeOrderSide.SELL, TraderOrderType.SELL_LIMIT)

        await self.stop(exchange_manager)
예제 #4
0
    async def _create_not_loaded_order(self, new_order: Order,
                                       portfolio) -> Order:
        """
        Creates an exchange managed order
        """
        if not self.simulate and not new_order.is_self_managed():
            created_order = await self.exchange_manager.exchange.create_order(
                new_order.order_type, new_order.symbol,
                new_order.origin_quantity, new_order.origin_price,
                new_order.origin_stop_price)

            self.logger.info(
                f"Created order on {self.exchange_manager.exchange_name}: {created_order}"
            )

            # get real order from exchange
            new_order = Order(self)
            new_order.update_from_raw(created_order)

            # rebind linked portfolio to new order instance
            new_order.linked_portfolio = portfolio

        # update the availability of the currency in the portfolio
        portfolio.update_portfolio_available(new_order, is_new_order=True)

        return new_order
예제 #5
0
 def clear(self):
     if self.wait_for_hit_event_task is not None:
         if not self.limit_price_hit_event.is_set():
             self.wait_for_hit_event_task.cancel()
         self.wait_for_hit_event_task = None
     if self.limit_price_hit_event is not None:
         self.exchange_manager.exchange_symbols_data. \
             get_exchange_symbol_data(self.symbol).price_events_manager.remove_event(self.limit_price_hit_event)
     Order.clear(self)
예제 #6
0
async def test_simulated_update(trader_simulator):
    config, exchange_manager_inst, trader_inst = trader_simulator
    order_sim_inst = Order(trader_inst)

    order_sim_inst.update(order_type=TraderOrderType.SELL_MARKET,
                          symbol="LTC/USDT",
                          quantity=100,
                          price=3.22)
    assert order_sim_inst.status == OrderStatus.OPEN
    assert order_sim_inst.filled_quantity == order_sim_inst.origin_quantity == 100
예제 #7
0
    async def cancel_order(self, order: Order):
        if order and not order.is_cancelled() and not order.is_filled():
            async with order.lock:
                odr = order
                cancelled_order = await odr.cancel_order()
                self.logger.info(
                    f"{odr.symbol} {odr.get_name()} at {odr.origin_price}"
                    f" (ID : {odr.order_id}) cancelled on {self.exchange_manager.exchange.name}"
                )

                if cancelled_order:
                    await self.exchange_manager.exchange_personal_data.handle_order_update(
                        order.symbol, order.order_id, cancelled_order)
예제 #8
0
    async def _handle_order_cancellation(
            self, order: Order, is_cancelled_from_exchange: bool) -> dict:
        raw_cancelled_order = None
        # if real order: cancel on exchange
        if not self.simulate and not order.is_self_managed(
        ) and not is_cancelled_from_exchange:
            raw_cancelled_order = await self.exchange_manager.exchange.cancel_order(
                order.order_id, order.symbol)

        # add to trade history and notify
        await self.exchange_manager.exchange_personal_data.handle_trade_instance_update(
            create_trade_from_order(order,
                                    close_status=OrderStatus.CANCELED,
                                    canceled_time=self.exchange_manager.
                                    exchange.get_exchange_current_time()))

        # update portfolio with cancelled funds order
        async with self.exchange_manager.exchange_personal_data.get_order_portfolio(
            order).lock:
            self.exchange_manager.exchange_personal_data.get_order_portfolio(order) \
                .update_portfolio_available(order, is_new_order=False)

        # remove order from open_orders
        self.exchange_manager.exchange_personal_data.orders_manager.remove_order_instance(
            order)

        return raw_cancelled_order
예제 #9
0
async def test_update(trader):
    config, exchange_manager_inst, trader_inst = trader

    # with real trader
    order_inst = Order(trader_inst)
    order_inst.update(order_type=TraderOrderType.BUY_MARKET,
                      symbol="BTC/USDT",
                      current_price=10000,
                      quantity=1)

    assert order_inst.order_type == TraderOrderType.BUY_MARKET
    assert order_inst.symbol == "BTC/USDT"
    assert order_inst.created_last_price == 10000
    assert order_inst.origin_quantity == 1
    assert order_inst.creation_time != 0
    assert order_inst.get_currency_and_market() == ('BTC', 'USDT')
    assert order_inst.side is None
    assert order_inst.status == OrderStatus.OPEN
    assert order_inst.filled_quantity != order_inst.origin_quantity

    order_inst.update(order_type=TraderOrderType.STOP_LOSS_LIMIT,
                      symbol="ETH/BTC",
                      quantity=0.1,
                      quantity_filled=5.2,
                      price=0.12,
                      stop_price=0.9)
    assert order_inst.origin_stop_price == 0.9
    assert order_inst.origin_price == 0.12
예제 #10
0
    async def cancel_order(self, order: Order):
        if order and not order.is_cancelled() and not order.is_filled():
            async with order.lock:
                odr = order
                cancelled_order = await odr.cancel_order()
                self.logger.info(
                    f"{odr.symbol} {odr.get_name()} at {odr.origin_price}"
                    f" (ID : {odr.order_id}) cancelled on {self.exchange_manager.exchange_name}"
                )

                # skip_upsert when cancelled_order is None (nothing to update because simulated order)
                skip_upsert = cancelled_order is None
                cancelled_order = odr if skip_upsert else cancelled_order
                await self.exchange_manager.exchange_personal_data.handle_order_update(
                    order.symbol,
                    order.order_id,
                    cancelled_order,
                    skip_upsert=skip_upsert)
예제 #11
0
 async def cancel_order(self, order: Order, ignored_order: Order = None):
     """
     Cancels the given order and its linked orders, and updates the portfolio, publish in order channel
     if order is from a real exchange.
     :param order: Order to cancel
     :param ignored_order: Order not to cancel if found in linked orders recursive cancels (ex: avoid cancelling
     a filled order)
     :return: None
     """
     if order and order.is_open():
         # always cancel this order first to avoid infinite loop followed by deadlock
         await self._handle_order_cancellation(order, ignored_order)
예제 #12
0
    async def _create_new_order(self, new_order: Order, portfolio) -> Order:
        """
        Creates an exchange managed order, it might be a simulated or a real order. Then updates the portfolio.
        """
        if not self.simulate and not new_order.is_self_managed():
            created_order = await self.exchange_manager.exchange.create_order(
                new_order.order_type, new_order.symbol,
                new_order.origin_quantity, new_order.origin_price,
                new_order.origin_stop_price)

            self.logger.info(
                f"Created order on {self.exchange_manager.exchange_name}: {created_order}"
            )

            # get real order from exchange
            new_order = create_order_instance_from_raw(self,
                                                       created_order,
                                                       force_open=True)

            # rebind linked portfolio to new order instance
            new_order.linked_portfolio = portfolio
        return new_order
예제 #13
0
    async def test_parse_exchange_order_to_trade_instance(self):
        _, exchange_manager, trader_inst = await self.init_default()

        timestamp = time.time()
        order_to_test = Order(trader_inst)
        exchange_order = {
            "status": OrderStatus.PARTIALLY_FILLED.value,
            "symbol": self.DEFAULT_SYMBOL,
            # "fee": 0.001,
            "price": 10.1444215411,
            "cost": 100.1444215411,
            "filled": 1.568415145687741563132,
            "timestamp": timestamp
        }

        order_to_test.update_from_raw(exchange_order)

        assert order_to_test.status == OrderStatus.PARTIALLY_FILLED
        assert order_to_test.filled_quantity == 1.568415145687741563132
        assert order_to_test.filled_price == 10.1444215411
        # assert order_to_test.fee == 0.001
        assert order_to_test.total_cost == 100.1444215411

        await self.stop(exchange_manager)
예제 #14
0
    async def _handle_order_cancellation(self, order: Order,
                                         ignored_order: Order):
        success = True
        async with order.lock:
            # if real order: cancel on exchange
            if not self.simulate and not order.is_self_managed():
                success = await self.exchange_manager.exchange.cancel_order(
                    order.order_id, order.symbol)
                if not success:
                    # retry to cancel order
                    success = await self.exchange_manager.exchange.cancel_order(
                        order.order_id, order.symbol)
                if not success:
                    self.logger.error(f"Failed to cancel order {order}")
                else:
                    order.status = OrderStatus.CLOSED
                    self.logger.debug(f"Successfully cancelled order {order}")
            else:
                order.status = OrderStatus.CANCELED

        # call CancelState termination
        await order.on_cancel(force_cancel=success,
                              is_from_exchange_data=False,
                              ignored_order=ignored_order)
예제 #15
0
 def clear(self):
     """
     Clear prices hit events and their related tasks and call super clear
     """
     self._clear_event_and_tasks()
     Order.clear(self)
예제 #16
0
 def _create_trade_from_raw(self, raw_trade):
     order = Order(self.trader)
     order.order_id = raw_trade[ExchangeConstantsOrderColumns.ID.value]
     order.origin_price = raw_trade[
         ExchangeConstantsOrderColumns.PRICE.value]
     order.origin_quantity = raw_trade[
         ExchangeConstantsOrderColumns.AMOUNT.value]
     order.symbol = raw_trade[ExchangeConstantsOrderColumns.SYMBOL.value]
     order.currency, order.market = self.exchange_manager.get_exchange_quote_and_base(
         raw_trade[ExchangeConstantsOrderColumns.SYMBOL.value])
     order.filled_quantity = raw_trade[
         ExchangeConstantsOrderColumns.AMOUNT.value]
     order.filled_quantity = None  # TODO
     order.filled_price = None  # TODO
     order.total_cost = None  # TODO
     order.order_type = None  # TODO
     order.fee = None  # TODO
     order.side = None  # TODO
     order.canceled_time = None  # TODO
     order.executed_time = None  # TODO
     return Trade(order)
예제 #17
0
async def test_get_profitability(trader_simulator):
    config, exchange_manager_inst, trader_inst = trader_simulator

    # Test filled_price > create_last_price
    # test side SELL
    order_filled_sup_side_sell_inst = Order(trader_inst)
    order_filled_sup_side_sell_inst.side = TradeOrderSide.SELL
    order_filled_sup_side_sell_inst.filled_price = 10
    order_filled_sup_side_sell_inst.created_last_price = 9
    assert order_filled_sup_side_sell_inst.get_profitability() == (-(1 - 10 / 9))

    # test side BUY
    order_filled_sup_side_sell_inst = Order(trader_inst)
    order_filled_sup_side_sell_inst.side = TradeOrderSide.BUY
    order_filled_sup_side_sell_inst.filled_price = 15.114778
    order_filled_sup_side_sell_inst.created_last_price = 7.265
    assert order_filled_sup_side_sell_inst.get_profitability() == (1 - 15.114778 / 7.265)

    # Test filled_price < create_last_price
    # test side SELL
    order_filled_sup_side_sell_inst = Order(trader_inst)
    order_filled_sup_side_sell_inst.side = TradeOrderSide.SELL
    order_filled_sup_side_sell_inst.filled_price = 11.556877
    order_filled_sup_side_sell_inst.created_last_price = 20
    assert order_filled_sup_side_sell_inst.get_profitability() == (1 - 20 / 11.556877)

    # test side BUY
    order_filled_sup_side_sell_inst = Order(trader_inst)
    order_filled_sup_side_sell_inst.side = TradeOrderSide.BUY
    order_filled_sup_side_sell_inst.filled_price = 8
    order_filled_sup_side_sell_inst.created_last_price = 14.35
    assert order_filled_sup_side_sell_inst.get_profitability() == (-(1 - 14.35 / 8))

    # Test filled_price == create_last_price
    # test side SELL
    order_filled_sup_side_sell_inst = Order(trader_inst)
    order_filled_sup_side_sell_inst.side = TradeOrderSide.SELL
    order_filled_sup_side_sell_inst.filled_price = 1517374.4567
    order_filled_sup_side_sell_inst.created_last_price = 1517374.4567
    assert order_filled_sup_side_sell_inst.get_profitability() == 0

    # test side BUY
    order_filled_sup_side_sell_inst = Order(trader_inst)
    order_filled_sup_side_sell_inst.side = TradeOrderSide.BUY
    order_filled_sup_side_sell_inst.filled_price = 0.4275587387858527
    order_filled_sup_side_sell_inst.created_last_price = 0.4275587387858527
    assert order_filled_sup_side_sell_inst.get_profitability() == 0
예제 #18
0
 def _create_order_from_raw(self, raw_order):
     order = Order(self.trader)
     order.update_from_raw(raw_order)
     return order
예제 #19
0
 def update_close_orders(self):
     for symbol in self.exchange_manager.exchange_config.get_traded_pairs():
         for close_order in self.exchange_manager.get_closed_orders(symbol):
             self.parse_exchange_order_to_trade_instance(
                 close_order, Order(self))