def test_show_ticker(self, notify_mock):
        self.client_config_map.db_mode = DBSqliteMode()

        captures = []
        notify_mock.side_effect = lambda s: captures.append(s)

        exchange_name = "paper"
        exchange = MockPaperExchange(
            client_config_map=ClientConfigAdapter(ClientConfigMap()))
        self.app.markets[exchange_name] = exchange
        trading_pair = "BTC-USDT"
        exchange.set_balanced_order_book(
            trading_pair,
            mid_price=10,
            min_price=8.5,
            max_price=11.5,
            price_step_size=1,
            volume_step_size=1,
        )

        self.async_run_with_timeout(
            self.app.show_ticker(exchange=exchange_name, live=False))

        self.assertEqual(1, len(captures))

        df_str_expected = (
            "   Market: mock_paper_exchange"
            "\n+------------+------------+-------------+--------------+"
            "\n|   Best Bid |   Best Ask |   Mid Price |   Last Trade |"
            "\n|------------+------------+-------------+--------------|"
            "\n|        9.5 |       10.5 |          10 |          nan |"
            "\n+------------+------------+-------------+--------------+")

        self.assertEqual(df_str_expected, captures[0])
Example #2
0
 def emit_order_created_event(market: MockPaperExchange, order: LimitOrder):
     event_cls = BuyOrderCreatedEvent if order.is_buy else SellOrderCreatedEvent
     event_tag = MarketEvent.BuyOrderCreated if order.is_buy else MarketEvent.SellOrderCreated
     market.trigger_event(
         event_tag,
         message=event_cls(order.creation_timestamp, OrderType.LIMIT,
                           order.trading_pair, order.quantity, order.price,
                           order.client_order_id,
                           order.creation_timestamp * 1e-6))
    def setUp(self) -> None:
        super().setUp()
        self.base_asset = "COINALPHA"
        self.quote_asset = "HBOT"
        self.trading_pair = f"{self.base_asset}-{self.quote_asset}"

        trade_fee_schema = TradeFeeSchema(
            maker_percent_fee_decimal=Decimal("0.01"),
            taker_percent_fee_decimal=Decimal("0.02"))
        self.exchange = MockPaperExchange(
            client_config_map=ClientConfigAdapter(ClientConfigMap()),
            trade_fee_schema=trade_fee_schema)
        self.budget_checker: BudgetChecker = self.exchange.budget_checker
    def test_populate_collateral_fields_percent_fees_in_third_token(self):
        pfc_token = "PFC"
        trade_fee_schema = TradeFeeSchema(
            percent_fee_token=pfc_token,
            maker_percent_fee_decimal=Decimal("0.01"),
            taker_percent_fee_decimal=Decimal("0.01"),
        )
        exchange = MockPaperExchange(client_config_map=ClientConfigAdapter(
            ClientConfigMap()),
                                     trade_fee_schema=trade_fee_schema)
        pfc_quote_pair = combine_to_hb_trading_pair(self.quote_asset,
                                                    pfc_token)
        exchange.set_balanced_order_book(  # the quote to pfc price will be 1:2
            trading_pair=pfc_quote_pair,
            mid_price=1.5,
            min_price=1,
            max_price=2,
            price_step_size=1,
            volume_step_size=1,
        )
        budget_checker: BudgetChecker = exchange.budget_checker

        order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.BUY,
            amount=Decimal("10"),
            price=Decimal("2"),
        )
        populated_candidate = budget_checker.populate_collateral_entries(
            order_candidate)

        self.assertEqual(self.quote_asset,
                         populated_candidate.order_collateral.token)
        self.assertEqual(Decimal("20"),
                         populated_candidate.order_collateral.amount)
        self.assertEqual(pfc_token,
                         populated_candidate.percent_fee_collateral.token)
        self.assertEqual(Decimal("0.4"),
                         populated_candidate.percent_fee_collateral.amount)
        self.assertEqual(pfc_token,
                         populated_candidate.percent_fee_value.token)
        self.assertEqual(Decimal("0.4"),
                         populated_candidate.percent_fee_value.amount)
        self.assertEqual(0, len(populated_candidate.fixed_fee_collaterals))
        self.assertEqual(self.base_asset,
                         populated_candidate.potential_returns.token)
        self.assertEqual(Decimal("10"),
                         populated_candidate.potential_returns.amount)
Example #5
0
    def setUp(self):
        self.maxDiff = None
        self.clock: Clock = Clock(ClockMode.BACKTEST, 1.0,
                                  self.start_timestamp, self.end_timestamp)
        self.market_1: MockPaperExchange = MockPaperExchange(
            client_config_map=ClientConfigAdapter(ClientConfigMap()))
        self.market_2: MockPaperExchange = MockPaperExchange(
            client_config_map=ClientConfigAdapter(ClientConfigMap()))

        self.market_1.set_balanced_order_book(self.market_1_trading_pairs[0],
                                              1.0, 0.5, 1.5, 0.01, 10)
        self.market_2.set_balanced_order_book(self.market_2_trading_pairs[0],
                                              1.0, 0.5, 1.5, 0.005, 5)

        self.market_1.set_balance("COINALPHA", 500)
        self.market_1.set_balance("WETH", 500)
        self.market_2.set_balance("COINALPHA", 500)
        self.market_2.set_balance("ETH", 500)
        self.market_1.set_quantization_param(
            QuantizationParams(self.market_1_trading_pairs[0], 5, 5, 5, 5))
        self.market_2.set_quantization_param(
            QuantizationParams(self.market_2_trading_pairs[0], 5, 5, 5, 5))
        self.market_trading_pair_tuple_1 = MarketTradingPairTuple(
            *([self.market_1] + self.market_1_trading_pairs))
        self.market_trading_pair_tuple_2 = MarketTradingPairTuple(
            *([self.market_2] + self.market_2_trading_pairs))
        self.market_pair: ArbitrageMarketPair = ArbitrageMarketPair(
            self.market_trading_pair_tuple_1, self.market_trading_pair_tuple_2)

        self.logging_options: int = ArbitrageStrategy.OPTION_LOG_ALL

        self.strategy: ArbitrageStrategy = ArbitrageStrategy()
        self.strategy.init_params(
            [self.market_pair],
            min_profitability=Decimal("0.03"),
            logging_options=self.logging_options,
            secondary_to_primary_quote_conversion_rate=Decimal("0.95"))

        self.clock.add_iterator(self.market_1)
        self.clock.add_iterator(self.market_2)
        self.clock.add_iterator(self.strategy)

        self.market_1_order_fill_logger: EventLogger = EventLogger()
        self.market_2_order_fill_logger: EventLogger = EventLogger()

        self.market_1.add_listener(MarketEvent.OrderFilled,
                                   self.market_1_order_fill_logger)
        self.market_2.add_listener(MarketEvent.OrderFilled,
                                   self.market_2_order_fill_logger)
    def test_adjust_candidate_insufficient_funds_for_flat_fees_and_percent_fees_third_token(
            self):
        fc_token = "PFC"
        trade_fee_schema = TradeFeeSchema(
            percent_fee_token=fc_token,
            maker_percent_fee_decimal=Decimal("0.01"),
            taker_percent_fee_decimal=Decimal("0.01"),
            maker_fixed_fees=[TokenAmount(fc_token, Decimal("1"))])
        exchange = MockPaperExchange(client_config_map=ClientConfigAdapter(
            ClientConfigMap()),
                                     trade_fee_schema=trade_fee_schema)
        pfc_quote_pair = combine_to_hb_trading_pair(self.quote_asset, fc_token)
        exchange.set_balanced_order_book(  # the quote to pfc price will be 1:2
            trading_pair=pfc_quote_pair,
            mid_price=1.5,
            min_price=1,
            max_price=2,
            price_step_size=1,
            volume_step_size=1,
        )
        budget_checker: BudgetChecker = exchange.budget_checker
        exchange.set_balance(self.quote_asset, Decimal("20"))
        exchange.set_balance(
            fc_token, Decimal("1.2")
        )  # 0.2 less than required; will result in 50% order reduction

        order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.BUY,
            amount=Decimal("10"),
            price=Decimal("2"),
        )
        adjusted_candidate = budget_checker.adjust_candidate(order_candidate,
                                                             all_or_none=False)

        self.assertEqual(Decimal("5"), adjusted_candidate.amount)
        self.assertEqual(self.quote_asset,
                         adjusted_candidate.order_collateral.token)
        self.assertEqual(Decimal("10"),
                         adjusted_candidate.order_collateral.amount)
        self.assertEqual(fc_token,
                         adjusted_candidate.percent_fee_collateral.token)
        self.assertEqual(Decimal("0.2"),
                         adjusted_candidate.percent_fee_collateral.amount)
        self.assertEqual(fc_token, adjusted_candidate.percent_fee_value.token)
        self.assertEqual(Decimal("0.2"),
                         adjusted_candidate.percent_fee_value.amount)
        self.assertEqual(1, len(adjusted_candidate.fixed_fee_collaterals))

        fixed_fee_collateral = adjusted_candidate.fixed_fee_collaterals[0]

        self.assertEqual(fc_token, fixed_fee_collateral.token)
        self.assertEqual(Decimal("1"), fixed_fee_collateral.amount)
        self.assertEqual(self.base_asset,
                         adjusted_candidate.potential_returns.token)
        self.assertEqual(Decimal("5"),
                         adjusted_candidate.potential_returns.amount)
