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))})
    def test_last_own_trade_price_order_update(self):
        self.clock.add_iterator(self.buy_last_own_trade_price_strategy)

        # Simulate own order filled
        last_own_traded_price: Decimal = Decimal("102.0")
        filled_order: LimitOrder = LimitOrder(client_order_id="myTrade",
                                              trading_pair=self.trading_pair,
                                              is_buy=True,
                                              base_currency=self.base_asset,
                                              quote_currency=self.quote_asset,
                                              price=last_own_traded_price,
                                              quantity=Decimal("10"))
        self.buy_last_own_trade_price_strategy._tracked_order_ids.add(
            "myTrade")
        self.simulate_limit_order_fill(self.market, filled_order,
                                       self.start_timestamp)

        market_filled_order: LimitOrder = LimitOrder(
            client_order_id="notMyTrade",
            trading_pair=self.trading_pair,
            is_buy=True,
            base_currency=self.base_asset,
            quote_currency=self.quote_asset,
            price=Decimal("100"),
            quantity=Decimal("10"))
        self.simulate_limit_order_fill(self.market, market_filled_order,
                                       self.start_timestamp)

        expected_new_price: Decimal = last_own_traded_price * (
            Decimal('1') - (self.spread / Decimal("100")))

        new_price: Decimal = self.buy_last_own_trade_price_strategy._recalculate_price_parameter(
        )
        self.assertEqual(new_price, expected_new_price)
    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 test_remove_orders_far_from_price(self):
     # hanging_orders_cancel_pct = 10% so will add one closer and one further
     # Current price = 100.0
     self.tracker.add_order(LimitOrder("Order-number-1", "BTC-USDT", False, "BTC", "USDT", Decimal(101), Decimal(1)))
     self.tracker.add_order(LimitOrder("Order-number-2", "BTC-USDT", False, "BTC", "USDT", Decimal(120), Decimal(1)))
     self.assertEqual(len(self.tracker.original_orders), 2)
     self.tracker.remove_orders_far_from_price()
     self.assertEqual(len(self.tracker.original_orders), 1)
    def test_renew_hanging_orders_past_max_order_age(self):
        cancelled_orders_ids = []
        strategy_active_orders = []
        type(self.strategy).current_timestamp = PropertyMock(
            return_value=1234967891)
        type(self.strategy).active_orders = PropertyMock(
            return_value=strategy_active_orders)
        self.strategy.cancel_order.side_effect = lambda order_id: cancelled_orders_ids.append(
            order_id)
        self.strategy.buy_with_specific_market.return_value = "Order-1234569990000000"

        # Order just executed
        new_order = LimitOrder("Order-1234567890000000", "BTC-USDT", True,
                               "BTC", "USDT", Decimal(101), Decimal(1))
        # Order executed 1900 seconds ago
        old_order = LimitOrder("Order-1234565991000000", "BTC-USDT", True,
                               "BTC", "USDT", Decimal(105), Decimal(1))

        self.tracker.add_order(new_order)
        strategy_active_orders.append(new_order)
        self.tracker.add_order(old_order)
        strategy_active_orders.append(old_order)

        self.tracker.update_strategy_orders_with_equivalent_orders()

        self.assertTrue(
            any(order.trading_pair == "BTC-USDT"
                and order.price == Decimal(105)
                for order in self.tracker.strategy_current_hanging_orders))

        # When calling the renew logic, the old order should start the renew process (it should be canceled)
        # but it will only stop being a current hanging order once the cancel confirmation arrives
        self.tracker.process_tick()
        self.assertTrue(old_order.client_order_id in cancelled_orders_ids)
        self.assertTrue(
            any(order.trading_pair == "BTC-USDT"
                and order.price == Decimal(105)
                for order in self.tracker.strategy_current_hanging_orders))

        # When the cancel is confirmed the order should no longer be considered a hanging order
        strategy_active_orders.remove(old_order)
        self.tracker._did_cancel_order(
            MarketEvent.OrderCancelled, self,
            OrderCancelledEvent(old_order.client_order_id,
                                old_order.client_order_id))
        self.assertTrue(
            self._is_logged(
                "INFO",
                f"(BTC-USDT) Hanging order {old_order.client_order_id} "
                f"has been cancelled as part of the renew process. "
                f"Now the replacing order will be created."))
        self.assertFalse(
            any(order.order_id == old_order.client_order_id
                for order in self.tracker.strategy_current_hanging_orders))
        self.assertTrue(
            any(order.order_id == "Order-1234569990000000"
                for order in self.tracker.strategy_current_hanging_orders))
    def test_limit_order_added_to_non_grouping_tracker_is_potential_hanging_order(
            self):
        strategy_active_orders = []
        newly_created_buy_orders_ids = [
            "Order-1234570000000000", "Order-1234570020000000",
            "Order-1234570040000000", "Order-1234570060000000"
        ]
        newly_created_sell_orders_ids = [
            "Order-1234570010000000", "Order-1234570030000000",
            "Order-1234570050000000", "Order-1234570070000000"
        ]

        type(self.strategy).active_orders = PropertyMock(
            return_value=strategy_active_orders)
        self.strategy.buy_with_specific_market.side_effect = newly_created_buy_orders_ids
        self.strategy.sell_with_specific_market.side_effect = newly_created_sell_orders_ids

        buy_order_1 = LimitOrder("Order-1234569960000000",
                                 "BTC-USDT",
                                 True,
                                 "BTC",
                                 "USDT",
                                 Decimal(101),
                                 Decimal(1),
                                 creation_timestamp=1234569960000000)
        buy_order_2 = LimitOrder("Order-1234569980000000",
                                 "BTC-USDT",
                                 True,
                                 "BTC",
                                 "USDT",
                                 Decimal(105),
                                 Decimal(1),
                                 creation_timestamp=1234569980000000)

        sell_order_1 = LimitOrder("Order-1234569970000000",
                                  "BTC-USDT",
                                  False,
                                  "BTC",
                                  "USDT",
                                  Decimal(110),
                                  Decimal(1),
                                  creation_timestamp=1234569970000000)

        self.tracker.add_order(buy_order_1)
        strategy_active_orders.append(buy_order_1)
        self.tracker.add_order(buy_order_2)
        strategy_active_orders.append(buy_order_2)
        self.tracker.add_order(sell_order_1)
        strategy_active_orders.append(sell_order_1)

        self.tracker.update_strategy_orders_with_equivalent_orders()

        self.assertTrue(self.tracker.is_potential_hanging_order(buy_order_1))
        self.assertTrue(self.tracker.is_potential_hanging_order(buy_order_2))
        self.assertTrue(self.tracker.is_potential_hanging_order(sell_order_1))
 def test_add_remove_limit_order(self):
     order_to_add = LimitOrder("Order-number-1", "BTC-USDT", True, "BTC", "USDT", Decimal(100), Decimal(1))
     self.tracker.add_order(order_to_add)
     self.assertEqual(len(self.tracker.original_orders), 1)
     order_that_doesnt_belong = LimitOrder("Order-number-2", "BTC-USDT", True, "BTC", "USDT", Decimal(100), Decimal(1))
     self.tracker.remove_order(order_that_doesnt_belong)
     self.assertEqual(len(self.tracker.original_orders), 1)
     self.tracker.remove_order(order_to_add)
     self.assertEqual(len(self.tracker.original_orders), 0)
     self.tracker.add_order(LimitOrder("Order-number-3", "BTC-USDT", True, "BTC", "USDT", Decimal(100), Decimal(1)))
     self.tracker.add_order(LimitOrder("Order-number-4", "BTC-USDT", True, "BTC", "USDT", Decimal(100), Decimal(1)))
     self.tracker.remove_all_orders()
     self.assertEqual(len(self.tracker.original_orders), 0)
    def test_order_being_renewed_is_canceled_only_one_time(self):
        cancelled_orders_ids = []
        strategy_active_orders = []
        type(self.strategy).current_timestamp = PropertyMock(
            return_value=1234967891)
        type(self.strategy).active_orders = PropertyMock(
            return_value=strategy_active_orders)
        self.strategy.cancel_order.side_effect = lambda order_id: cancelled_orders_ids.append(
            order_id)
        self.strategy.buy_with_specific_market.return_value = "Order-1234569990000000"

        # Order just executed
        new_order = LimitOrder("Order-1234567890000000",
                               "BTC-USDT",
                               True,
                               "BTC",
                               "USDT",
                               Decimal(101),
                               Decimal(1),
                               creation_timestamp=1234567890000000)
        # Order executed 1900 seconds ago
        old_order = LimitOrder("Order-1234565991000000",
                               "BTC-USDT",
                               True,
                               "BTC",
                               "USDT",
                               Decimal(105),
                               Decimal(1),
                               creation_timestamp=1234565991000000)

        self.tracker.add_order(new_order)
        strategy_active_orders.append(new_order)
        self.tracker.add_order(old_order)
        strategy_active_orders.append(old_order)

        self.tracker.update_strategy_orders_with_equivalent_orders()

        self.assertTrue(
            any(order.trading_pair == "BTC-USDT"
                and order.price == Decimal(105)
                for order in self.tracker.strategy_current_hanging_orders))

        # When calling the renew logic, the old order should start the renew process (it should be canceled)
        # but it will only stop being a current hanging order once the cancel confirmation arrives
        self.tracker.process_tick()
        self.assertTrue(old_order.client_order_id in cancelled_orders_ids)
        # Now we suppose that a new tick happens before the cancellation confirmation arrives
        self.tracker.process_tick()
        # The cancel request should not have been sent a second time
        self.assertEqual(1,
                         cancelled_orders_ids.count(old_order.client_order_id))
    def setUpClass(cls):
        cls.ev_loop = asyncio.get_event_loop()
        cls.trading_pair = "COINALPHA-HBOT"

        cls.limit_orders: List[LimitOrder] = [
            LimitOrder(client_order_id=f"LIMIT//-{i}-{int(time.time()*1e3)}",
                       trading_pair=cls.trading_pair,
                       is_buy=True if i % 2 == 0 else False,
                       base_currency=cls.trading_pair.split("-")[0],
                       quote_currency=cls.trading_pair.split("-")[1],
                       price=Decimal(f"{100 - i}") if i % 2 == 0 else Decimal(f"{100 + i}"),
                       quantity=Decimal(f"{10 * (i + 1)}")
                       )
            for i in range(20)
        ]
        cls.market_orders: List[MarketOrder] = [
            MarketOrder(order_id=f"MARKET//-{i}-{int(time.time()*1e3)}",
                        trading_pair=cls.trading_pair,
                        is_buy=True if i % 2 == 0 else False,
                        base_asset=cls.trading_pair.split("-")[0],
                        quote_asset=cls.trading_pair.split("-")[1],
                        amount=float(f"{10 * (i + 1)}"),
                        timestamp=time.time()
                        )
            for i in range(20)
        ]

        cls.market: BacktestMarket = BacktestMarket()
        cls.market_info: MarketTradingPairTuple = MarketTradingPairTuple(
            cls.market, cls.trading_pair, *cls.trading_pair.split("-")
        )
