def test_symmetrical_volume_age_weighted(self):
        # Symmetrical in distance to mid-price and amounts, BUT different ages
        current_time_mock = 1234567891
        self.tracker.add_order(LimitOrder(f"Order-{current_time_mock - 300}000000",
                                          "BTC-USDT", True, "BTC", "USDT", Decimal(99), Decimal(6)))
        self.tracker.add_order(LimitOrder(f"Order-{current_time_mock - 600}000000",
                                          "BTC-USDT", True, "BTC", "USDT", Decimal(91), Decimal(5)))
        self.tracker.add_order(LimitOrder(f"Order-{current_time_mock - 800}000000",
                                          "BTC-USDT", False, "BTC", "USDT", Decimal(101), Decimal(6)))
        self.tracker.add_order(LimitOrder(f"Order-{current_time_mock - 1200}000000",
                                          "BTC-USDT", False, "BTC", "USDT", Decimal(109), Decimal(5)))

        with patch('time.time', return_value=current_time_mock):
            self.tracker.set_aggregation_method(HangingOrdersAggregationType.VOLUME_TIME_WEIGHTED)
            self.tracker.update_strategy_orders_with_equivalent_orders()
            self.assertEqual(self.tracker.strategy_current_hanging_orders,
                             {HangingOrder(order_id=None,
                                           trading_pair='BTC-USDT',
                                           is_buy=True,
                                           price=Decimal('95.69098'),
                                           amount=Decimal('11.00000')),
                              HangingOrder(order_id=None,
                                           trading_pair='BTC-USDT',
                                           is_buy=False,
                                           price=Decimal('104.20177'),
                                           amount=Decimal('11.00000'))})
    def _execute_orders_in_strategy(self, candidate_orders: Set[HangingOrder]):
        new_hanging_orders = set()
        order_type = self.strategy.market_info.market.get_maker_order_type()
        for order in candidate_orders:
            # Only execute if order is new
            if order.order_id is None:
                if order.amount > 0:
                    if order.is_buy:
                        order_id = self.strategy.buy_with_specific_market(
                            self.strategy.market_info,
                            amount=order.amount,
                            order_type=order_type,
                            price=order.price,
                            expiration_seconds=self.strategy.order_refresh_time
                        )
                    else:
                        order_id = self.strategy.sell_with_specific_market(
                            self.strategy.market_info,
                            amount=order.amount,
                            order_type=order_type,
                            price=order.price,
                            expiration_seconds=self.strategy.order_refresh_time
                        )
                    new_hanging_order = HangingOrder(order_id,
                                                     order.trading_pair,
                                                     order.is_buy, order.price,
                                                     order.amount)

                    new_hanging_orders.add(new_hanging_order)
            # If it's a preexistent order we don't create it but we add it to hanging orders
            else:
                new_hanging_orders.add(order)
        return new_hanging_orders
    def _process_cancel_as_part_of_renew(self, event: OrderCancelledEvent):
        renewing_order = next((order for order in self.orders_being_renewed
                               if order.order_id == event.order_id), None)
        if renewing_order:
            self.logger().info(
                f"({self.trading_pair}) Hanging order {event.order_id} "
                f"has been canceled as part of the renew process. "
                f"Now the replacing order will be created.")
            self.strategy_current_hanging_orders.remove(renewing_order)
            self.orders_being_renewed.remove(renewing_order)
            order_to_be_created = HangingOrder(None,
                                               renewing_order.trading_pair,
                                               renewing_order.is_buy,
                                               renewing_order.price,
                                               renewing_order.amount,
                                               self.strategy.current_timestamp)

            executed_orders = self._execute_orders_in_strategy(
                [order_to_be_created])
            self.strategy_current_hanging_orders = self.strategy_current_hanging_orders.union(
                executed_orders)
            for new_hanging_order in executed_orders:
                limit_order_from_hanging_order = next(
                    (o for o in self.strategy.active_orders
                     if o.client_order_id == new_hanging_order.order_id), None)
                if limit_order_from_hanging_order:
                    self.add_order(limit_order_from_hanging_order)
    def test_renew_hanging_orders_past_max_order_age(self):
        current_time_mock = 1234567891
        # Order just executed
        self.tracker.add_order(LimitOrder("Order-1234567890000000",
                                          "BTC-USDT",
                                          True,
                                          "BTC",
                                          "USDT",
                                          Decimal(101),
                                          Decimal(1)))
        # Order executed 1900 seconds ago
        self.tracker.add_order(LimitOrder("Order-1234565991000000",
                                          "BTC-USDT",
                                          True,
                                          "BTC",
                                          "USDT",
                                          Decimal(105),
                                          Decimal(1)))

        with patch('time.time', return_value=current_time_mock):
            self.tracker.update_strategy_orders_with_equivalent_orders()
            self.tracker.renew_hanging_orders_past_max_order_age()
            self.assertEqual(self.tracker.orders_to_be_created, {HangingOrder(None,
                                                                              "BTC-USDT",
                                                                              True,
                                                                              Decimal(105),
                                                                              Decimal(1))})