Example #7
0
 def __init__(
     self,
     client_config_map: "ClientConfigAdapter",
     trade_fee_schema: Optional[TradeFeeSchema] = None,
     buy_collateral_token: Optional[str] = None,
     sell_collateral_token: Optional[str] = None,
 ):
     MockPaperExchange.__init__(self,
                                client_config_map=client_config_map,
                                trade_fee_schema=trade_fee_schema)
     PerpetualTrading.__init__(self)
     self._budget_checker = PerpetualBudgetChecker(exchange=self)
     self._funding_payment_span = [0, 10]
     self._buy_collateral_token = buy_collateral_token
     self._sell_collateral_token = sell_collateral_token
    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()*1e6)}",
                       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)}"),
                       creation_timestamp=int(time.time() * 1e6))
            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: MockPaperExchange = MockPaperExchange(
            client_config_map=ClientConfigAdapter(ClientConfigMap()))
        cls.market_info: MarketTradingPairTuple = MarketTradingPairTuple(
            cls.market, cls.trading_pair, *cls.trading_pair.split("-"))
    def setUp(self):
        self.maxDiff = None
        self.clock: Clock = Clock(ClockMode.BACKTEST, 1.0,
                                  self.start_timestamp, self.end_timestamp)
        self.market: MockPaperExchange = MockPaperExchange(
            client_config_map=ClientConfigAdapter(ClientConfigMap()))

        self.market.set_balanced_order_book(self.trading_pair, 10, 5, 15, 0.1,
                                            1)

        self.market.set_balance(self.base_asset, 500)
        self.market.set_balance(self.quote_asset, 500)
        self.market.set_quantization_param(
            QuantizationParams(self.trading_pair, 5, 5, 5, 5))
        self.market_info = MarketTradingPairTuple(self.market,
                                                  self.trading_pair,
                                                  self.base_asset,
                                                  self.quote_asset)
        self.logging_options: int = CeloArbStrategy.OPTION_LOG_ALL
        self.strategy = CeloArbStrategy()
        self.strategy.init_params(self.market_info,
                                  min_profitability=Decimal("0.01"),
                                  order_amount=Decimal("1"),
                                  celo_slippage_buffer=Decimal("0.001"),
                                  logging_options=self.logging_options,
                                  hb_app_notification=False,
                                  mock_celo_cli_mode=True)
        self.clock.add_iterator(self.market)
        self.clock.add_iterator(self.strategy)
        self.market_order_fill_logger: EventLogger = EventLogger()
        self.market.add_listener(MarketEvent.OrderFilled,
                                 self.market_order_fill_logger)
        CeloCLI.unlock_account(TEST_ADDRESS, TEST_PASSWORD)
 def setUp(self):
     self.log_records = []
     self.start: pd.Timestamp = pd.Timestamp("2019-01-01", tz="UTC")
     self.end: pd.Timestamp = pd.Timestamp("2019-01-01 01:00:00", tz="UTC")
     self.start_timestamp: float = self.start.timestamp()
     self.end_timestamp: float = self.end.timestamp()
     self.connector_name: str = "mock_paper_exchange"
     self.trading_pair: str = "HBOT-USDT"
     self.base_asset, self.quote_asset = self.trading_pair.split("-")
     self.base_balance: int = 500
     self.quote_balance: int = 5000
     self.initial_mid_price: int = 100
     self.clock_tick_size = 1
     self.clock: Clock = Clock(ClockMode.BACKTEST, self.clock_tick_size,
                               self.start_timestamp, self.end_timestamp)
     self.connector: MockPaperExchange = MockPaperExchange(
         client_config_map=ClientConfigAdapter(ClientConfigMap()))
     self.connector.set_balanced_order_book(trading_pair=self.trading_pair,
                                            mid_price=100,
                                            min_price=50,
                                            max_price=150,
                                            price_step_size=1,
                                            volume_step_size=10)
     self.connector.set_balance(self.base_asset, self.base_balance)
     self.connector.set_balance(self.quote_asset, self.quote_balance)
     self.connector.set_quantization_param(
         QuantizationParams(self.trading_pair, 6, 6, 6, 6))
     self.clock.add_iterator(self.connector)
     ScriptStrategyBase.markets = {self.connector_name: {self.trading_pair}}
     self.strategy = ScriptStrategyBase(
         {self.connector_name: self.connector})
     self.strategy.logger().setLevel(1)
     self.strategy.logger().addHandler(self)
Example #11
0
    def setUp(self) -> None:
        np.random.seed(self.INITIAL_RANDOM_SEED)

        trade_fee_schema = TradeFeeSchema(
            maker_percent_fee_decimal=Decimal("0.25"),
            taker_percent_fee_decimal=Decimal("0.25"))
        client_config_map = ClientConfigAdapter(ClientConfigMap())
        self.market: MockPaperExchange = MockPaperExchange(
            client_config_map, trade_fee_schema)
        self.market_info: MarketTradingPairTuple = MarketTradingPairTuple(
            self.market, self.trading_pair, *self.trading_pair.split("-"))
        self.market.set_balanced_order_book(trading_pair=self.trading_pair,
                                            mid_price=self.initial_mid_price,
                                            min_price=1,
                                            max_price=200,
                                            price_step_size=1,
                                            volume_step_size=10)
        self.market.set_balance("COINALPHA", 1)
        self.market.set_balance("HBOT", 500)
        self.market.set_quantization_param(
            QuantizationParams(self.trading_pair.split("-")[0], 6, 6, 6, 6))

        self.price_delegate = OrderBookAssetPriceDelegate(
            self.market_info.market, self.trading_pair)

        self.indicator = TradingIntensityIndicator(
            order_book=self.market_info.order_book,
            price_delegate=self.price_delegate,
            sampling_length=self.BUFFER_LENGTH)
    def create_market(trading_pairs: List[str], mid_price, balances: Dict[str, int]) -> \
            (MockPaperExchange, Dict[str, MarketTradingPairTuple]):
        """
        Create a BacktestMarket and marketinfo dictionary to be used by the liquidity mining strategy
        """
        market: MockPaperExchange = MockPaperExchange(
            client_config_map=ClientConfigAdapter(ClientConfigMap())
        )
        market_infos: Dict[str, MarketTradingPairTuple] = {}

        for trading_pair in trading_pairs:
            base_asset = trading_pair.split("-")[0]
            quote_asset = trading_pair.split("-")[1]
            market.set_balanced_order_book(trading_pair=trading_pair,
                                           mid_price=mid_price,
                                           min_price=1,
                                           max_price=200,
                                           price_step_size=1,
                                           volume_step_size=10)
            market.set_quantization_param(QuantizationParams(trading_pair, 6, 6, 6, 6))
            market_infos[trading_pair] = MarketTradingPairTuple(market, trading_pair, base_asset, quote_asset)

        for asset, value in balances.items():
            market.set_balance(asset, value)

        return market, market_infos
Example #13
0
 def setUp(self):
     self.clock_tick_size = 1
     self.clock: Clock = Clock(ClockMode.BACKTEST, self.clock_tick_size,
                               self.start_timestamp, self.end_timestamp)
     self.market: MockPaperExchange = MockPaperExchange(
         client_config_map=ClientConfigAdapter(ClientConfigMap()))
     self.mid_price = 100
     self.bid_spread = 0.01
     self.ask_spread = 0.01
     self.order_refresh_time = 30
     self.market.set_balanced_order_book(trading_pair=self.trading_pair,
                                         mid_price=self.mid_price,
                                         min_price=1,
                                         max_price=200,
                                         price_step_size=1,
                                         volume_step_size=10)
     self.market.set_balance("HBOT", 500)
     self.market.set_balance("ETH", 5000)
     self.market.set_quantization_param(
         QuantizationParams(self.trading_pair, 6, 6, 6, 6))
     self.market_info = MarketTradingPairTuple(self.market,
                                               self.trading_pair,
                                               self.base_asset,
                                               self.quote_asset)
     self.clock.add_iterator(self.market)
     self.maker_order_fill_logger: EventLogger = EventLogger()
     self.cancel_order_logger: EventLogger = EventLogger()
     self.market.add_listener(MarketEvent.OrderFilled,
                              self.maker_order_fill_logger)
     self.market.add_listener(MarketEvent.OrderCancelled,
                              self.cancel_order_logger)
    def setUp(self):
        self.market: MockPaperExchange = MockPaperExchange(
            client_config_map=ClientConfigAdapter(ClientConfigMap()))
        self.market_info: MarketTradingPairTuple = MarketTradingPairTuple(
            self.market, self.trading_pair, *self.trading_pair.split("-"))

        self.strategy: StrategyPyBase = MockPyStrategy()
        self.strategy.add_markets([self.market])
    def test_adjust_candidate_insufficient_funds_for_flat_fees_and_percent_fees(
            self):
        trade_fee_schema = TradeFeeSchema(
            maker_percent_fee_decimal=Decimal("0.1"),
            maker_fixed_fees=[TokenAmount(self.quote_asset, Decimal("1"))],
        )
        exchange = MockPaperExchange(client_config_map=ClientConfigAdapter(
            ClientConfigMap()),
                                     trade_fee_schema=trade_fee_schema)
        budget_checker: BudgetChecker = exchange.budget_checker
        exchange.set_balance(self.quote_asset, Decimal("12"))

        order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.BUY,
            amount=Decimal("10"),
            price=Decimal("2"),
        )
        adjusted_candidate = budget_checker.adjust_candidate(order_candidate,
                                                             all_or_none=False)

        self.assertEqual(Decimal("5"), adjusted_candidate.amount)
        self.assertEqual(self.quote_asset,
                         adjusted_candidate.order_collateral.token)
        self.assertEqual(Decimal("10"),
                         adjusted_candidate.order_collateral.amount)
        self.assertEqual(self.quote_asset,
                         adjusted_candidate.percent_fee_collateral.token)
        self.assertEqual(Decimal("1"),
                         adjusted_candidate.percent_fee_collateral.amount)
        self.assertEqual(self.quote_asset,
                         adjusted_candidate.percent_fee_value.token)
        self.assertEqual(Decimal("1"),
                         adjusted_candidate.percent_fee_value.amount)
        self.assertEqual(1, len(adjusted_candidate.fixed_fee_collaterals))

        fixed_fee_collateral = adjusted_candidate.fixed_fee_collaterals[0]

        self.assertEqual(self.quote_asset, fixed_fee_collateral.token)
        self.assertEqual(Decimal("1"), fixed_fee_collateral.amount)
        self.assertEqual(self.base_asset,
                         adjusted_candidate.potential_returns.token)
        self.assertEqual(Decimal("5"),
                         adjusted_candidate.potential_returns.amount)