Example #10
0
    def test_get_price_by_type(self):
        # Check PriceType.BestAsk
        expected_best_ask: Decimal = max([entry.price for entry in self.market.order_book_bid_entries(self.trading_pair)])
        self.assertEqual(expected_best_ask, self.market_info.get_price_by_type(PriceType.BestBid))

        # Check PriceType.BestAsk
        expected_best_ask: Decimal = min([entry.price for entry in self.market.order_book_ask_entries(self.trading_pair)])
        self.assertEqual(expected_best_ask, self.market_info.get_price_by_type(PriceType.BestAsk))

        # Check PriceType.MidPrice
        expected_mid_price: Decimal = Decimal(self.initial_mid_price)
        self.assertEqual(expected_mid_price, self.market_info.get_price_by_type(PriceType.MidPrice))

        # Check initial PriceType.LastTrade
        self.assertTrue(math.isnan(self.market_info.get_price_by_type(PriceType.LastTrade)))

        # Simulate fill buy order
        expected_trade_price = Decimal("101.0")
        fill_order: LimitOrder = LimitOrder(client_order_id="test",
                                            trading_pair=self.trading_pair,
                                            is_buy=True,
                                            base_currency=self.base_asset,
                                            quote_currency=self.quote_asset,
                                            price=expected_trade_price,
                                            quantity=Decimal("10"))
        self.simulate_limit_order_fill(self.market_info.market, fill_order)

        # Check for updated trade price
        self.assertEqual(expected_trade_price, self.market_info.get_price_by_type(PriceType.LastTrade))