Beispiel #5
0
    def renew_hanging_orders_past_max_order_age(self):
        max_age = getattr(self.strategy, "max_order_age", None)
        to_be_cancelled: Set[HangingOrder] = set()
        to_be_created: Set[HangingOrder] = set()
        if max_age:
            for order in self.strategy_current_hanging_orders:
                if order.age > max_age:
                    self.logger().info(
                        f"Reached max_order_age={max_age}sec hanging order: {order}. Renewing..."
                    )
                    to_be_cancelled.add(order)

            self._cancel_multiple_orders_in_strategy(
                [o.order_id for o in to_be_cancelled if o.order_id])
            for order in to_be_cancelled:
                self.strategy_current_hanging_orders.remove(order)
                order_to_be_created = HangingOrder(None, order.trading_pair,
                                                   order.is_buy, order.price,
                                                   order.amount)
                if self.aggregation_method == HangingOrdersAggregationType.NO_AGGREGATION:
                    self.original_orders.remove(
                        next(o for o in self.original_orders
                             if o.client_order_id == order.order_id))
                    self.orders_renewed.add(order_to_be_created)
                to_be_created.add(order_to_be_created)

            self.orders_to_be_created = self.orders_to_be_created.union(
                to_be_created)
    def test_symmetrical_volume_distance_weighted(self):
        # Symmetrical in distance to mid-price and amounts, BUT with distance affecting the weight exponentially
        self.tracker.add_order(LimitOrder("Order-number-1", "BTC-USDT", True, "BTC", "USDT", Decimal(99), Decimal(6)))
        self.tracker.add_order(LimitOrder("Order-number-2", "BTC-USDT", True, "BTC", "USDT", Decimal(91), Decimal(5)))
        self.tracker.add_order(LimitOrder("Order-number-3", "BTC-USDT", False, "BTC", "USDT", Decimal(101), Decimal(6)))
        self.tracker.add_order(LimitOrder("Order-number-4", "BTC-USDT", False, "BTC", "USDT", Decimal(109), Decimal(5)))

        self.tracker.set_aggregation_method(HangingOrdersAggregationType.VOLUME_DISTANCE_WEIGHTED)
        self.tracker.update_strategy_orders_with_equivalent_orders()
        self.assertEqual(self.tracker.strategy_current_hanging_orders,
                         {HangingOrder(order_id=None,
                                       trading_pair='BTC-USDT',
                                       is_buy=True,
                                       price=Decimal('96.82055'),
                                       amount=Decimal('11.00000')),
                          HangingOrder(order_id=None,
                                       trading_pair='BTC-USDT',
                                       is_buy=False,
                                       price=Decimal('103.17945'),
                                       amount=Decimal('11.00000'))})
    def test_asymmetrical_volume_weighted(self):
        # Asymmetrical in distance to mid-price and amounts
        self.tracker.add_order(LimitOrder("Order-number-1", "BTC-USDT", True, "BTC", "USDT", Decimal(99), Decimal(2)))
        self.tracker.add_order(LimitOrder("Order-number-2", "BTC-USDT", True, "BTC", "USDT", Decimal(95), Decimal(1)))
        self.tracker.add_order(LimitOrder("Order-number-3", "BTC-USDT", False, "BTC", "USDT", Decimal(94), Decimal(6)))
        self.tracker.add_order(LimitOrder("Order-number-4", "BTC-USDT", False, "BTC", "USDT", Decimal(109), Decimal(5)))

        self.tracker.set_aggregation_method(HangingOrdersAggregationType.VOLUME_WEIGHTED)
        self.tracker.update_strategy_orders_with_equivalent_orders()
        self.assertEqual(self.tracker.strategy_current_hanging_orders,
                         {HangingOrder(order_id=None,
                                       trading_pair='BTC-USDT',
                                       is_buy=True,
                                       price=Decimal('97.66667'),
                                       amount=Decimal('3.00000')),
                          HangingOrder(order_id=None,
                                       trading_pair='BTC-USDT',
                                       is_buy=False,
                                       price=Decimal('107.36364'),
                                       amount=Decimal('11.00000'))})
    def _obtain_equivalent_weighted_order(self, orders, weight_function):
        result = set()
        buys = [o for o in orders if o.is_buy]
        sells = [o for o in orders if not o.is_buy]
        current_price = self.strategy.get_price()
        distance_prod_buys = sum(
            abs(current_price - o.price) * o.quantity * weight_function(o)
            for o in buys)
        distance_prod_sells = sum(
            abs(current_price - o.price) * o.quantity * weight_function(o)
            for o in sells)

        if distance_prod_buys > 0:
            price = current_price - distance_prod_buys / sum(
                o.quantity * weight_function(o) for o in buys)
            amount = sum(o.quantity for o in buys)
            quantized_amount = self.strategy.market_info.market.quantize_order_amount(
                self.trading_pair, amount)
            quantized_price = self.strategy.market_info.market.quantize_order_price(
                self.trading_pair, price)
            if quantized_amount > 0:
                result.add(
                    HangingOrder(None, self.trading_pair, True,
                                 quantized_price, quantized_amount))
        if distance_prod_sells > 0:
            price = current_price + distance_prod_sells / sum(
                o.quantity * weight_function(o) for o in sells)
            amount = sum(o.quantity for o in sells)
            quantized_amount = self.strategy.market_info.market.quantize_order_amount(
                self.trading_pair, amount)
            quantized_price = self.strategy.market_info.market.quantize_order_price(
                self.trading_pair, price)
            if quantized_amount > 0:
                result.add(
                    HangingOrder(None, self.trading_pair, False,
                                 quantized_price, quantized_amount))
        return frozenset(result)
 def test_asymmetrical_volume_age_weighted(self):
     current_time_mock = 1234567891
     self.tracker.add_order(LimitOrder(f"Order-{current_time_mock - 500}000000",
                                       "BTC-USDT", True, "BTC", "USDT", Decimal(99), Decimal(2)))
     self.tracker.add_order(LimitOrder(f"Order-{current_time_mock - 600}000000",
                                       "BTC-USDT", True, "BTC", "USDT", Decimal(95), Decimal(1)))
     self.tracker.add_order(LimitOrder(f"Order-{current_time_mock - 700}000000",
                                       "BTC-USDT", True, "BTC", "USDT", Decimal(94), Decimal(6)))
     self.tracker.add_order(LimitOrder(f"Order-{current_time_mock - 800}000000",
                                       "BTC-USDT", False, "BTC", "USDT", Decimal(109), Decimal(5)))
     with patch('time.time', return_value=current_time_mock):
         self.tracker.set_aggregation_method(HangingOrdersAggregationType.VOLUME_TIME_WEIGHTED)
         self.tracker.update_strategy_orders_with_equivalent_orders()
         self.assertEqual(self.tracker.strategy_current_hanging_orders,
                          {HangingOrder(order_id=None,
                                        trading_pair='BTC-USDT',
                                        is_buy=True,
                                        price=Decimal('95.31641'),
                                        amount=Decimal('9.00000')),
                           HangingOrder(order_id=None,
                                        trading_pair='BTC-USDT',
                                        is_buy=False,
                                        price=Decimal('109.00000'),
                                        amount=Decimal('5.00000'))})