Example #16
0
    def test_add_markets(self):

        self.assertEqual(1, len(self.strategy.active_markets))

        new_market: MockPaperExchange = MockPaperExchange(
            client_config_map=ClientConfigAdapter(ClientConfigMap()))
        self.strategy.add_markets([new_market])

        self.assertEqual(2, len(self.strategy.active_markets))
Example #17
0
    def setUp(self):

        super().setUp()
        self.log_records = []

        self.clock: Clock = Clock(ClockMode.BACKTEST, self.clock_tick_size, self.start_timestamp, self.end_timestamp)
        self.market: MockPaperExchange = MockPaperExchange(
            client_config_map=ClientConfigAdapter(ClientConfigMap())
        )
        self.mid_price = 100
        self.order_delay_time = 15
        self.cancel_order_wait_time = 45
        self.market.set_balanced_order_book(trading_pair=self.maker_trading_pairs[0],
                                            mid_price=self.mid_price, min_price=1,
                                            max_price=200, price_step_size=1, volume_step_size=10)
        self.market.set_balance("COINALPHA", 500)
        self.market.set_balance("WETH", 50000)
        self.market.set_balance("QETH", 500)
        self.market.set_quantization_param(
            QuantizationParams(
                self.maker_trading_pairs[0], 6, 6, 6, 6
            )
        )

        self.market_info: MarketTradingPairTuple = MarketTradingPairTuple(*([self.market] + self.maker_trading_pairs))

        # Define strategies to test
        self.limit_buy_strategy: TwapTradeStrategy = TwapTradeStrategy(
            [self.market_info],
            order_price=Decimal("99"),
            cancel_order_wait_time=self.cancel_order_wait_time,
            is_buy=True,
            order_delay_time=self.order_delay_time,
            target_asset_amount=Decimal("2.0"),
            order_step_size=Decimal("1.0")
        )
        self.limit_sell_strategy: TwapTradeStrategy = TwapTradeStrategy(
            [self.market_info],
            order_price=Decimal("101"),
            cancel_order_wait_time=self.cancel_order_wait_time,
            is_buy=False,
            order_delay_time=self.order_delay_time,
            target_asset_amount=Decimal("5.0"),
            order_step_size=Decimal("1.67")
        )

        self.clock.add_iterator(self.market)
        self.maker_order_fill_logger: EventLogger = EventLogger()
        self.cancel_order_logger: EventLogger = EventLogger()
        self.buy_order_completed_logger: EventLogger = EventLogger()
        self.sell_order_completed_logger: EventLogger = EventLogger()

        self.market.add_listener(MarketEvent.BuyOrderCompleted, self.buy_order_completed_logger)
        self.market.add_listener(MarketEvent.SellOrderCompleted, self.sell_order_completed_logger)
        self.market.add_listener(MarketEvent.OrderFilled, self.maker_order_fill_logger)
        self.market.add_listener(MarketEvent.OrderCancelled, self.cancel_order_logger)
 def setUpClass(cls):
     cls.ev_loop = asyncio.get_event_loop()
     cls.clock: Clock = Clock(ClockMode.BACKTEST, cls.tick_size, cls.start_timestamp, cls.end_timestamp)
     cls.market: MockPaperExchange = MockPaperExchange(
         client_config_map=ClientConfigAdapter(ClientConfigMap())
     )
     cls.strategy: GetOrderBookStrategy = GetOrderBookStrategy(
         exchange=cls.market,
         trading_pair=cls.trading_pair,
     )
Example #19
0
    def test_empty_maker_orderbook(self):
        self.clock.remove_iterator(self.strategy)
        self.clock.remove_iterator(self.maker_market)
        self.maker_market: MockPaperExchange = MockPaperExchange(
            client_config_map=ClientConfigAdapter(ClientConfigMap()))

        # Orderbook is empty
        self.maker_market.new_empty_order_book(self.trading_pairs_maker[0])
        self.market_pair: CrossExchangeMarketPair = CrossExchangeMarketPair(
            MarketTradingPairTuple(self.maker_market,
                                   *self.trading_pairs_maker),
            MarketTradingPairTuple(self.taker_market,
                                   *self.trading_pairs_taker),
        )

        config_map_raw = deepcopy(self.config_map_raw)
        config_map_raw.min_profitability = Decimal("0.5")
        config_map_raw.adjust_order_enabled = False
        config_map_raw.order_amount = Decimal("1")

        config_map = ClientConfigAdapter(config_map_raw)

        self.strategy: CrossExchangeMarketMakingStrategy = CrossExchangeMarketMakingStrategy(
        )
        self.strategy.init_params(
            config_map=config_map,
            market_pairs=[self.market_pair],
            logging_options=self.logging_options,
        )
        self.maker_market.set_balance("COINALPHA", 5)
        self.maker_market.set_balance("WETH", 5)
        self.maker_market.set_balance("QETH", 5)
        self.maker_market.set_quantization_param(
            QuantizationParams(self.trading_pairs_maker[0], 4, 4, 4, 4))
        self.clock.add_iterator(self.strategy)
        self.clock.add_iterator(self.maker_market)
        self.clock.backtest_til(self.start_timestamp + 4)
        self.assertEqual(1, len(self.strategy.active_bids))
        self.assertEqual(1, len(self.strategy.active_asks))
        bid_order: LimitOrder = self.strategy.active_bids[0][1]
        ask_order: LimitOrder = self.strategy.active_asks[0][1]
        # Places orders based on taker orderbook
        self.assertEqual(Decimal("0.9945"), bid_order.price)
        self.assertEqual(Decimal("1.006"), ask_order.price)
        self.assertAlmostEqual(Decimal("1"), round(bid_order.quantity, 4))
        self.assertAlmostEqual(Decimal("1"), round(ask_order.quantity, 4))