Example #11
0
    def format_status(self) -> str:
        lines = []
        warning_lines = []

        for market_info in self._market_infos.values():
            active_orders = self.market_info_to_active_orders.get(
                market_info, [])

            warning_lines.extend(self.network_warning([market_info]))

            markets_df = self.market_status_data_frame([market_info])
            lines.extend(
                ["", "  Markets:"] +
                ["    " + line for line in str(markets_df).split("\n")])

            assets_df = self.wallet_balance_data_frame([market_info])
            lines.extend(
                ["", "  Assets:"] +
                ["    " + line for line in str(assets_df).split("\n")])

            # See if there're any open orders.
            if active_orders:
                df = LimitOrder.to_pandas(active_orders)
                df_lines = str(df).split("\n")
                lines.extend(["", "  Active orders:"] +
                             ["    " + line for line in df_lines])
            else:
                lines.extend(["", "  No active maker orders."])

            warning_lines.extend(self.balance_warning([market_info]))

        if warning_lines:
            lines.extend(["", "*** WARNINGS ***"] + warning_lines)

        return "\n".join(lines)
    def test_sell_last_price_place_order(self):
        self.clock.add_iterator(self.sell_last_price_strategy)

        filled_order: LimitOrder = LimitOrder(client_order_id="test",
                                              trading_pair=self.trading_pair,
                                              is_buy=True,
                                              base_currency=self.base_asset,
                                              quote_currency=self.quote_asset,
                                              price=Decimal("101.0"),
                                              quantity=Decimal("10"))
        self.simulate_limit_order_fill(self.market, filled_order,
                                       self.start_timestamp)

        self.clock.backtest_til(self.start_timestamp + self.clock_tick_size +
                                self.time_delay)

        last_trade_price = filled_order.price
        expected_order_price: Decimal = last_trade_price * (
            Decimal('1') + (self.spread / Decimal("100")))

        ask_orders: List[LimitOrder] = [
            o for o in self.sell_last_price_strategy.active_orders
            if not o.is_buy
        ]
        self.assertEqual(1, len(ask_orders))
        ask_order: LimitOrder = ask_orders[0]
        self.assertEqual(expected_order_price, ask_order.price)
        self.assertEqual(1, ask_order.quantity)
    def test_hanging_order_removed_when_cancelled(self):
        strategy_active_orders = []
        strategy_logs = []
        app_notifications = []

        type(self.strategy).active_orders = PropertyMock(return_value=strategy_active_orders)
        self.strategy.log_with_clock.side_effect = lambda log_type, message: strategy_logs.append((log_type, message))
        self.strategy.notify_hb_app.side_effect = lambda message: app_notifications.append(message)

        new_order = LimitOrder("Order-1234567890000000",
                               "BTC-USDT",
                               True,
                               "BTC",
                               "USDT",
                               Decimal(101),
                               Decimal(1))

        self.tracker.add_order(new_order)
        strategy_active_orders.append(new_order)

        self.tracker.update_strategy_orders_with_equivalent_orders()

        # Now we simulate the order is cancelled
        self.tracker._did_cancel_order(MarketEvent.OrderCancelled,
                                       self,
                                       OrderCancelledEvent(new_order.client_order_id, new_order.client_order_id))

        self.assertIn((logging.INFO, "(BTC-USDT) Hanging order Order-1234567890000000 cancelled."), strategy_logs)
        self.assertIn("(BTC-USDT) Hanging order Order-1234567890000000 cancelled.", app_notifications)
        self.assertTrue(len(self.tracker.strategy_current_hanging_orders) == 0)
        self.assertNotIn(new_order, self.tracker.original_orders)
    def test_stop_tracking_limit_order(self):
        self.assertEqual(0,
                         len(self.strategy.order_tracker.tracked_limit_orders))

        limit_order: LimitOrder = LimitOrder(
            client_order_id="limit_test",
            trading_pair=self.trading_pair,
            is_buy=True,
            base_currency=self.trading_pair.split("-")[0],
            quote_currency=self.trading_pair.split("-")[1],
            price=Decimal("100"),
            quantity=Decimal("50"))

        limit_order_id: str = self.strategy.buy_with_specific_market(
            market_trading_pair_tuple=self.market_info,
            order_type=OrderType.LIMIT,
            price=limit_order.price,
            amount=limit_order.quantity,
        )

        self.assertEqual(1,
                         len(self.strategy.order_tracker.tracked_limit_orders))

        self.strategy.cancel_order(self.market_info, limit_order_id)
        self.assertEqual(0,
                         len(self.strategy.order_tracker.tracked_limit_orders))
    def test_sell_last_own_trade_price_place_order(self):
        self.clock.add_iterator(self.sell_last_own_trade_price_strategy)

        # Simulate a order being filled in the orderbook
        own_filled_order: LimitOrder = LimitOrder(
            client_order_id="myTrade",
            trading_pair=self.trading_pair,
            is_buy=True,
            base_currency=self.base_asset,
            quote_currency=self.quote_asset,
            price=Decimal("102.0"),
            quantity=Decimal("10"))
        self.sell_last_own_trade_price_strategy._tracked_order_ids.add(
            "myTrade")
        self.simulate_limit_order_fill(self.market, own_filled_order,
                                       self.start_timestamp + 60)

        self.clock.backtest_til(self.start_timestamp + 120)

        last_own_traded_price = own_filled_order.price
        expected_order_price: Decimal = last_own_traded_price * (
            Decimal('1') + (self.spread / Decimal("100")))

        ask_orders: List[LimitOrder] = [
            o for o in self.sell_last_own_trade_price_strategy.active_orders
            if not o.is_buy
        ]
        self.assertEqual(1, len(ask_orders))
        ask_order: LimitOrder = ask_orders[0]
        self.assertEqual(expected_order_price, ask_order.price)
        self.assertEqual(1, ask_order.quantity)
    def test_hanging_order_removed_when_cancelled(self):
        strategy_active_orders = []

        type(self.strategy).active_orders = PropertyMock(
            return_value=strategy_active_orders)

        new_order = LimitOrder("Order-1234567890000000",
                               "BTC-USDT",
                               True,
                               "BTC",
                               "USDT",
                               Decimal(101),
                               Decimal(1),
                               creation_timestamp=1234567890000000)

        self.tracker.add_order(new_order)
        strategy_active_orders.append(new_order)

        self.tracker.update_strategy_orders_with_equivalent_orders()

        # Now we simulate the order is cancelled
        self.tracker._did_cancel_order(
            MarketEvent.OrderCancelled.value, self,
            OrderCancelledEvent(datetime.now().timestamp(),
                                new_order.client_order_id,
                                new_order.client_order_id))

        self.assertTrue(
            self._is_logged(
                "INFO",
                "(BTC-USDT) Hanging order Order-1234567890000000 canceled."))
        self.assertTrue(len(self.tracker.strategy_current_hanging_orders) == 0)
        self.assertNotIn(new_order, self.tracker.original_orders)
    def test_to_limit_order(self):
        order: InFlightOrder = InFlightOrder(
            client_order_id=self.client_order_id,
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            price=Decimal("1.0"),
        )

        expected_limit_order: LimitOrder = LimitOrder(
            client_order_id=order.client_order_id,
            trading_pair=order.trading_pair,
            is_buy=True,
            base_currency=self.base_asset,
            quote_currency=self.quote_asset,
            price=Decimal("1.0"),
            quantity=Decimal("1000.0"),
            filled_quantity=Decimal("0"),
        )

        limit_order = order.to_limit_order()

        self.assertIsInstance(limit_order, LimitOrder)

        self.assertEqual(limit_order.client_order_id, expected_limit_order.client_order_id)
        self.assertEqual(limit_order.trading_pair, expected_limit_order.trading_pair)
        self.assertEqual(limit_order.is_buy, expected_limit_order.is_buy)
        self.assertEqual(limit_order.base_currency, expected_limit_order.base_currency)
        self.assertEqual(limit_order.quote_currency, expected_limit_order.quote_currency)
        self.assertEqual(limit_order.price, expected_limit_order.price)
        self.assertEqual(limit_order.quantity, expected_limit_order.quantity)
        self.assertEqual(limit_order.filled_quantity, expected_limit_order.filled_quantity)
        self.assertEqual(limit_order.creation_timestamp, expected_limit_order.creation_timestamp)
        self.assertEqual(limit_order.status, expected_limit_order.status)
    def test_add_order_as_hanging_order(self):
        order = LimitOrder("Order-number-1", "BTC-USDT", True, "BTC", "USDT", Decimal(100), Decimal(1))
        self.tracker.add_as_hanging_order(order)

        self.assertIn(order, self.tracker.original_orders)
        self.assertEqual(1, len(self.tracker.strategy_current_hanging_orders))

        hanging_order = next((hanging_order for hanging_order in self.tracker.strategy_current_hanging_orders))

        self.assertEqual(order.client_order_id, hanging_order.order_id)
    def test_sell_with_specific_market(self):
        limit_order: LimitOrder = LimitOrder(
            client_order_id="limit_test",
            trading_pair=self.trading_pair,
            is_buy=False,
            base_currency=self.trading_pair.split("-")[0],
            quote_currency=self.trading_pair.split("-")[1],
            price=Decimal("100"),
            quantity=Decimal("50"))

        limit_order_id: str = self.strategy.sell_with_specific_market(
            market_trading_pair_tuple=self.market_info,
            order_type=OrderType.LIMIT,
            price=limit_order.price,
            amount=limit_order.quantity,
        )

        tracked_limit_order: LimitOrder = self.strategy.order_tracker.get_limit_order(
            self.market_info, limit_order_id)

        # Note: order_id generate here is random
        self.assertIsNotNone(limit_order_id)

        self.assertEqual(limit_order.is_buy, tracked_limit_order.is_buy)
        self.assertEqual(limit_order.trading_pair,
                         tracked_limit_order.trading_pair)
        self.assertEqual(limit_order.price, tracked_limit_order.price)
        self.assertEqual(limit_order.quantity, tracked_limit_order.quantity)

        market_order: MarketOrder = MarketOrder(
            order_id="market_test",
            trading_pair=self.trading_pair,
            is_buy=False,
            base_asset=self.trading_pair.split("-")[0],
            quote_asset=self.trading_pair.split("-")[1],
            amount=Decimal("100"),
            timestamp=int(time.time() * 1e3))

        # Note: order_id generate here is random
        market_order_id: str = self.strategy.sell_with_specific_market(
            market_trading_pair_tuple=self.market_info,
            order_type=OrderType.MARKET,
            amount=market_order.amount)

        tracked_market_order: MarketOrder = self.strategy.order_tracker.get_market_order(
            self.market_info, market_order_id)

        # Note: order_id generate here is random
        self.assertIsNotNone(market_order_id)

        self.assertEqual(market_order.is_buy, tracked_market_order.is_buy)
        self.assertEqual(market_order.trading_pair,
                         tracked_market_order.trading_pair)
        self.assertEqual(market_order.amount, tracked_market_order.amount)
