Exemple #1
0
class AmmArbUnitTest(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.ev_loop = asyncio.get_event_loop()
        cls.clock: Clock = Clock(ClockMode.REALTIME)
        cls.stack: contextlib.ExitStack = contextlib.ExitStack()
        cls._clock = cls.stack.enter_context(cls.clock)

    @classmethod
    def tearDownClass(cls) -> None:
        cls.stack.close()

    def setUp(self):
        self.amm_1: MockAMM = MockAMM("onion")

        self.amm_1.set_balance(base_asset, 500)
        self.amm_1.set_balance(quote_asset, 500)
        self.market_info_1 = MarketTradingPairTuple(self.amm_1, trading_pair,
                                                    base_asset, quote_asset)

        self.amm_2: MockAMM = MockAMM("garlic")
        self.amm_2.set_balance(base_asset, 500)
        self.amm_2.set_balance(quote_asset, 500)
        self.market_info_2 = MarketTradingPairTuple(self.amm_2, trading_pair,
                                                    base_asset, quote_asset)
        self.strategy = AmmArbStrategy(
            self.market_info_1,
            self.market_info_2,
            min_profitability=Decimal("0.01"),
            order_amount=Decimal("1"),
            market_1_slippage_buffer=Decimal("0.001"),
            market_2_slippage_buffer=Decimal("0.002"),
        )
        self.clock.add_iterator(self.amm_1)
        self.clock.add_iterator(self.amm_2)
        self.clock.add_iterator(self.strategy)
        self.market_order_fill_logger: EventLogger = EventLogger()
        self.amm_1.add_listener(MarketEvent.OrderFilled,
                                self.market_order_fill_logger)
        self.amm_2.add_listener(MarketEvent.OrderFilled,
                                self.market_order_fill_logger)

    def test_arbitrage_not_profitable(self):
        self.amm_1.set_prices(trading_pair, True, 101)
        self.amm_1.set_prices(trading_pair, False, 100)
        self.amm_2.set_prices(trading_pair, True, 101)
        self.amm_2.set_prices(trading_pair, False, 100)
        self.ev_loop.run_until_complete(asyncio.sleep(2))
        taker_orders = self.strategy.tracked_limit_orders + self.strategy.tracked_market_orders
        self.assertTrue(len(taker_orders) == 0)

    def test_arb_buy_amm_1_sell_amm_2(self):
        asyncio.ensure_future(self.clock.run())
        self.amm_1.set_prices(trading_pair, True, 101)
        self.amm_1.set_prices(trading_pair, False, 100)
        self.amm_2.set_prices(trading_pair, True, 105)
        self.amm_2.set_prices(trading_pair, False, 104)
        self.ev_loop.run_until_complete(asyncio.sleep(1.5))
        placed_orders = self.strategy.tracked_limit_orders
        amm_1_order = [
            order for market, order in placed_orders if market == self.amm_1
        ][0]
        amm_2_order = [
            order for market, order in placed_orders if market == self.amm_2
        ][0]

        self.assertTrue(len(placed_orders) == 2)
        # Check if the order is created as intended
        self.assertEqual(Decimal("1"), amm_1_order.quantity)
        self.assertEqual(True, amm_1_order.is_buy)
        # The order price has to account for slippage_buffer
        exp_price = self.amm_1.quantize_order_price(
            trading_pair,
            Decimal("101") * Decimal("1.001"))
        self.assertEqual(exp_price, amm_1_order.price)
        self.assertEqual(trading_pair, amm_1_order.trading_pair)

        self.assertEqual(Decimal("1"), amm_2_order.quantity)
        self.assertEqual(False, amm_2_order.is_buy)
        exp_price = self.amm_1.quantize_order_price(
            trading_pair,
            Decimal("104") * (Decimal("1") - Decimal("0.002")))
        self.assertEqual(exp_price, amm_2_order.price)
        self.assertEqual(trading_pair, amm_2_order.trading_pair)

        # There are outstanding orders, the strategy is not ready to take on new arb
        self.assertFalse(self.strategy.ready_for_new_arb_trades())
        self.ev_loop.run_until_complete(asyncio.sleep(2))
        placed_orders = self.strategy.tracked_limit_orders
        new_amm_1_order = [
            order for market, order in placed_orders if market == self.amm_1
        ][0]
        new_amm_2_order = [
            order for market, order in placed_orders if market == self.amm_2
        ][0]
        # Check if orders remain the same
        self.assertEqual(amm_1_order.client_order_id,
                         new_amm_1_order.client_order_id)
        self.assertEqual(amm_2_order.client_order_id,
                         new_amm_2_order.client_order_id)

    def test_arb_buy_amm_2_sell_amm_1(self):
        asyncio.ensure_future(self.clock.run())
        self.amm_1.set_prices(trading_pair, True, 105)
        self.amm_1.set_prices(trading_pair, False, 104)
        self.amm_2.set_prices(trading_pair, True, 101)
        self.amm_2.set_prices(trading_pair, False, 100)
        self.ev_loop.run_until_complete(asyncio.sleep(1.5))
        placed_orders = self.strategy.tracked_limit_orders
        amm_1_order = [
            order for market, order in placed_orders if market == self.amm_1
        ][0]
        amm_2_order = [
            order for market, order in placed_orders if market == self.amm_2
        ][0]

        self.assertTrue(len(placed_orders) == 2)
        self.assertEqual(Decimal("1"), amm_1_order.quantity)
        self.assertEqual(False, amm_1_order.is_buy)
        exp_price = self.amm_1.quantize_order_price(
            trading_pair,
            Decimal("104") * (Decimal("1") - Decimal("0.001")))
        self.assertEqual(exp_price, amm_1_order.price)
        self.assertEqual(trading_pair, amm_1_order.trading_pair)
        self.assertEqual(Decimal("1"), amm_2_order.quantity)
        self.assertEqual(True, amm_2_order.is_buy)
        exp_price = self.amm_1.quantize_order_price(
            trading_pair,
            Decimal("101") * (Decimal("1") + Decimal("0.002")))
        self.assertEqual(exp_price, amm_2_order.price)
        self.assertEqual(trading_pair, amm_2_order.trading_pair)

    def test_insufficient_balance(self):
        self.amm_1.set_prices(trading_pair, True, 105)
        self.amm_1.set_prices(trading_pair, False, 104)
        self.amm_2.set_prices(trading_pair, True, 101)
        self.amm_2.set_prices(trading_pair, False, 100)
        # set base_asset to below order_amount, so not enough to sell on amm_1
        self.amm_1.set_balance(base_asset, 0.5)
        asyncio.ensure_future(self.clock.run())
        self.ev_loop.run_until_complete(asyncio.sleep(1.5))
        placed_orders = self.strategy.tracked_limit_orders
        self.assertTrue(len(placed_orders) == 0)
        self.amm_1.set_balance(base_asset, 10)
        # set quote balance to 0 on amm_2, so not enough to buy
        self.amm_2.set_balance(quote_asset, 0)
        asyncio.ensure_future(self.clock.run())
        self.ev_loop.run_until_complete(asyncio.sleep(1.5))
        placed_orders = self.strategy.tracked_limit_orders
        self.assertTrue(len(placed_orders) == 0)

    @staticmethod
    def trigger_order_complete(is_buy: bool, connector: ConnectorBase,
                               amount: Decimal, price: Decimal, order_id: str):
        # This function triggers order complete event for our mock connector, this is to simulate scenarios more
        # precisely taker orders are fully filled.
        event_tag = MarketEvent.BuyOrderCompleted if is_buy else MarketEvent.SellOrderCompleted
        event_class = BuyOrderCompletedEvent if is_buy else SellOrderCompletedEvent
        connector.trigger_event(
            event_tag,
            event_class(connector.current_timestamp, order_id, base_asset,
                        quote_asset, quote_asset, amount, amount * price,
                        Decimal("0"), OrderType.LIMIT))

    def test_non_concurrent_orders_submission(self):
        # On non concurrent orders submission, the second leg of the arb trade has to wait for the first leg order gets
        # filled.
        self.strategy = AmmArbStrategy(self.market_info_1,
                                       self.market_info_2,
                                       min_profitability=Decimal("0.01"),
                                       order_amount=Decimal("1"),
                                       concurrent_orders_submission=False)
        self.clock.add_iterator(self.strategy)
        asyncio.ensure_future(self.clock.run())
        self.amm_1.set_prices(trading_pair, True, 101)
        self.amm_1.set_prices(trading_pair, False, 100)
        self.amm_2.set_prices(trading_pair, True, 105)
        self.amm_2.set_prices(trading_pair, False, 104)
        self.ev_loop.run_until_complete(asyncio.sleep(1.5))
        placed_orders = self.strategy.tracked_limit_orders
        self.assertEqual(1, len(placed_orders))
        # Only one order submitted at this point, the one from amm_1
        amm_1_order = [
            order for market, order in placed_orders if market == self.amm_1
        ][0]
        amm_2_orders = [
            order for market, order in placed_orders if market == self.amm_2
        ]
        self.assertEqual(0, len(amm_2_orders))
        self.assertEqual(True, amm_1_order.is_buy)
        self.trigger_order_complete(True, self.amm_1, amm_1_order.quantity,
                                    amm_1_order.price,
                                    amm_1_order.client_order_id)
        # After the first leg order completed, the second one is now submitted.
        self.ev_loop.run_until_complete(asyncio.sleep(1.5))
        placed_orders = self.strategy.tracked_limit_orders
        amm_2_orders = [
            order for market, order in placed_orders if market == self.amm_2
        ]
        self.assertEqual(1, len(amm_2_orders))
        amm_2_order = amm_2_orders[0]
        self.assertEqual(False, amm_2_order.is_buy)
        self.trigger_order_complete(False, self.amm_2, amm_2_order.quantity,
                                    amm_2_order.price,
                                    amm_2_order.client_order_id)
        self.ev_loop.run_until_complete(asyncio.sleep(1.5))
        placed_orders = self.strategy.tracked_limit_orders
        new_amm_1_order = [
            order for market, order in placed_orders if market == self.amm_1
        ][0]
        # Check if new order is submitted when arb opportunity still presents
        self.assertNotEqual(amm_1_order.client_order_id,
                            new_amm_1_order.client_order_id)
class AmmArbUnitTest(unittest.TestCase):
    def setUp(self):
        self.clock: Clock = Clock(ClockMode.REALTIME)
        self.stack: contextlib.ExitStack = contextlib.ExitStack()
        self.amm_1: MockAMM = MockAMM(
            name="onion",
            client_config_map=ClientConfigAdapter(ClientConfigMap()))
        self.amm_1.set_balance(BASE_ASSET, 500)
        self.amm_1.set_balance(QUOTE_ASSET, 500)
        self.market_info_1 = MarketTradingPairTuple(self.amm_1, TRADING_PAIR, BASE_ASSET, QUOTE_ASSET)

        self.amm_2: MockAMM = MockAMM(
            name="garlic",
            client_config_map=ClientConfigAdapter(ClientConfigMap()))
        self.amm_2.set_balance(BASE_ASSET, 500)
        self.amm_2.set_balance(QUOTE_ASSET, 500)
        self.market_info_2 = MarketTradingPairTuple(self.amm_2, TRADING_PAIR, BASE_ASSET, QUOTE_ASSET)

        # Set some default prices.
        self.amm_1.set_prices(TRADING_PAIR, True, 101)
        self.amm_1.set_prices(TRADING_PAIR, False, 100)
        self.amm_2.set_prices(TRADING_PAIR, True, 105)
        self.amm_2.set_prices(TRADING_PAIR, False, 104)

        self.strategy = AmmArbStrategy()
        self.strategy.init_params(
            self.market_info_1,
            self.market_info_2,
            min_profitability=Decimal("0.01"),
            order_amount=Decimal("1"),
            market_1_slippage_buffer=Decimal("0.001"),
            market_2_slippage_buffer=Decimal("0.002"),
        )
        self.rate_source: FixedRateSource = FixedRateSource()
        self.strategy.rate_source = self.rate_source
        self.clock.add_iterator(self.amm_1)
        self.clock.add_iterator(self.amm_2)
        self.clock.add_iterator(self.strategy)
        self.market_order_fill_logger: EventLogger = EventLogger()
        self.amm_1.add_listener(MarketEvent.OrderFilled, self.market_order_fill_logger)
        self.amm_2.add_listener(MarketEvent.OrderFilled, self.market_order_fill_logger)
        self.rate_source.add_rate("ETH-USDT", Decimal(3000))

        self.stack.enter_context(self.clock)
        self.stack.enter_context(patch(
            "hummingbot.client.config.trade_fee_schema_loader.TradeFeeSchemaLoader.configured_schema_for_exchange",
            return_value=TradeFeeSchema()
        ))
        self.clock_task: asyncio.Task = safe_ensure_future(self.clock.run())

    def tearDown(self) -> None:
        self.stack.close()
        self.clock_task.cancel()
        try:
            ev_loop.run_until_complete(self.clock_task)
        except asyncio.CancelledError:
            pass

    @async_test(loop=ev_loop)
    async def test_arbitrage_not_profitable(self):
        self.amm_1.set_prices(TRADING_PAIR, True, 101)
        self.amm_1.set_prices(TRADING_PAIR, False, 100)
        self.amm_2.set_prices(TRADING_PAIR, True, 101)
        self.amm_2.set_prices(TRADING_PAIR, False, 100)
        await asyncio.sleep(2)
        taker_orders = self.strategy.tracked_limit_orders + self.strategy.tracked_market_orders
        self.assertTrue(len(taker_orders) == 0)

    @async_test(loop=ev_loop)
    async def test_arb_buy_amm_1_sell_amm_2(self):
        self.amm_1.set_prices(TRADING_PAIR, True, 101)
        self.amm_1.set_prices(TRADING_PAIR, False, 100)
        self.amm_2.set_prices(TRADING_PAIR, True, 105)
        self.amm_2.set_prices(TRADING_PAIR, False, 104)
        await asyncio.sleep(1.5)
        placed_orders = self.strategy.tracked_limit_orders
        amm_1_order = [order for market, order in placed_orders if market == self.amm_1][0]
        amm_2_order = [order for market, order in placed_orders if market == self.amm_2][0]

        self.assertTrue(len(placed_orders) == 2)
        # Check if the order is created as intended
        self.assertEqual(Decimal("1"), amm_1_order.quantity)
        self.assertEqual(True, amm_1_order.is_buy)
        # The order price has to account for slippage_buffer
        exp_price = self.amm_1.quantize_order_price(TRADING_PAIR, Decimal("101") * Decimal("1.001"))
        self.assertEqual(exp_price, amm_1_order.price)
        self.assertEqual(TRADING_PAIR, amm_1_order.trading_pair)

        self.assertEqual(Decimal("1"), amm_2_order.quantity)
        self.assertEqual(False, amm_2_order.is_buy)
        exp_price = self.amm_1.quantize_order_price(TRADING_PAIR, Decimal("104") * (Decimal("1") - Decimal("0.002")))
        self.assertEqual(exp_price, amm_2_order.price)
        self.assertEqual(TRADING_PAIR, amm_2_order.trading_pair)

        # There are outstanding orders, the strategy is not ready to take on new arb
        self.assertFalse(self.strategy.ready_for_new_arb_trades())
        await asyncio.sleep(2)
        placed_orders = self.strategy.tracked_limit_orders
        new_amm_1_order = [order for market, order in placed_orders if market == self.amm_1][0]
        new_amm_2_order = [order for market, order in placed_orders if market == self.amm_2][0]
        # Check if orders remain the same
        self.assertEqual(amm_1_order.client_order_id, new_amm_1_order.client_order_id)
        self.assertEqual(amm_2_order.client_order_id, new_amm_2_order.client_order_id)

    @async_test(loop=ev_loop)
    async def test_arb_buy_amm_2_sell_amm_1(self):
        self.amm_1.set_prices(TRADING_PAIR, True, 105)
        self.amm_1.set_prices(TRADING_PAIR, False, 104)
        self.amm_2.set_prices(TRADING_PAIR, True, 101)
        self.amm_2.set_prices(TRADING_PAIR, False, 100)
        await asyncio.sleep(1.5)
        placed_orders = self.strategy.tracked_limit_orders
        amm_1_order = [order for market, order in placed_orders if market == self.amm_1][0]
        amm_2_order = [order for market, order in placed_orders if market == self.amm_2][0]

        self.assertTrue(len(placed_orders) == 2)
        self.assertEqual(Decimal("1"), amm_1_order.quantity)
        self.assertEqual(False, amm_1_order.is_buy)
        exp_price = self.amm_1.quantize_order_price(TRADING_PAIR, Decimal("104") * (Decimal("1") - Decimal("0.001")))
        self.assertEqual(exp_price, amm_1_order.price)
        self.assertEqual(TRADING_PAIR, amm_1_order.trading_pair)
        self.assertEqual(Decimal("1"), amm_2_order.quantity)
        self.assertEqual(True, amm_2_order.is_buy)
        exp_price = self.amm_1.quantize_order_price(TRADING_PAIR, Decimal("101") * (Decimal("1") + Decimal("0.002")))
        self.assertEqual(exp_price, amm_2_order.price)
        self.assertEqual(TRADING_PAIR, amm_2_order.trading_pair)

    @async_test(loop=ev_loop)
    async def test_insufficient_balance(self):
        self.amm_1.set_prices(TRADING_PAIR, True, 105)
        self.amm_1.set_prices(TRADING_PAIR, False, 104)
        self.amm_2.set_prices(TRADING_PAIR, True, 101)
        self.amm_2.set_prices(TRADING_PAIR, False, 100)
        # set base_asset to below order_amount, so not enough to sell on amm_1
        self.amm_1.set_balance(BASE_ASSET, 0.5)
        await asyncio.sleep(1.5)
        placed_orders = self.strategy.tracked_limit_orders
        self.assertTrue(len(placed_orders) == 0)
        self.amm_1.set_balance(BASE_ASSET, 10)
        # set quote balance to 0 on amm_2, so not enough to buy
        self.amm_2.set_balance(QUOTE_ASSET, 0)
        await asyncio.sleep(1.5)
        placed_orders = self.strategy.tracked_limit_orders
        self.assertTrue(len(placed_orders) == 0)

    @staticmethod
    def trigger_order_complete(is_buy: bool, connector: ConnectorBase, amount: Decimal, price: Decimal,
                               order_id: str):
        # This function triggers order complete event for our mock connector, this is to simulate scenarios more
        # precisely taker orders are fully filled.
        event_tag = MarketEvent.BuyOrderCompleted if is_buy else MarketEvent.SellOrderCompleted
        event_class = BuyOrderCompletedEvent if is_buy else SellOrderCompletedEvent
        connector.trigger_event(event_tag,
                                event_class(connector.current_timestamp, order_id, BASE_ASSET, QUOTE_ASSET,
                                            amount, amount * price, OrderType.LIMIT))

    @async_test(loop=ev_loop)
    async def test_non_concurrent_orders_submission(self):
        # On non concurrent orders submission, the second leg of the arb trade has to wait for the first leg order gets
        # filled.
        self.strategy = AmmArbStrategy()
        self.strategy.init_params(
            self.market_info_1,
            self.market_info_2,
            min_profitability=Decimal("0.01"),
            order_amount=Decimal("1"),
            concurrent_orders_submission=False
        )
        self.strategy.rate_source = self.rate_source
        self.clock.add_iterator(self.strategy)
        await asyncio.sleep(1.5)
        placed_orders = self.strategy.tracked_limit_orders
        self.assertEqual(1, len(placed_orders))
        # Only one order submitted at this point, the one from amm_1
        amm_1_order = [order for market, order in placed_orders if market == self.amm_1][0]
        amm_2_orders = [order for market, order in placed_orders if market == self.amm_2]
        self.assertEqual(0, len(amm_2_orders))
        self.assertEqual(True, amm_1_order.is_buy)
        self.trigger_order_complete(True, self.amm_1, amm_1_order.quantity, amm_1_order.price,
                                    amm_1_order.client_order_id)
        # After the first leg order completed, the second one is now submitted.
        await asyncio.sleep(1.5)
        placed_orders = self.strategy.tracked_limit_orders
        amm_2_orders = [order for market, order in placed_orders if market == self.amm_2]
        self.assertEqual(1, len(amm_2_orders))
        amm_2_order = amm_2_orders[0]
        self.assertEqual(False, amm_2_order.is_buy)
        self.trigger_order_complete(False, self.amm_2, amm_2_order.quantity, amm_2_order.price,
                                    amm_2_order.client_order_id)
        await asyncio.sleep(1.5)
        placed_orders = self.strategy.tracked_limit_orders
        new_amm_1_order = [order for market, order in placed_orders if market == self.amm_1][0]
        # Check if new order is submitted when arb opportunity still presents
        self.assertNotEqual(amm_1_order.client_order_id, new_amm_1_order.client_order_id)

    @async_test(loop=ev_loop)
    async def test_format_status(self):
        first_side = ArbProposalSide(
            self.market_info_1,
            True,
            Decimal(101),
            Decimal(100),
            Decimal(50),
            []
        )
        second_side = ArbProposalSide(
            self.market_info_2,
            False,
            Decimal(105),
            Decimal(104),
            Decimal(50),
            []
        )
        self.strategy._all_arb_proposals = [ArbProposal(first_side, second_side)]

        expected_status = """  Markets:
    Exchange    Market   Sell Price    Buy Price    Mid Price
       onion HBOT-USDT 100.00000000 101.00000000 100.50000000
      garlic HBOT-USDT 104.00000000 105.00000000 104.50000000

  Network Fees:
    Exchange Gas Fees
       onion    0 ETH
      garlic    0 ETH

  Assets:
      Exchange Asset  Total Balance  Available Balance
    0    onion  HBOT            500                500
    1    onion  USDT            500                500
    2   garlic  HBOT            500                500
    3   garlic  USDT            500                500

  Profitability:
    buy at onion, sell at garlic: 3.96%

  Quotes Rates (fixed rates)
      Quotes pair Rate
    0   USDT-USDT    1"""
        current_status = await self.strategy.format_status()
        self.assertTrue(expected_status in current_status)

    @async_test(loop=ev_loop)
    async def test_arb_not_profitable_from_gas_prices(self):
        self.amm_1.set_prices(TRADING_PAIR, True, 101)
        self.amm_1.set_prices(TRADING_PAIR, False, 100)
        self.amm_2.set_prices(TRADING_PAIR, True, 110)
        self.amm_2.set_prices(TRADING_PAIR, False, 109)
        self.amm_1.network_transaction_fee = TokenAmount("ETH", Decimal("0.01"))
        await asyncio.sleep(2)
        taker_orders = self.strategy.tracked_limit_orders + self.strategy.tracked_market_orders
        self.assertTrue(len(taker_orders) == 0)

    @async_test(loop=ev_loop)
    async def test_arb_profitable_after_gas_prices(self):
        self.amm_1.set_prices(TRADING_PAIR, True, 101)
        self.amm_1.set_prices(TRADING_PAIR, False, 100)
        self.amm_2.set_prices(TRADING_PAIR, True, 105)
        self.amm_2.set_prices(TRADING_PAIR, False, 104)
        self.amm_1.network_transaction_fee = TokenAmount("ETH", Decimal("0.0002"))
        await asyncio.sleep(2)
        placed_orders = self.strategy.tracked_limit_orders + self.strategy.tracked_market_orders
        self.assertEqual(2, len(placed_orders))

    @async_test(loop=ev_loop)
    @unittest.mock.patch("hummingbot.strategy.amm_arb.amm_arb.AmmArbStrategy.apply_gateway_transaction_cancel_interval")
    async def test_apply_cancel_interval(self, patched_func: unittest.mock.AsyncMock):
        await asyncio.sleep(2)
        patched_func.assert_awaited()

    @async_test(loop=ev_loop)
    @unittest.mock.patch("hummingbot.strategy.amm_arb.amm_arb.AmmArbStrategy.is_gateway_market", return_value=True)
    @unittest.mock.patch.object(MockAMM, "cancel_outdated_orders")
    async def test_cancel_outdated_orders(
            self,
            cancel_outdated_orders_func: unittest.mock.AsyncMock,
            _: unittest.mock.Mock
    ):
        await asyncio.sleep(2)
        cancel_outdated_orders_func.assert_awaited()

    @async_test(loop=ev_loop)
    async def test_set_order_failed(self):
        self.amm_1.set_prices(TRADING_PAIR, True, 101)
        self.amm_1.set_prices(TRADING_PAIR, False, 100)
        self.amm_2.set_prices(TRADING_PAIR, True, 105)
        self.amm_2.set_prices(TRADING_PAIR, False, 104)
        self.amm_1.network_transaction_fee = TokenAmount("ETH", Decimal("0.0002"))
        await asyncio.sleep(2)
        new_amm_1_order = [order for market, order in self.strategy.tracked_limit_orders if market == self.amm_1][0]
        self.assertEqual(2, len(self.strategy.tracked_limit_orders))
        self.strategy.set_order_failed(new_amm_1_order.client_order_id)
        self.assertEqual(2, len(self.strategy.tracked_limit_orders))

    @async_test(loop=ev_loop)
    async def test_market_ready(self):
        self.amm_1.ready = False
        await asyncio.sleep(10)
        self.assertFalse(self.strategy._all_markets_ready)