Example #20
0
    def test_with_adjust_orders_enabled(self):
        self.clock.remove_iterator(self.strategy)
        self.clock.remove_iterator(self.maker_market)
        self.maker_market: MockPaperExchange = MockPaperExchange(
            client_config_map=ClientConfigAdapter(ClientConfigMap()))
        self.maker_market.set_balanced_order_book(self.trading_pairs_maker[0],
                                                  1.0, 0.5, 1.5, 0.1, 10)
        self.market_pair: CrossExchangeMarketPair = CrossExchangeMarketPair(
            MarketTradingPairTuple(self.maker_market,
                                   *self.trading_pairs_maker),
            MarketTradingPairTuple(self.taker_market,
                                   *self.trading_pairs_taker),
        )

        config_map_raw = deepcopy(self.config_map_raw)
        config_map_raw.order_size_portfolio_ratio_limit = Decimal("30")
        config_map_raw.min_profitability = Decimal("0.5")
        config_map_raw.adjust_order_enabled = True
        config_map = ClientConfigAdapter(config_map_raw)

        self.strategy: CrossExchangeMarketMakingStrategy = CrossExchangeMarketMakingStrategy(
        )
        self.strategy.init_params(
            config_map=config_map,
            market_pairs=[self.market_pair],
            logging_options=self.logging_options,
        )
        self.maker_market.set_balance("COINALPHA", 5)
        self.maker_market.set_balance("WETH", 5)
        self.maker_market.set_balance("QETH", 5)
        self.maker_market.set_quantization_param(
            QuantizationParams(self.trading_pairs_maker[0], 4, 4, 4, 4))
        self.clock.add_iterator(self.strategy)
        self.clock.add_iterator(self.maker_market)
        self.clock.backtest_til(self.start_timestamp + 5)
        self.assertEqual(1, len(self.strategy.active_bids))
        self.assertEqual(1, len(self.strategy.active_asks))
        bid_order: LimitOrder = self.strategy.active_bids[0][1]
        ask_order: LimitOrder = self.strategy.active_asks[0][1]
        # place above top bid (at 0.95)
        self.assertAlmostEqual(Decimal("0.9501"), bid_order.price)
        # place below top ask (at 1.05)
        self.assertAlmostEqual(Decimal("1.049"), ask_order.price)
        self.assertAlmostEqual(Decimal("3"), round(bid_order.quantity, 4))
        self.assertAlmostEqual(Decimal("3"), round(ask_order.quantity, 4))
    def setUp(self):
        self.clock: Clock = Clock(ClockMode.BACKTEST, self.clock_tick_size, self.start_timestamp, self.end_timestamp)
        self.market: MockPaperExchange = MockPaperExchange(
            client_config_map=ClientConfigAdapter(ClientConfigMap())
        )
        self.market.set_balanced_order_book(trading_pair=self.trading_pair,
                                            mid_price=100,
                                            min_price=50,
                                            max_price=150,
                                            price_step_size=1,
                                            volume_step_size=10)
        self.market.set_balance("COINALPHA", self.base_balance)
        self.market.set_balance("HBOT", self.quote_balance)
        self.market.set_quantization_param(
            QuantizationParams(
                self.trading_pair, 6, 6, 6, 6
            )
        )

        self.market_info = MarketTradingPairTuple(self.market, self.trading_pair, self.base_asset, self.quote_asset)
    def test_populate_collateral_fields_fixed_fees_in_quote_token(self):
        trade_fee_schema = TradeFeeSchema(
            maker_fixed_fees=[TokenAmount(self.quote_asset, Decimal("1"))],
            taker_fixed_fees=[TokenAmount(self.base_asset, Decimal("2"))],
        )
        exchange = MockPaperExchange(client_config_map=ClientConfigAdapter(
            ClientConfigMap()),
                                     trade_fee_schema=trade_fee_schema)
        budget_checker: BudgetChecker = exchange.budget_checker

        order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.BUY,
            amount=Decimal("10"),
            price=Decimal("2"),
        )
        populated_candidate = budget_checker.populate_collateral_entries(
            order_candidate)

        self.assertEqual(self.quote_asset,
                         populated_candidate.order_collateral.token)
        self.assertEqual(Decimal("20"),
                         populated_candidate.order_collateral.amount)
        self.assertIsNone(populated_candidate.percent_fee_collateral)
        self.assertIsNone(populated_candidate.percent_fee_value)
        self.assertEqual(1, len(populated_candidate.fixed_fee_collaterals))

        fixed_fee_collateral = populated_candidate.fixed_fee_collaterals[0]

        self.assertEqual(self.quote_asset, fixed_fee_collateral.token)
        self.assertEqual(Decimal("1"), fixed_fee_collateral.amount)
        self.assertEqual(self.base_asset,
                         populated_candidate.potential_returns.token)
        self.assertEqual(Decimal("10"),
                         populated_candidate.potential_returns.amount)
    def test_adjust_candidate_insufficient_funds_for_flat_fees_third_token(
            self):
        fee_asset = "FEE"
        trade_fee_schema = TradeFeeSchema(
            maker_fixed_fees=[TokenAmount(fee_asset, Decimal("11"))], )
        exchange = MockPaperExchange(client_config_map=ClientConfigAdapter(
            ClientConfigMap()),
                                     trade_fee_schema=trade_fee_schema)
        budget_checker: BudgetChecker = exchange.budget_checker
        exchange.set_balance(self.quote_asset, Decimal("100"))
        exchange.set_balance(fee_asset, Decimal("10"))

        order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.BUY,
            amount=Decimal("10"),
            price=Decimal("2"),
        )
        adjusted_candidate = budget_checker.adjust_candidate(order_candidate,
                                                             all_or_none=False)

        self.assertTrue(adjusted_candidate.is_zero_order)
    def setUp(self):
        self.clock: Clock = Clock(ClockMode.BACKTEST, self.clock_tick_size,
                                  self.start_timestamp, self.end_timestamp)
        self.mid_price = 100
        self.time_delay = 15
        self.cancel_order_wait_time = 45

        self.market: MockPaperExchange = MockPaperExchange(
            client_config_map=ClientConfigAdapter(ClientConfigMap()))
        self.market.set_balanced_order_book(trading_pair=self.trading_pair,
                                            mid_price=self.mid_price,
                                            min_price=1,
                                            max_price=200,
                                            price_step_size=1,
                                            volume_step_size=10)

        self.market.set_balance("COINALPHA", 500)
        self.market.set_balance("WETH", 5000)
        self.market.set_quantization_param(
            QuantizationParams(self.trading_pair, 6, 6, 6, 6))

        self.market_info: MarketTradingPairTuple = MarketTradingPairTuple(
            self.market, self.trading_pair, self.base_asset, self.quote_asset)

        # Define strategies to test
        self.buy_mid_price_strategy: PerformTradeStrategy = PerformTradeStrategy(
            exchange=self.market,
            trading_pair=self.trading_pair,
            is_buy=True,
            spread=self.spread,
            order_amount=Decimal("1.0"),
            price_type=PriceType.MidPrice)

        self.sell_mid_price_strategy: PerformTradeStrategy = PerformTradeStrategy(
            exchange=self.market,
            trading_pair=self.trading_pair,
            is_buy=False,
            spread=self.spread,
            order_amount=Decimal("1.0"),
            price_type=PriceType.MidPrice)

        self.buy_last_price_strategy: PerformTradeStrategy = PerformTradeStrategy(
            exchange=self.market,
            trading_pair=self.trading_pair,
            is_buy=True,
            spread=self.spread,
            order_amount=Decimal("1.0"),
            price_type=PriceType.LastTrade)

        self.sell_last_price_strategy: PerformTradeStrategy = PerformTradeStrategy(
            exchange=self.market,
            trading_pair=self.trading_pair,
            is_buy=False,
            spread=self.spread,
            order_amount=Decimal("1.0"),
            price_type=PriceType.LastTrade)

        self.buy_last_own_trade_price_strategy: PerformTradeStrategy = PerformTradeStrategy(
            exchange=self.market,
            trading_pair=self.trading_pair,
            is_buy=True,
            spread=self.spread,
            order_amount=Decimal("1.0"),
            price_type=PriceType.LastOwnTrade)

        self.sell_last_own_trade_price_strategy: PerformTradeStrategy = PerformTradeStrategy(
            exchange=self.market,
            trading_pair=self.trading_pair,
            is_buy=False,
            spread=self.spread,
            order_amount=Decimal("1.0"),
            price_type=PriceType.LastOwnTrade)

        self.clock.add_iterator(self.market)
        self.maker_order_fill_logger: EventLogger = EventLogger()
        self.cancel_order_logger: EventLogger = EventLogger()
        self.buy_order_completed_logger: EventLogger = EventLogger()
        self.sell_order_completed_logger: EventLogger = EventLogger()

        self.market.add_listener(MarketEvent.BuyOrderCompleted,
                                 self.buy_order_completed_logger)
        self.market.add_listener(MarketEvent.SellOrderCompleted,
                                 self.sell_order_completed_logger)
        self.market.add_listener(MarketEvent.OrderFilled,
                                 self.maker_order_fill_logger)
        self.market.add_listener(MarketEvent.OrderCancelled,
                                 self.cancel_order_logger)
    def simulate_limit_order_fill(market: MockPaperExchange,
                                  limit_order: LimitOrder, timestamp: float):
        quote_currency_traded: Decimal = limit_order.price * limit_order.quantity
        base_currency_traded: Decimal = limit_order.quantity
        quote_currency: str = limit_order.quote_currency
        base_currency: str = limit_order.base_currency

        trade_event = OrderBookTradeEvent(
            trading_pair=limit_order.trading_pair,
            timestamp=timestamp,
            type=TradeType.BUY if limit_order.is_buy else TradeType.SELL,
            price=limit_order.price,
            amount=limit_order.quantity,
        )

        if limit_order.is_buy:
            market.set_balance(
                quote_currency,
                market.get_balance(quote_currency) - quote_currency_traded)
            market.set_balance(
                base_currency,
                market.get_balance(base_currency) + base_currency_traded)
            market.trigger_event(
                MarketEvent.OrderFilled,
                OrderFilledEvent(market.current_timestamp,
                                 limit_order.client_order_id,
                                 limit_order.trading_pair, TradeType.BUY,
                                 OrderType.LIMIT, limit_order.price,
                                 limit_order.quantity,
                                 AddedToCostTradeFee(Decimal(0.0))))
            market.trigger_event(
                MarketEvent.BuyOrderCompleted,
                BuyOrderCompletedEvent(market.current_timestamp,
                                       limit_order.client_order_id,
                                       base_currency, quote_currency,
                                       base_currency_traded,
                                       quote_currency_traded, OrderType.LIMIT))
            market.order_books[limit_order.trading_pair].apply_trade(
                trade_event)
        else:
            market.set_balance(
                quote_currency,
                market.get_balance(quote_currency) + quote_currency_traded)
            market.set_balance(
                base_currency,
                market.get_balance(base_currency) - base_currency_traded)
            market.trigger_event(
                MarketEvent.OrderFilled,
                OrderFilledEvent(market.current_timestamp,
                                 limit_order.client_order_id,
                                 limit_order.trading_pair, TradeType.SELL,
                                 OrderType.LIMIT, limit_order.price,
                                 limit_order.quantity,
                                 AddedToCostTradeFee(Decimal(0.0))))
            market.trigger_event(
                MarketEvent.SellOrderCompleted,
                SellOrderCompletedEvent(market.current_timestamp,
                                        limit_order.client_order_id,
                                        base_currency, quote_currency,
                                        base_currency_traded,
                                        quote_currency_traded,
                                        OrderType.LIMIT))
            market.order_books[limit_order.trading_pair].apply_trade(
                trade_event)
    def simulate_limit_order_fill(market: MockPaperExchange, limit_order: LimitOrder):
        quote_currency_traded: Decimal = limit_order.price * limit_order.quantity
        base_currency_traded: Decimal = limit_order.quantity
        quote_currency: str = limit_order.quote_currency
        base_currency: str = limit_order.base_currency

        if limit_order.is_buy:
            market.set_balance(quote_currency, market.get_balance(quote_currency) - quote_currency_traded)
            market.set_balance(base_currency, market.get_balance(base_currency) + base_currency_traded)
        else:
            market.set_balance(quote_currency, market.get_balance(quote_currency) + quote_currency_traded)
            market.set_balance(base_currency, market.get_balance(base_currency) - base_currency_traded)

        market.trigger_event(MarketEvent.OrderFilled, OrderFilledEvent(
            market.current_timestamp,
            limit_order.client_order_id,
            limit_order.trading_pair,
            TradeType.BUY if limit_order.is_buy else TradeType.SELL,
            OrderType.LIMIT,
            limit_order.price,
            limit_order.quantity,
            AddedToCostTradeFee(Decimal("0"))
        ))
        event_type = MarketEvent.BuyOrderCompleted if limit_order.is_buy else MarketEvent.SellOrderCompleted
        event_class = BuyOrderCompletedEvent if limit_order.is_buy else SellOrderCompletedEvent
        market.trigger_event(event_type, event_class(
            market.current_timestamp,
            limit_order.client_order_id,
            base_currency,
            quote_currency,
            base_currency_traded,
            quote_currency_traded,
            OrderType.LIMIT
        ))
    def setUp(self):
        self.log_records = []
        self.order_fill_logger: EventLogger = EventLogger()
        self.cancel_order_logger: EventLogger = EventLogger()
        self.clock: Clock = Clock(ClockMode.BACKTEST, 1, self.start_timestamp,
                                  self.end_timestamp)
        self.spot_connector: MockPaperExchange = MockPaperExchange(
            client_config_map=ClientConfigAdapter(ClientConfigMap()))
        self.spot_connector.set_balanced_order_book(trading_pair=trading_pair,
                                                    mid_price=100,
                                                    min_price=1,
                                                    max_price=200,
                                                    price_step_size=1,
                                                    volume_step_size=10)
        self.spot_connector.set_balance(base_asset, 5)
        self.spot_connector.set_balance(quote_asset, 500)
        self.spot_connector.set_quantization_param(
            QuantizationParams(trading_pair, 6, 6, 6, 6))
        self.spot_market_info = MarketTradingPairTuple(self.spot_connector,
                                                       trading_pair,
                                                       base_asset, quote_asset)

        self.perp_connector: MockPerpConnector = MockPerpConnector(
            client_config_map=ClientConfigAdapter(ClientConfigMap()))
        self.perp_connector.set_leverage(trading_pair, 5)
        self.perp_connector.set_balanced_order_book(trading_pair=trading_pair,
                                                    mid_price=110,
                                                    min_price=1,
                                                    max_price=200,
                                                    price_step_size=1,
                                                    volume_step_size=10)
        self.perp_connector.set_balance(base_asset, 5)
        self.perp_connector.set_balance(quote_asset, 500)
        self.perp_connector.set_quantization_param(
            QuantizationParams(trading_pair, 6, 6, 6, 6))
        self.perp_market_info = MarketTradingPairTuple(self.perp_connector,
                                                       trading_pair,
                                                       base_asset, quote_asset)

        self.clock.add_iterator(self.spot_connector)
        self.clock.add_iterator(self.perp_connector)

        self.spot_connector.add_listener(MarketEvent.OrderFilled,
                                         self.order_fill_logger)
        self.spot_connector.add_listener(MarketEvent.OrderCancelled,
                                         self.cancel_order_logger)
        self.perp_connector.add_listener(MarketEvent.OrderFilled,
                                         self.order_fill_logger)
        self.perp_connector.add_listener(MarketEvent.OrderCancelled,
                                         self.cancel_order_logger)

        self.strategy = SpotPerpetualArbitrageStrategy()
        self.strategy.init_params(
            spot_market_info=self.spot_market_info,
            perp_market_info=self.perp_market_info,
            order_amount=Decimal("1"),
            perp_leverage=5,
            min_opening_arbitrage_pct=Decimal("0.05"),
            min_closing_arbitrage_pct=Decimal("0.01"),
            next_arbitrage_opening_delay=10,
        )
        self.strategy.logger().setLevel(1)
        self.strategy.logger().addHandler(self)
        self._last_tick = 0