Example #20
0
 def test_order_creation_with_default_values(self):
     order = LimitOrder(client_order_id="HBOT_1",
                        trading_pair="HBOT-USDT",
                        is_buy=False,
                        base_currency="HBOT",
                        quote_currency="USDT",
                        price=Decimal("100"),
                        quantity=Decimal("1.5")
                        )
     self.assertEqual("HBOT_1", order.client_order_id)
     self.assertEqual("HBOT-USDT", order.trading_pair)
     self.assertEqual(False, order.is_buy)
     self.assertEqual("HBOT", order.base_currency)
     self.assertEqual("USDT", order.quote_currency)
     self.assertEqual(Decimal("100"), order.price)
     self.assertEqual(Decimal("1.5"), order.quantity)
     self.assertTrue(Decimal.is_nan(order.filled_quantity))
     self.assertEqual(0, order.creation_timestamp)
     self.assertEqual(LimitOrderStatus.UNKNOWN, order.status)
     self.assertEqual(-1, order.age())
    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'))})
Example #23
0
 def test_order_creation_with_all_values(self):
     created = int((time.time() - 100.) * 1e6)
     order = LimitOrder(client_order_id="HBOT_1",
                        trading_pair="HBOT-USDT",
                        is_buy=False,
                        base_currency="HBOT",
                        quote_currency="USDT",
                        price=Decimal("100"),
                        quantity=Decimal("1.5"),
                        filled_quantity=Decimal("0.5"),
                        creation_timestamp=created,
                        status=LimitOrderStatus.OPEN
                        )
     self.assertEqual(Decimal("0.5"), order.filled_quantity)
     self.assertEqual(created, order.creation_timestamp)
     self.assertEqual(LimitOrderStatus.OPEN, order.status)
     self.assertEqual(100, order.age())
     end_time = created + (50 * 1e6)
     self.assertEqual(50, order.age_til(end_time))
     end_time = created - (50 * 1e6)
     self.assertEqual(-1, order.age_til(end_time))