Beispiel #10
0
 def _execute_orders_in_strategy(self, candidate_orders: Set[HangingOrder]):
     new_hanging_orders = set()
     order_type = self.strategy.market_info.market.get_maker_order_type()
     for order in candidate_orders:
         # Only execute if order is new
         if order.order_id is None:
             if order.amount > 0:
                 if order.is_buy:
                     order_id = self.strategy.buy_with_specific_market(
                         self.strategy.market_info,
                         amount=order.amount,
                         order_type=order_type,
                         price=order.price,
                         expiration_seconds=self.strategy.order_refresh_time
                     )
                 else:
                     order_id = self.strategy.sell_with_specific_market(
                         self.strategy.market_info,
                         amount=order.amount,
                         order_type=order_type,
                         price=order.price,
                         expiration_seconds=self.strategy.order_refresh_time
                     )
                 new_hanging_order = HangingOrder(order_id,
                                                  order.trading_pair,
                                                  order.is_buy, order.price,
                                                  order.amount)
                 # If newly created order is an original order which was renewed, it will be added to original_orders
                 if order in self.orders_renewed:
                     limit_order_from_hanging_order = next(
                         o for o in self.strategy.active_orders
                         if o.client_order_id == order_id)
                     if limit_order_from_hanging_order:
                         self.add_order(limit_order_from_hanging_order)
                         self.orders_renewed.remove(order)
                 new_hanging_orders.add(new_hanging_order)
         # If it's a preexistent order we don't create it but we add it to hanging orders
         else:
             new_hanging_orders.add(order)
     return new_hanging_orders
    def _process_cancel_as_part_of_renew(self, event: OrderCancelledEvent):
        renewing_order = next((order for order in self.orders_being_renewed
                               if order.order_id == event.order_id), None)
        if renewing_order:
            self.strategy_current_hanging_orders.remove(renewing_order)
            self.orders_being_renewed.remove(renewing_order)
            order_to_be_created = HangingOrder(None,
                                               renewing_order.trading_pair,
                                               renewing_order.is_buy,
                                               renewing_order.price,
                                               renewing_order.amount)

            executed_orders = self._execute_orders_in_strategy(
                [order_to_be_created])
            self.strategy_current_hanging_orders = self.strategy_current_hanging_orders.union(
                executed_orders)
            for new_hanging_order in executed_orders:
                limit_order_from_hanging_order = next(
                    (o for o in self.strategy.active_orders
                     if o.client_order_id == new_hanging_order.order_id), None)
                if limit_order_from_hanging_order:
                    self.add_order(limit_order_from_hanging_order)
 def _get_hanging_order_from_limit_order(self, order: LimitOrder):
     return HangingOrder(order.client_order_id, order.trading_pair,
                         order.is_buy, order.price, order.quantity)