Example #28
0
    def setUp(self):

        self.clock: Clock = Clock(ClockMode.BACKTEST, self.clock_tick_size,
                                  self.start_timestamp, self.end_timestamp)
        self.market: MockPaperExchange = MockPaperExchange(
            client_config_map=ClientConfigAdapter(ClientConfigMap()))
        self.mid_price = 100
        self.time_delay = 15
        self.cancel_order_wait_time = 45
        self.market.set_balanced_order_book(self.maker_symbols[0],
                                            mid_price=self.mid_price,
                                            min_price=1,
                                            max_price=200,
                                            price_step_size=1,
                                            volume_step_size=10)
        self.market.set_balance("COINALPHA", 500)
        self.market.set_balance("WETH", 500000000000)
        self.market.set_balance("QETH", 500)
        self.market.set_quantization_param(
            QuantizationParams(self.maker_symbols[0], 6, 6, 6, 6))

        self.market_info: MarketTradingPairTuple = MarketTradingPairTuple(
            *([self.market] + self.maker_symbols))

        # Define strategies to test
        self.limit_buy_strategy: Dev5TwapTradeStrategy = Dev5TwapTradeStrategy(
            [self.market_info],
            order_type="limit",
            order_price=Decimal("99"),
            cancel_order_wait_time=self.cancel_order_wait_time,
            is_buy=True,
            time_delay=self.time_delay,
            is_vwap=True,
            percent_slippage=50.0,
            order_percent_of_volume=0.5,
            order_amount=Decimal("100.0"))
        self.limit_sell_strategy: Dev5TwapTradeStrategy = Dev5TwapTradeStrategy(
            [self.market_info],
            order_type="limit",
            order_price=Decimal("101"),
            cancel_order_wait_time=self.cancel_order_wait_time,
            is_buy=False,
            time_delay=self.time_delay,
            is_vwap=True,
            percent_slippage=50.0,
            order_percent_of_volume=0.5,
            order_amount=Decimal("100.0"))
        self.market_buy_strategy: Dev5TwapTradeStrategy = Dev5TwapTradeStrategy(
            [self.market_info],
            order_type="market",
            order_price=None,
            cancel_order_wait_time=self.cancel_order_wait_time,
            is_buy=True,
            time_delay=self.time_delay,
            is_vwap=True,
            percent_slippage=50.0,
            order_percent_of_volume=0.5,
            order_amount=Decimal("100.0"))
        self.market_sell_strategy: Dev5TwapTradeStrategy = Dev5TwapTradeStrategy(
            [self.market_info],
            order_type="market",
            order_price=None,
            cancel_order_wait_time=self.cancel_order_wait_time,
            is_buy=False,
            time_delay=self.time_delay,
            is_vwap=True,
            percent_slippage=50.0,
            order_percent_of_volume=0.5,
            order_amount=Decimal("100.0"))
        self.clock.add_iterator(self.market)
        self.maker_order_fill_logger: EventLogger = EventLogger()
        self.cancel_order_logger: EventLogger = EventLogger()
        self.buy_order_completed_logger: EventLogger = EventLogger()
        self.sell_order_completed_logger: EventLogger = EventLogger()

        self.market.add_listener(MarketEvent.BuyOrderCompleted,
                                 self.buy_order_completed_logger)
        self.market.add_listener(MarketEvent.SellOrderCompleted,
                                 self.sell_order_completed_logger)
        self.market.add_listener(MarketEvent.OrderFilled,
                                 self.maker_order_fill_logger)
        self.market.add_listener(MarketEvent.OrderCancelled,
                                 self.cancel_order_logger)
    def setUp(self):
        self.clock_tick_size = 1
        self.clock: Clock = Clock(ClockMode.BACKTEST, self.clock_tick_size, self.start_timestamp, self.end_timestamp)
        self.client_config_map = ClientConfigAdapter(ClientConfigMap())

        self.market: MockPaperExchange = MockPaperExchange(self.client_config_map)
        self.mid_price = 100
        self.start_order_spread = 0.01
        self.order_refresh_time = 30

        self.n_levels = 10
        self.grid_price_ceiling = 200
        self.grid_price_floor = 20

        self.market.set_balanced_order_book(self.trading_pair,
                                            mid_price=self.mid_price,
                                            min_price=1,
                                            max_price=200,
                                            price_step_size=1,
                                            volume_step_size=10)
        self.market.set_balance("HBOT", 500)
        self.market.set_balance("ETH", 5000)
        self.market.set_quantization_param(
            QuantizationParams(
                self.trading_pair, 6, 6, 6, 6
            )
        )
        self.market_info = MarketTradingPairTuple(self.market, self.trading_pair,
                                                  self.base_asset, self.quote_asset)
        self.clock.add_iterator(self.market)
        self.order_fill_logger: EventLogger = EventLogger()
        self.cancel_order_logger: EventLogger = EventLogger()
        self.market.add_listener(MarketEvent.OrderFilled, self.order_fill_logger)
        self.market.add_listener(MarketEvent.OrderCancelled, self.cancel_order_logger)

        self.quote_required_strategy = FixedGridStrategy()
        self.quote_required_strategy.init_params(
            self.market_info,
            n_levels=10,
            grid_price_floor = Decimal("20"),
            grid_price_ceiling = Decimal("200"),
            start_order_spread=Decimal("0.01"),
            order_amount=Decimal("52"),
            order_refresh_time=30.0
        )

        self.base_required_strategy = FixedGridStrategy()
        self.base_required_strategy.init_params(
            self.market_info,
            n_levels=10,
            grid_price_floor = Decimal("110"),
            grid_price_ceiling = Decimal("200"),
            start_order_spread=Decimal("0.01"),
            order_amount=Decimal("60"),
            order_refresh_time=30.0
        )

        self.no_rebalance_strategy = FixedGridStrategy()
        self.no_rebalance_strategy.init_params(
            self.market_info,
            n_levels=10,
            grid_price_floor = Decimal("40"),
            grid_price_ceiling = Decimal("130"),
            start_order_spread=Decimal("0.01"),
            order_amount=Decimal("5"),
            order_refresh_time=10.0
        )