Example #24
0
    def format_status(self) -> str:
        lines: list = []
        warning_lines: list = []

        lines.extend(self.configuration_status_lines())

        for market_info in self._market_infos.values():

            active_orders = self.market_info_to_active_orders.get(
                market_info, [])

            warning_lines.extend(self.network_warning([market_info]))

            markets_df = self.market_status_data_frame([market_info])
            lines.extend(
                ["", "  Markets:"] +
                ["    " + line for line in str(markets_df).split("\n")])

            assets_df = self.wallet_balance_data_frame([market_info])
            lines.extend(
                ["", "  Assets:"] +
                ["    " + line for line in str(assets_df).split("\n")])

            # See if there're any open orders.
            if len(active_orders) > 0:
                df = LimitOrder.to_pandas(active_orders)
                df_lines = str(df).split("\n")
                lines.extend(["", "  Active orders:"] +
                             ["    " + line for line in df_lines])
            else:
                lines.extend(["", "  No active maker orders."])

            filled_trades = self.filled_trades()
            average_price = (statistics.mean(
                [trade.price
                 for trade in filled_trades]) if filled_trades else Decimal(0))
            lines.extend([
                "", f"  Average filled orders price: "
                f"{PerformanceMetrics.smart_round(average_price)} "
                f"{market_info.quote_asset}"
            ])

            lines.extend([
                f"  Pending amount: {PerformanceMetrics.smart_round(self._quantity_remaining)} "
                f"{market_info.base_asset}"
            ])

            warning_lines.extend(self.balance_warning([market_info]))

        if warning_lines:
            lines.extend(["", "*** WARNINGS ***"] + warning_lines)

        return "\n".join(lines)
