From c0c0cc8c1615324bfc5141897ec8fddb4723a89a Mon Sep 17 00:00:00 2001 From: Guillaume De Saint Martin Date: Tue, 3 Dec 2024 23:47:52 +0100 Subject: [PATCH] [ExchangeTests] add cross position tests --- .../abstract_authenticated_exchange_tester.py | 8 +++- ...ct_authenticated_future_exchange_tester.py | 42 +++++++++++++++++-- .../exchanges_tests/test_binance_futures.py | 16 ++++--- .../exchanges_tests/test_kucoin_futures.py | 1 + 4 files changed, 56 insertions(+), 11 deletions(-) diff --git a/additional_tests/exchanges_tests/abstract_authenticated_exchange_tester.py b/additional_tests/exchanges_tests/abstract_authenticated_exchange_tester.py index d906604c4..257021f92 100644 --- a/additional_tests/exchanges_tests/abstract_authenticated_exchange_tester.py +++ b/additional_tests/exchanges_tests/abstract_authenticated_exchange_tester.py @@ -229,7 +229,7 @@ async def test_create_and_cancel_limit_orders(self): async with self.local_exchange_manager(): await self.inner_test_create_and_cancel_limit_orders() - async def inner_test_create_and_cancel_limit_orders(self, symbol=None, settlement_currency=None): + async def inner_test_create_and_cancel_limit_orders(self, symbol=None, settlement_currency=None, margin_type=None): symbol = symbol or self.SYMBOL # # DEBUG tools p1, uncomment to create specific orders # symbol = "ADA/USDT" @@ -247,7 +247,11 @@ async def inner_test_create_and_cancel_limit_orders(self, symbol=None, settlemen min_size = personal_data.decimal_adapt_quantity( market_status, # add 25% to min order size to avoid rounding of amount of price ending up just bellow min cost - decimal.Decimal(str(self.EXPECTED_QUOTE_MIN_ORDER_SIZE)) * decimal.Decimal("1.25") / price + decimal.Decimal(str(self.EXPECTED_QUOTE_MIN_ORDER_SIZE)) * ( + decimal.Decimal("1.25") if symbols.parse_symbol(symbol).is_spot() else decimal.Decimal("1") + ) / ( + decimal.Decimal("1") if symbols.parse_symbol(symbol).is_inverse() else price + ) ) self.check_order_size_and_price(min_size, price, symbol=symbol, allow_empty_size=False) size = min(min_size, default_size) diff --git a/additional_tests/exchanges_tests/abstract_authenticated_future_exchange_tester.py b/additional_tests/exchanges_tests/abstract_authenticated_future_exchange_tester.py index 9b36da85d..d6ab6805d 100644 --- a/additional_tests/exchanges_tests/abstract_authenticated_future_exchange_tester.py +++ b/additional_tests/exchanges_tests/abstract_authenticated_future_exchange_tester.py @@ -42,10 +42,25 @@ async def test_get_empty_linear_and_inverse_positions(self): await self.inner_test_get_empty_linear_and_inverse_positions() async def inner_test_get_empty_linear_and_inverse_positions(self): + if self.exchange_manager.exchange.SUPPORTS_SET_MARGIN_TYPE: + await self.set_margin_type(trading_enums.MarginType.ISOLATED) + await self._inner_test_get_empty_linear_and_inverse_positions_for_margin_type( + trading_enums.MarginType.ISOLATED + ) + await self.set_margin_type(trading_enums.MarginType.CROSS) + await self._inner_test_get_empty_linear_and_inverse_positions_for_margin_type( + trading_enums.MarginType.CROSS + ) + else: + await self._inner_test_get_empty_linear_and_inverse_positions_for_margin_type(None) + + async def _inner_test_get_empty_linear_and_inverse_positions_for_margin_type( + self, margin_type: trading_enums.MarginType + ): positions = await self.get_positions() self._check_positions_content(positions) position = await self.get_position(self.SYMBOL) - self._check_position_content(position, self.SYMBOL) + self._check_position_content(position, self.SYMBOL, margin_type=margin_type) for contract_type in (trading_enums.FutureContractType.LINEAR_PERPETUAL, trading_enums.FutureContractType.INVERSE_PERPETUAL): if not self.has_empty_position(self.get_filtered_positions(positions, contract_type)): @@ -134,11 +149,13 @@ def _check_positions_content(self, positions): for position in positions: self._check_position_content(position, None) - def _check_position_content(self, position, symbol, position_mode=None): + def _check_position_content(self, position, symbol, position_mode=None, margin_type=None): if symbol: assert position[trading_enums.ExchangeConstantsPositionColumns.SYMBOL.value] == symbol else: assert position[trading_enums.ExchangeConstantsPositionColumns.SYMBOL.value] + if margin_type: + assert position[trading_enums.ExchangeConstantsPositionColumns.MARGIN_TYPE.value] == margin_type leverage = position[trading_enums.ExchangeConstantsPositionColumns.LEVERAGE.value] assert isinstance(leverage, decimal.Decimal) # should not be 0 in octobot @@ -149,11 +166,28 @@ def _check_position_content(self, position, symbol, position_mode=None): assert position[trading_enums.ExchangeConstantsPositionColumns.POSITION_MODE.value] is position_mode async def inner_test_create_and_cancel_limit_orders(self, symbol=None, settlement_currency=None): + if self.exchange_manager.exchange.SUPPORTS_SET_MARGIN_TYPE: + await self.set_margin_type(trading_enums.MarginType.ISOLATED) + await self._inner_test_create_and_cancel_limit_orders_for_margin_type( + symbol=symbol, settlement_currency=settlement_currency, margin_type=trading_enums.MarginType.ISOLATED + ) + await self.set_margin_type(trading_enums.MarginType.CROSS) + await self._inner_test_create_and_cancel_limit_orders_for_margin_type( + symbol=symbol, settlement_currency=settlement_currency, margin_type=trading_enums.MarginType.CROSS + ) + else: + await self._inner_test_create_and_cancel_limit_orders_for_margin_type( + symbol=symbol, settlement_currency=settlement_currency, margin_type=None + ) + + async def _inner_test_create_and_cancel_limit_orders_for_margin_type( + self, symbol=None, settlement_currency=None, margin_type=None + ): # test with linear symbol - await super().inner_test_create_and_cancel_limit_orders() + await super().inner_test_create_and_cancel_limit_orders(margin_type=margin_type) # test with inverse symbol await super().inner_test_create_and_cancel_limit_orders( - symbol=self.INVERSE_SYMBOL, settlement_currency=self.ORDER_CURRENCY + symbol=self.INVERSE_SYMBOL, settlement_currency=self.ORDER_CURRENCY, margin_type=margin_type ) async def inner_test_create_and_fill_market_orders(self): diff --git a/additional_tests/exchanges_tests/test_binance_futures.py b/additional_tests/exchanges_tests/test_binance_futures.py index 30fa13746..cfb5c6ce7 100644 --- a/additional_tests/exchanges_tests/test_binance_futures.py +++ b/additional_tests/exchanges_tests/test_binance_futures.py @@ -29,12 +29,13 @@ class TestBinanceFuturesAuthenticatedExchange( EXCHANGE_NAME = "binance" CREDENTIALS_EXCHANGE_NAME = "BINANCE_FUTURES" ORDER_CURRENCY = "BTC" - SETTLEMENT_CURRENCY = "USDT" + SETTLEMENT_CURRENCY = "USDC" SYMBOL = f"{ORDER_CURRENCY}/{SETTLEMENT_CURRENCY}:{SETTLEMENT_CURRENCY}" INVERSE_SYMBOL = f"{ORDER_CURRENCY}/USD:{ORDER_CURRENCY}" - ORDER_SIZE = 10 # % of portfolio to include in test orders + ORDER_SIZE = 30 # % of portfolio to include in test orders DUPLICATE_TRADES_RATIO = 0.1 # allow 10% duplicate in trades (due to trade id set to order id) VALID_ORDER_ID = "26408108410" + EXPECTED_QUOTE_MIN_ORDER_SIZE = 200 # min quote value of orders to create (used to check market status parsing) async def _set_account_types(self, account_types): # todo remove this and use both types when exchange-side multi portfolio is enabled @@ -86,18 +87,23 @@ async def test_is_valid_account(self): async def test_create_and_cancel_limit_orders(self): await super().test_create_and_cancel_limit_orders() - async def inner_test_create_and_cancel_limit_orders(self, symbol=None, settlement_currency=None): + async def _inner_test_create_and_cancel_limit_orders_for_margin_type( + self, symbol=None, settlement_currency=None, margin_type=None + ): # todo remove this and use both types when exchange-side multi portfolio is enabled # test with linear symbol + await self._set_account_types( + [self.exchange_manager.exchange.LINEAR_TYPE] + ) await abstract_authenticated_exchange_tester.AbstractAuthenticatedExchangeTester\ - .inner_test_create_and_cancel_limit_orders(self) + .inner_test_create_and_cancel_limit_orders(self, margin_type=margin_type) # test with inverse symbol await self._set_account_types( [self.exchange_manager.exchange.INVERSE_TYPE] ) await abstract_authenticated_exchange_tester.AbstractAuthenticatedExchangeTester\ .inner_test_create_and_cancel_limit_orders( - self, symbol=self.INVERSE_SYMBOL, settlement_currency=self.ORDER_CURRENCY + self, symbol=self.INVERSE_SYMBOL, settlement_currency=self.ORDER_CURRENCY, margin_type=margin_type ) async def test_create_and_fill_market_orders(self): diff --git a/additional_tests/exchanges_tests/test_kucoin_futures.py b/additional_tests/exchanges_tests/test_kucoin_futures.py index 8dd13ffa1..7c31e6e32 100644 --- a/additional_tests/exchanges_tests/test_kucoin_futures.py +++ b/additional_tests/exchanges_tests/test_kucoin_futures.py @@ -73,6 +73,7 @@ async def test_is_valid_account(self): await super().test_is_valid_account() async def test_create_and_cancel_limit_orders(self): + # todo test cross position order creation (kucoin param) at next ccxt update (will support set margin type) await super().test_create_and_cancel_limit_orders() async def test_create_and_fill_market_orders(self):