class BudgetCheckerTest(unittest.TestCase):
    def setUp(self) -> None:
        super().setUp()
        self.base_asset = "COINALPHA"
        self.quote_asset = "HBOT"
        self.trading_pair = f"{self.base_asset}-{self.quote_asset}"

        trade_fee_schema = TradeFeeSchema(
            maker_percent_fee_decimal=Decimal("0.01"),
            taker_percent_fee_decimal=Decimal("0.02"))
        self.exchange = MockPaperExchange(
            client_config_map=ClientConfigAdapter(ClientConfigMap()),
            trade_fee_schema=trade_fee_schema)
        self.budget_checker: BudgetChecker = self.exchange.budget_checker

    def test_populate_collateral_fields_buy_order(self):
        order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.BUY,
            amount=Decimal("10"),
            price=Decimal("2"),
        )
        populated_candidate = self.budget_checker.populate_collateral_entries(
            order_candidate)

        self.assertEqual(self.quote_asset,
                         populated_candidate.order_collateral.token)
        self.assertEqual(Decimal("20"),
                         populated_candidate.order_collateral.amount)
        self.assertEqual(self.quote_asset,
                         populated_candidate.percent_fee_collateral.token)
        self.assertEqual(Decimal("0.2"),
                         populated_candidate.percent_fee_collateral.amount)
        self.assertEqual(self.quote_asset,
                         populated_candidate.percent_fee_value.token)
        self.assertEqual(Decimal("0.2"),
                         populated_candidate.percent_fee_value.amount)
        self.assertEqual(0, len(populated_candidate.fixed_fee_collaterals))
        self.assertEqual(self.base_asset,
                         populated_candidate.potential_returns.token)
        self.assertEqual(Decimal("10"),
                         populated_candidate.potential_returns.amount)

    def test_populate_collateral_fields_taker_buy_order(self):
        order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=False,
            order_type=OrderType.LIMIT,
            order_side=TradeType.BUY,
            amount=Decimal("10"),
            price=Decimal("2"),
        )
        populated_candidate = self.budget_checker.populate_collateral_entries(
            order_candidate)

        self.assertEqual(self.quote_asset,
                         populated_candidate.order_collateral.token)
        self.assertEqual(Decimal("20"),
                         populated_candidate.order_collateral.amount)
        self.assertEqual(self.quote_asset,
                         populated_candidate.percent_fee_collateral.token)
        self.assertEqual(Decimal("0.4"),
                         populated_candidate.percent_fee_collateral.amount)
        self.assertEqual(self.quote_asset,
                         populated_candidate.percent_fee_value.token)
        self.assertEqual(Decimal("0.4"),
                         populated_candidate.percent_fee_value.amount)
        self.assertEqual(0, len(populated_candidate.fixed_fee_collaterals))
        self.assertEqual(self.base_asset,
                         populated_candidate.potential_returns.token)
        self.assertEqual(Decimal("10"),
                         populated_candidate.potential_returns.amount)

    def test_populate_collateral_fields_buy_order_percent_fee_from_returns(
            self):
        trade_fee_schema = TradeFeeSchema(
            maker_percent_fee_decimal=Decimal("0.01"),
            taker_percent_fee_decimal=Decimal("0.01"),
            buy_percent_fee_deducted_from_returns=True,
        )
        exchange = MockPaperExchange(client_config_map=ClientConfigAdapter(
            ClientConfigMap()),
                                     trade_fee_schema=trade_fee_schema)
        budget_checker: BudgetChecker = exchange.budget_checker
        order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.BUY,
            amount=Decimal("10"),
            price=Decimal("2"),
        )
        populated_candidate = budget_checker.populate_collateral_entries(
            order_candidate)

        self.assertEqual(self.quote_asset,
                         populated_candidate.order_collateral.token)
        self.assertEqual(Decimal("20"),
                         populated_candidate.order_collateral.amount)
        self.assertIsNone(populated_candidate.percent_fee_collateral)
        self.assertEqual(self.base_asset,
                         populated_candidate.percent_fee_value.token)
        self.assertEqual(Decimal("0.1"),
                         populated_candidate.percent_fee_value.amount)
        self.assertEqual(0, len(populated_candidate.fixed_fee_collaterals))
        self.assertEqual(self.base_asset,
                         populated_candidate.potential_returns.token)
        self.assertEqual(Decimal("9.90"),
                         populated_candidate.potential_returns.amount)

    def test_populate_collateral_fields_sell_order(self):
        order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.SELL,
            amount=Decimal("10"),
            price=Decimal("2"),
        )
        populated_candidate = self.budget_checker.populate_collateral_entries(
            order_candidate)

        self.assertEqual(self.base_asset,
                         populated_candidate.order_collateral.token)
        self.assertEqual(Decimal("10"),
                         populated_candidate.order_collateral.amount)
        self.assertIsNone(populated_candidate.percent_fee_collateral)
        self.assertEqual(self.quote_asset,
                         populated_candidate.percent_fee_value.token)
        self.assertEqual(Decimal("0.2"),
                         populated_candidate.percent_fee_value.amount)
        self.assertEqual(0, len(populated_candidate.fixed_fee_collaterals))
        self.assertEqual(self.quote_asset,
                         populated_candidate.potential_returns.token)
        self.assertEqual(Decimal("19.8"),
                         populated_candidate.potential_returns.amount)

    def test_populate_collateral_fields_percent_fees_in_third_token(self):
        pfc_token = "PFC"
        trade_fee_schema = TradeFeeSchema(
            percent_fee_token=pfc_token,
            maker_percent_fee_decimal=Decimal("0.01"),
            taker_percent_fee_decimal=Decimal("0.01"),
        )
        exchange = MockPaperExchange(client_config_map=ClientConfigAdapter(
            ClientConfigMap()),
                                     trade_fee_schema=trade_fee_schema)
        pfc_quote_pair = combine_to_hb_trading_pair(self.quote_asset,
                                                    pfc_token)
        exchange.set_balanced_order_book(  # the quote to pfc price will be 1:2
            trading_pair=pfc_quote_pair,
            mid_price=1.5,
            min_price=1,
            max_price=2,
            price_step_size=1,
            volume_step_size=1,
        )
        budget_checker: BudgetChecker = exchange.budget_checker

        order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.BUY,
            amount=Decimal("10"),
            price=Decimal("2"),
        )
        populated_candidate = budget_checker.populate_collateral_entries(
            order_candidate)

        self.assertEqual(self.quote_asset,
                         populated_candidate.order_collateral.token)
        self.assertEqual(Decimal("20"),
                         populated_candidate.order_collateral.amount)
        self.assertEqual(pfc_token,
                         populated_candidate.percent_fee_collateral.token)
        self.assertEqual(Decimal("0.4"),
                         populated_candidate.percent_fee_collateral.amount)
        self.assertEqual(pfc_token,
                         populated_candidate.percent_fee_value.token)
        self.assertEqual(Decimal("0.4"),
                         populated_candidate.percent_fee_value.amount)
        self.assertEqual(0, len(populated_candidate.fixed_fee_collaterals))
        self.assertEqual(self.base_asset,
                         populated_candidate.potential_returns.token)
        self.assertEqual(Decimal("10"),
                         populated_candidate.potential_returns.amount)

    def test_populate_collateral_fields_fixed_fees_in_quote_token(self):
        trade_fee_schema = TradeFeeSchema(
            maker_fixed_fees=[TokenAmount(self.quote_asset, Decimal("1"))],
            taker_fixed_fees=[TokenAmount(self.base_asset, Decimal("2"))],
        )
        exchange = MockPaperExchange(client_config_map=ClientConfigAdapter(
            ClientConfigMap()),
                                     trade_fee_schema=trade_fee_schema)
        budget_checker: BudgetChecker = exchange.budget_checker

        order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.BUY,
            amount=Decimal("10"),
            price=Decimal("2"),
        )
        populated_candidate = budget_checker.populate_collateral_entries(
            order_candidate)

        self.assertEqual(self.quote_asset,
                         populated_candidate.order_collateral.token)
        self.assertEqual(Decimal("20"),
                         populated_candidate.order_collateral.amount)
        self.assertIsNone(populated_candidate.percent_fee_collateral)
        self.assertIsNone(populated_candidate.percent_fee_value)
        self.assertEqual(1, len(populated_candidate.fixed_fee_collaterals))

        fixed_fee_collateral = populated_candidate.fixed_fee_collaterals[0]

        self.assertEqual(self.quote_asset, fixed_fee_collateral.token)
        self.assertEqual(Decimal("1"), fixed_fee_collateral.amount)
        self.assertEqual(self.base_asset,
                         populated_candidate.potential_returns.token)
        self.assertEqual(Decimal("10"),
                         populated_candidate.potential_returns.amount)

    def test_adjust_candidate_sufficient_funds(self):
        self.exchange.set_balance(self.quote_asset, Decimal("100"))

        order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.BUY,
            amount=Decimal("10"),
            price=Decimal("2"),
        )
        adjusted_candidate = self.budget_checker.adjust_candidate(
            order_candidate)

        self.assertEqual(self.quote_asset,
                         adjusted_candidate.order_collateral.token)
        self.assertEqual(Decimal("20"),
                         adjusted_candidate.order_collateral.amount)
        self.assertEqual(self.quote_asset,
                         adjusted_candidate.percent_fee_collateral.token)
        self.assertEqual(Decimal("0.2"),
                         adjusted_candidate.percent_fee_collateral.amount)
        self.assertEqual(self.quote_asset,
                         adjusted_candidate.percent_fee_value.token)
        self.assertEqual(Decimal("0.2"),
                         adjusted_candidate.percent_fee_value.amount)
        self.assertEqual(0, len(adjusted_candidate.fixed_fee_collaterals))
        self.assertEqual(self.base_asset,
                         adjusted_candidate.potential_returns.token)
        self.assertEqual(Decimal("10"),
                         adjusted_candidate.potential_returns.amount)

    def test_adjust_candidate_insufficient_funds_all_or_none(self):
        self.exchange.set_balance(self.quote_asset, Decimal("10"))

        order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.BUY,
            amount=Decimal("10"),
            price=Decimal("2"),
        )
        adjusted_candidate = self.budget_checker.adjust_candidate(
            order_candidate, all_or_none=True)

        self.assertEqual(0, adjusted_candidate.amount)
        self.assertIsNone(adjusted_candidate.order_collateral)
        self.assertIsNone(adjusted_candidate.percent_fee_collateral)
        self.assertIsNone(adjusted_candidate.percent_fee_value)
        self.assertEqual(0, len(adjusted_candidate.fixed_fee_collaterals))
        self.assertIsNone(adjusted_candidate.potential_returns)

    def test_adjust_candidate_buy_insufficient_funds_partial_adjustment_allowed(
            self):
        q_params = QuantizationParams(
            trading_pair=self.trading_pair,
            price_precision=8,
            price_decimals=2,
            order_size_precision=8,
            order_size_decimals=2,
        )
        self.exchange.set_quantization_param(q_params)
        self.exchange.set_balance(self.quote_asset, Decimal("10"))

        order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.BUY,
            amount=Decimal("10"),
            price=Decimal("2"),
        )
        adjusted_candidate = self.budget_checker.adjust_candidate(
            order_candidate, all_or_none=False)

        # order amount quantized to two decimal places
        self.assertEqual(Decimal("4.95"), adjusted_candidate.amount)  # 5 * .99
        self.assertEqual(self.quote_asset,
                         adjusted_candidate.order_collateral.token)
        self.assertEqual(
            Decimal("9.9"),
            adjusted_candidate.order_collateral.amount)  # 4.95 * 2
        self.assertEqual(self.quote_asset,
                         adjusted_candidate.percent_fee_collateral.token)
        self.assertEqual(
            Decimal("0.099"),
            adjusted_candidate.percent_fee_collateral.amount)  # 9.9 * 0.01
        self.assertEqual(self.quote_asset,
                         adjusted_candidate.percent_fee_value.token)
        self.assertEqual(
            Decimal("0.099"),
            adjusted_candidate.percent_fee_value.amount)  # 9.9 * 0.01
        self.assertEqual(0, len(adjusted_candidate.fixed_fee_collaterals))
        self.assertEqual(self.base_asset,
                         adjusted_candidate.potential_returns.token)
        self.assertEqual(Decimal("4.95"),
                         adjusted_candidate.potential_returns.amount)

    def test_adjust_candidate_sell_insufficient_funds_partial_adjustment_allowed(
            self):
        self.exchange.set_balance(self.base_asset, Decimal("5"))

        order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.SELL,
            amount=Decimal("10"),
            price=Decimal("2"),
        )
        adjusted_candidate = self.budget_checker.adjust_candidate(
            order_candidate, all_or_none=False)

        self.assertEqual(Decimal("5"), adjusted_candidate.amount)
        self.assertEqual(self.base_asset,
                         adjusted_candidate.order_collateral.token)
        self.assertEqual(Decimal("5"),
                         adjusted_candidate.order_collateral.amount)
        self.assertIsNone(adjusted_candidate.percent_fee_collateral)
        self.assertEqual(self.quote_asset,
                         adjusted_candidate.percent_fee_value.token)
        self.assertEqual(
            Decimal("0.1"),
            adjusted_candidate.percent_fee_value.amount)  # 10 * 0.01
        self.assertEqual(0, len(adjusted_candidate.fixed_fee_collaterals))
        self.assertEqual(self.quote_asset,
                         adjusted_candidate.potential_returns.token)
        self.assertEqual(
            Decimal("9.9"),
            adjusted_candidate.potential_returns.amount)  # 10 * 0.99

    def test_adjust_candidate_insufficient_funds_for_flat_fees_same_token(
            self):
        trade_fee_schema = TradeFeeSchema(
            maker_fixed_fees=[TokenAmount(self.quote_asset, Decimal("1"))], )
        exchange = MockPaperExchange(client_config_map=ClientConfigAdapter(
            ClientConfigMap()),
                                     trade_fee_schema=trade_fee_schema)
        budget_checker: BudgetChecker = exchange.budget_checker
        exchange.set_balance(self.quote_asset, Decimal("11"))

        order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.BUY,
            amount=Decimal("10"),
            price=Decimal("2"),
        )
        adjusted_candidate = budget_checker.adjust_candidate(order_candidate,
                                                             all_or_none=False)

        self.assertEqual(Decimal("5"), adjusted_candidate.amount)
        self.assertEqual(self.quote_asset,
                         adjusted_candidate.order_collateral.token)
        self.assertEqual(Decimal("10"),
                         adjusted_candidate.order_collateral.amount)
        self.assertIsNone(adjusted_candidate.percent_fee_collateral)
        self.assertIsNone(adjusted_candidate.percent_fee_value)
        self.assertEqual(1, len(adjusted_candidate.fixed_fee_collaterals))

        fixed_fee_collateral = adjusted_candidate.fixed_fee_collaterals[0]

        self.assertEqual(self.quote_asset, fixed_fee_collateral.token)
        self.assertEqual(Decimal("1"), fixed_fee_collateral.amount)
        self.assertEqual(self.base_asset,
                         adjusted_candidate.potential_returns.token)
        self.assertEqual(Decimal("5"),
                         adjusted_candidate.potential_returns.amount)

    def test_adjust_candidate_insufficient_funds_for_flat_fees_third_token(
            self):
        fee_asset = "FEE"
        trade_fee_schema = TradeFeeSchema(
            maker_fixed_fees=[TokenAmount(fee_asset, Decimal("11"))], )
        exchange = MockPaperExchange(client_config_map=ClientConfigAdapter(
            ClientConfigMap()),
                                     trade_fee_schema=trade_fee_schema)
        budget_checker: BudgetChecker = exchange.budget_checker
        exchange.set_balance(self.quote_asset, Decimal("100"))
        exchange.set_balance(fee_asset, Decimal("10"))

        order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.BUY,
            amount=Decimal("10"),
            price=Decimal("2"),
        )
        adjusted_candidate = budget_checker.adjust_candidate(order_candidate,
                                                             all_or_none=False)

        self.assertTrue(adjusted_candidate.is_zero_order)

    def test_adjust_candidate_insufficient_funds_for_flat_fees_and_percent_fees(
            self):
        trade_fee_schema = TradeFeeSchema(
            maker_percent_fee_decimal=Decimal("0.1"),
            maker_fixed_fees=[TokenAmount(self.quote_asset, Decimal("1"))],
        )
        exchange = MockPaperExchange(client_config_map=ClientConfigAdapter(
            ClientConfigMap()),
                                     trade_fee_schema=trade_fee_schema)
        budget_checker: BudgetChecker = exchange.budget_checker
        exchange.set_balance(self.quote_asset, Decimal("12"))

        order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.BUY,
            amount=Decimal("10"),
            price=Decimal("2"),
        )
        adjusted_candidate = budget_checker.adjust_candidate(order_candidate,
                                                             all_or_none=False)

        self.assertEqual(Decimal("5"), adjusted_candidate.amount)
        self.assertEqual(self.quote_asset,
                         adjusted_candidate.order_collateral.token)
        self.assertEqual(Decimal("10"),
                         adjusted_candidate.order_collateral.amount)
        self.assertEqual(self.quote_asset,
                         adjusted_candidate.percent_fee_collateral.token)
        self.assertEqual(Decimal("1"),
                         adjusted_candidate.percent_fee_collateral.amount)
        self.assertEqual(self.quote_asset,
                         adjusted_candidate.percent_fee_value.token)
        self.assertEqual(Decimal("1"),
                         adjusted_candidate.percent_fee_value.amount)
        self.assertEqual(1, len(adjusted_candidate.fixed_fee_collaterals))

        fixed_fee_collateral = adjusted_candidate.fixed_fee_collaterals[0]

        self.assertEqual(self.quote_asset, fixed_fee_collateral.token)
        self.assertEqual(Decimal("1"), fixed_fee_collateral.amount)
        self.assertEqual(self.base_asset,
                         adjusted_candidate.potential_returns.token)
        self.assertEqual(Decimal("5"),
                         adjusted_candidate.potential_returns.amount)

    def test_adjust_candidate_insufficient_funds_for_flat_fees_and_percent_fees_third_token(
            self):
        fc_token = "PFC"
        trade_fee_schema = TradeFeeSchema(
            percent_fee_token=fc_token,
            maker_percent_fee_decimal=Decimal("0.01"),
            taker_percent_fee_decimal=Decimal("0.01"),
            maker_fixed_fees=[TokenAmount(fc_token, Decimal("1"))])
        exchange = MockPaperExchange(client_config_map=ClientConfigAdapter(
            ClientConfigMap()),
                                     trade_fee_schema=trade_fee_schema)
        pfc_quote_pair = combine_to_hb_trading_pair(self.quote_asset, fc_token)
        exchange.set_balanced_order_book(  # the quote to pfc price will be 1:2
            trading_pair=pfc_quote_pair,
            mid_price=1.5,
            min_price=1,
            max_price=2,
            price_step_size=1,
            volume_step_size=1,
        )
        budget_checker: BudgetChecker = exchange.budget_checker
        exchange.set_balance(self.quote_asset, Decimal("20"))
        exchange.set_balance(
            fc_token, Decimal("1.2")
        )  # 0.2 less than required; will result in 50% order reduction

        order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.BUY,
            amount=Decimal("10"),
            price=Decimal("2"),
        )
        adjusted_candidate = budget_checker.adjust_candidate(order_candidate,
                                                             all_or_none=False)

        self.assertEqual(Decimal("5"), adjusted_candidate.amount)
        self.assertEqual(self.quote_asset,
                         adjusted_candidate.order_collateral.token)
        self.assertEqual(Decimal("10"),
                         adjusted_candidate.order_collateral.amount)
        self.assertEqual(fc_token,
                         adjusted_candidate.percent_fee_collateral.token)
        self.assertEqual(Decimal("0.2"),
                         adjusted_candidate.percent_fee_collateral.amount)
        self.assertEqual(fc_token, adjusted_candidate.percent_fee_value.token)
        self.assertEqual(Decimal("0.2"),
                         adjusted_candidate.percent_fee_value.amount)
        self.assertEqual(1, len(adjusted_candidate.fixed_fee_collaterals))

        fixed_fee_collateral = adjusted_candidate.fixed_fee_collaterals[0]

        self.assertEqual(fc_token, fixed_fee_collateral.token)
        self.assertEqual(Decimal("1"), fixed_fee_collateral.amount)
        self.assertEqual(self.base_asset,
                         adjusted_candidate.potential_returns.token)
        self.assertEqual(Decimal("5"),
                         adjusted_candidate.potential_returns.amount)

    def test_adjust_candidate_and_lock_available_collateral(self):
        self.exchange.set_balance(self.base_asset, Decimal("10"))

        first_order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.SELL,
            amount=Decimal("7"),
            price=Decimal("2"),
        )
        first_adjusted_candidate = self.budget_checker.adjust_candidate_and_lock_available_collateral(
            first_order_candidate, all_or_none=False)
        second_order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.SELL,
            amount=Decimal("5"),
            price=Decimal("2"),
        )
        second_adjusted_candidate = self.budget_checker.adjust_candidate_and_lock_available_collateral(
            second_order_candidate, all_or_none=False)
        third_order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.SELL,
            amount=Decimal("5"),
            price=Decimal("2"),
        )
        third_adjusted_candidate = self.budget_checker.adjust_candidate_and_lock_available_collateral(
            third_order_candidate, all_or_none=False)

        self.assertEqual(Decimal("7"), first_adjusted_candidate.amount)
        self.assertEqual(Decimal("3"), second_adjusted_candidate.amount)
        self.assertEqual(Decimal("3"),
                         second_adjusted_candidate.order_collateral.amount)
        self.assertEqual(Decimal("0"), third_adjusted_candidate.amount)
        self.assertIsNone(third_adjusted_candidate.order_collateral)

    def test_reset_locked_collateral(self):
        self.exchange.set_balance(self.base_asset, Decimal("10"))

        first_order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.SELL,
            amount=Decimal("7"),
            price=Decimal("2"),
        )
        first_adjusted_candidate = self.budget_checker.adjust_candidate_and_lock_available_collateral(
            first_order_candidate, all_or_none=False)

        self.budget_checker.reset_locked_collateral()

        second_order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.SELL,
            amount=Decimal("5"),
            price=Decimal("2"),
        )
        second_adjusted_candidate = self.budget_checker.adjust_candidate_and_lock_available_collateral(
            second_order_candidate, all_or_none=False)

        self.assertEqual(Decimal("7"), first_adjusted_candidate.amount)
        self.assertEqual(Decimal("5"), second_adjusted_candidate.amount)

    def test_adjust_candidates(self):
        self.exchange.set_balance(self.base_asset, Decimal("10"))

        first_order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.SELL,
            amount=Decimal("7"),
            price=Decimal("2"),
        )
        second_order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.SELL,
            amount=Decimal("5"),
            price=Decimal("2"),
        )
        third_order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.SELL,
            amount=Decimal("5"),
            price=Decimal("2"),
        )

        first_adjusted_candidate, second_adjusted_candidate, third_adjusted_candidate = (
            self.budget_checker.adjust_candidates([
                first_order_candidate, second_order_candidate,
                third_order_candidate
            ],
                                                  all_or_none=False))

        self.assertEqual(Decimal("7"), first_adjusted_candidate.amount)
        self.assertEqual(Decimal("3"), second_adjusted_candidate.amount)
        self.assertEqual(Decimal("3"),
                         second_adjusted_candidate.order_collateral.amount)
        self.assertEqual(Decimal("0"), third_adjusted_candidate.amount)
        self.assertIsNone(third_adjusted_candidate.order_collateral)

    def test_adjust_candidates_resets_locked_collateral(self):
        self.exchange.set_balance(self.base_asset, Decimal("10"))

        first_order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.SELL,
            amount=Decimal("7"),
            price=Decimal("2"),
        )
        first_adjusted_candidate, = self.budget_checker.adjust_candidates(
            [first_order_candidate], all_or_none=False)

        second_order_candidate = OrderCandidate(
            trading_pair=self.trading_pair,
            is_maker=True,
            order_type=OrderType.LIMIT,
            order_side=TradeType.SELL,
            amount=Decimal("5"),
            price=Decimal("2"),
        )
        second_adjusted_candidate = self.budget_checker.adjust_candidate_and_lock_available_collateral(
            second_order_candidate, all_or_none=False)

        self.assertEqual(Decimal("7"), first_adjusted_candidate.amount)
        self.assertEqual(Decimal("5"), second_adjusted_candidate.amount)