Example #25
0
    def test_did_create_buy_order(self):
        limit_order: limit_order = LimitOrder(client_order_id="test",
                                              trading_pair=self.trading_pair,
                                              is_buy=True,
                                              base_currency=self.trading_pair.split("-")[0],
                                              quote_currency=self.trading_pair.split("-")[1],
                                              price=Decimal("100"),
                                              quantity=Decimal("50"))
        self.simulate_order_created(self.market_info, limit_order)

        event = self.strategy.events_queue.popleft()

        self.assertIsInstance(event, BuyOrderCreatedEvent)
Example #26
0
 def to_limit_order(self) -> LimitOrder:
     """
     Returns this InFlightOrder as a LimitOrder object.
     :return: LimitOrder object.
     """
     return LimitOrder(client_order_id=self.client_order_id,
                       trading_pair=self.trading_pair,
                       is_buy=self.trade_type is TradeType.BUY,
                       base_currency=self.base_asset,
                       quote_currency=self.quote_asset,
                       price=self.price,
                       quantity=self.amount,
                       filled_quantity=self.executed_amount_base)
Example #27
0
    def test_order_age(self, time_mock):
        time_mock.return_value = 1640001112.223
        order = LimitOrder(client_order_id="OID1",
                           trading_pair="COINALPHA-HBOT",
                           is_buy=True,
                           base_currency="COINALPHA",
                           quote_currency="HBOT",
                           price=Decimal(1000),
                           quantity=Decimal(1),
                           creation_timestamp=1640001110000000)

        age = order_age(order)
        self.assertEqual(int(time_mock.return_value - 1640001110), age)
    def test_trades(self):
        self.assertEqual(0, len(self.strategy.trades))

        # Simulate order being placed and filled
        limit_order = LimitOrder(
            client_order_id="test",
            trading_pair=self.trading_pair,
            is_buy=False,
            base_currency=self.trading_pair.split("-")[0],
            quote_currency=self.trading_pair.split("-")[1],
            price=Decimal("100"),
            quantity=Decimal("50"))
        self.simulate_order_filled(self.market_info, limit_order)

        self.assertEqual(1, len(self.strategy.trades))
 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'))})
Example #30
0
    def test_to_pandas(self):
        # Fix the timestamp here so that we can test order age accurately
        created = 1625835199511442
        now_ts = created + 100 * 1e6
        self.maxDiff = None
        orders = [
            LimitOrder("HBOT_1", "A-B", True, "A", "B", Decimal("1"), Decimal("1.5")),
            LimitOrder(f"HBOT_{str(created)}", "C-D", True, "C", "D", Decimal("1"), Decimal("1")),
            LimitOrder("HBOT_2", "A-B ", False, "A", "B", Decimal("2.5"), Decimal("1"), Decimal("0"), created, LimitOrderStatus.OPEN),
            LimitOrder(f"HBOT_{str(created)}", "A-B ", False, "A", "B", Decimal("2"), Decimal("1"), Decimal(0), created, LimitOrderStatus.CANCELED),
        ]
        df = LimitOrder.to_pandas(orders, 1.5, end_time_order_age=now_ts)
        # Except df output is as below

        # Order ID Type  Price Spread  Amount      Age Hang
        #   HBOT_2 sell    2.5 66.67%     1.0 00:01:40  n/a
        #  ...1442 sell    2.0 33.33%     1.0 00:01:40  n/a
        #   HBOT_1  buy    1.0 33.33%     1.5      n/a  n/a
        #  ...1442  buy    1.0 33.33%     1.0 00:01:40  n/a
        # we can't compare the text output directly as for some weird reason the test file passes when run individually
        # but will fail under coverage run -m nose test.hummingbot
        # self.assertEqual(expect_txt, df.to_string(index=False, max_colwidth=50))
        self.assertEqual("HBOT_2", df["Order ID"][0])
        self.assertEqual("sell", df["Type"][0])
        self.assertAlmostEqual(2.5, df["Price"][0])
        self.assertEqual("66.67%", df["Spread"][0])
        self.assertAlmostEqual(1., df["Amount"][0])
        self.assertEqual("00:01:40", df["Age"][0])
        self.assertEqual("n/a", df["Hang"][0])

        # Test to see if hanging orders are displayed correctly
        df = LimitOrder.to_pandas(orders, 1.5, ["HBOT_1", "HBOT_2"], end_time_order_age=now_ts)
        # Except df output is as below
        # Order ID Type  Price Spread  Amount      Age Hang
        #   HBOT_2 sell    2.5 66.67%     1.0 00:01:40  yes
        #  ...1442 sell    2.0 33.33%     1.0 00:01:40   no
        #   HBOT_1  buy    1.0 33.33%     1.5      n/a  yes
        #  ...1442  buy    1.0 33.33%     1.0 00:01:40   no

        self.assertEqual("HBOT_2", df["Order ID"][0])
        self.assertEqual("sell", df["Type"][0])
        self.assertAlmostEqual(2.5, df["Price"][0])
        self.assertEqual("66.67%", df["Spread"][0])
        self.assertAlmostEqual(1., df["Amount"][0])
        self.assertEqual("00:01:40", df["Age"][0])
        self.assertEqual("yes", df["Hang"][0])
        # Test to see if df is created and order age is calculated
        df = LimitOrder.to_pandas(orders, 1.5, [])
        self.assertAlmostEqual(2.5, df["Price"][0])
        self.assertTrue(":" in df["Age"][0])