Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Order tests #2849

Merged
merged 3 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import octobot_trading.enums as trading_enums
import octobot_trading.constants as trading_constants
import octobot_trading.exchanges as trading_exchanges
import octobot_trading.exchanges.connectors.ccxt.constants as ccxt_constants
import octobot_trading.personal_data as personal_data
import octobot_trading.personal_data.orders as personal_data_orders
import octobot_trading.util.test_tools.exchanges_test_tools as exchanges_test_tools
Expand All @@ -52,6 +53,18 @@ class AbstractAuthenticatedExchangeTester:
SETTLEMENT_CURRENCY = "USDT"
SYMBOL = f"{ORDER_CURRENCY}/{SETTLEMENT_CURRENCY}"
VALID_ORDER_ID = "8bb80a81-27f7-4415-aa50-911ea46d841c"
SPECIAL_ORDER_TYPES_BY_EXCHANGE_ID: dict[
str, (
str, # symbol
str, # order type key in 'info' dict
str, # order type found in 'info' dict
str, # parsed trading_enums.TradeOrderType
str, # parsed trading_enums.TradeOrderSide
bool, # trigger above (on higher price than order price)
)
] = {} # stop loss / take profit and other special order types to be successfully parsed
# details of an order that exists but can"t be cancelled
UNCANCELLABLE_ORDER_ID_SYMBOL_TYPE: tuple[str, str, trading_enums.TraderOrderType] = None
ORDER_SIZE = 10 # % of portfolio to include in test orders
PORTFOLIO_TYPE_FOR_SIZE = trading_constants.CONFIG_PORTFOLIO_FREE
CONVERTS_ORDER_SIZE_BEFORE_PUSHING_TO_EXCHANGES = False
Expand Down Expand Up @@ -327,8 +340,53 @@ async def inner_test_is_valid_account(self):
assert isinstance(error, str)
assert len(error) > 0


async def test_get_special_orders(self):
if self.SPECIAL_ORDER_TYPES_BY_EXCHANGE_ID:
async with self.local_exchange_manager():
await self.inner_test_get_special_orders()

async def inner_test_get_special_orders(self):
# open_orders = await self.get_open_orders(_symbols=["TAO/USDT"])
# print(open_orders) # to print special orders when they are open
# return
for exchange_id, order_details in self.SPECIAL_ORDER_TYPES_BY_EXCHANGE_ID.items():
symbol, info_key, info_type, expected_type, expected_side, expected_trigger_above = order_details
fetched_order = await self.exchange_manager.exchange.get_order(exchange_id, symbol=symbol)
assert fetched_order is not None
self._check_fetched_order_dicts([fetched_order])
# ensure parsing order doesn't crash
parsed = personal_data.create_order_instance_from_raw(self.exchange_manager.trader, fetched_order)
assert isinstance(parsed, personal_data.Order)

assert fetched_order[trading_enums.ExchangeConstantsOrderColumns.SYMBOL.value] == symbol
found_type = fetched_order[ccxt_constants.CCXT_INFO][info_key]
assert found_type == info_type, f"[{exchange_id}]: {found_type} != {info_type}"
parsed_type = fetched_order[trading_enums.ExchangeConstantsOrderColumns.TYPE.value]
assert parsed_type == expected_type, f"[{exchange_id}]: {parsed_type} != {expected_type}"
assert fetched_order[trading_enums.ExchangeConstantsOrderColumns.SIDE.value] == expected_side
if expected_trigger_above is None:
assert trading_enums.ExchangeConstantsOrderColumns.TRIGGER_ABOVE.value not in fetched_order
else:
parsed_trigger_above = fetched_order[trading_enums.ExchangeConstantsOrderColumns.TRIGGER_ABOVE.value]
assert parsed_trigger_above == expected_trigger_above, (
f"[{exchange_id}]: {parsed_trigger_above} != {expected_trigger_above}"
)
if isinstance(parsed, personal_data.LimitOrder):
assert parsed.trigger_above == parsed_trigger_above
if expected_type == trading_enums.TradeOrderType.LIMIT.value:
assert fetched_order[trading_enums.ExchangeConstantsOrderColumns.PRICE.value] > 0
elif expected_type == trading_enums.TradeOrderType.STOP_LOSS.value:
assert fetched_order[trading_enums.ExchangeConstantsOrderColumns.STOP_PRICE.value] > 0
elif expected_type == trading_enums.TradeOrderType.UNSUPPORTED.value:
assert isinstance(parsed, personal_data.UnsupportedOrder)
else:
# ensure all cases are covered, otherwise there is a problem in order type parsing
assert expected_type == trading_enums.TradeOrderType.MARKET

async def test_create_and_cancel_limit_orders(self):
async with self.local_exchange_manager():
await self.inner_test_cancel_uncancellable_order()
await self.inner_test_create_and_cancel_limit_orders()

async def inner_test_create_and_cancel_limit_orders(self, symbol=None, settlement_currency=None, margin_type=None):
Expand Down Expand Up @@ -396,6 +454,12 @@ async def inner_test_create_and_cancel_limit_orders(self, symbol=None, settlemen
assert await self.order_not_in_open_orders(open_orders, buy_limit, symbol=symbol)
assert await self.order_in_cancelled_orders(cancelled_orders, buy_limit, symbol=symbol)

async def inner_test_cancel_uncancellable_order(self):
if self.UNCANCELLABLE_ORDER_ID_SYMBOL_TYPE:
order_id, symbol, order_type = self.UNCANCELLABLE_ORDER_ID_SYMBOL_TYPE
with pytest.raises(trading_errors.ExchangeOrderCancelError):
await self.exchange_manager.exchange.cancel_order(order_id, symbol, order_type)

async def test_create_and_fill_market_orders(self):
async with self.local_exchange_manager():
await self.inner_test_create_and_fill_market_orders()
Expand Down Expand Up @@ -747,12 +811,12 @@ async def get_my_recent_trades(self, exchange_data=None):
async def get_closed_orders(self, symbol=None):
return await self.exchange_manager.exchange.get_closed_orders(symbol or self.SYMBOL)

async def get_cancelled_orders(self, exchange_data=None, force_fetch=False):
async def get_cancelled_orders(self, exchange_data=None, force_fetch=False, _symbols=None):
if not force_fetch and not self.exchange_manager.exchange.SUPPORT_FETCHING_CANCELLED_ORDERS:
# skipped
return []
exchange_data = exchange_data or self.get_exchange_data()
return await exchanges_test_tools.get_cancelled_orders(self.exchange_manager, exchange_data)
return await exchanges_test_tools.get_cancelled_orders(self.exchange_manager, exchange_data, symbols=_symbols)

async def check_require_closed_orders_from_recent_trades(self, symbol=None):
if self.exchange_manager.exchange.REQUIRE_CLOSED_ORDERS_FROM_RECENT_TRADES:
Expand Down Expand Up @@ -1088,9 +1152,9 @@ def get_order_price(self, price, is_above_price, symbol=None, price_diff=None):
price * (decimal.Decimal(str(multiplier)))
)

async def get_open_orders(self, exchange_data=None):
async def get_open_orders(self, exchange_data=None, _symbols=None):
exchange_data = exchange_data or self.get_exchange_data()
orders = await exchanges_test_tools.get_open_orders(self.exchange_manager, exchange_data)
orders = await exchanges_test_tools.get_open_orders(self.exchange_manager, exchange_data, symbols=_symbols)
self.check_duplicate(orders)
self._check_fetched_order_dicts(orders)
return orders
Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_ascendex.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ async def test_get_not_found_order(self):
async def test_is_valid_account(self):
await super().test_is_valid_account()

async def test_get_special_orders(self):
await super().test_get_special_orders()

async def test_create_and_cancel_limit_orders(self):
await super().test_create_and_cancel_limit_orders()

Expand Down
36 changes: 36 additions & 0 deletions additional_tests/exchanges_tests/test_binance.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
# You should have received a copy of the GNU General Public
# License along with OctoBot. If not, see <https://www.gnu.org/licenses/>.
import pytest
import octobot_trading.enums

from additional_tests.exchanges_tests import abstract_authenticated_exchange_tester

Expand Down Expand Up @@ -41,6 +42,38 @@ class TestBinanceAuthenticatedExchange(
IS_BROKER_ENABLED_ACCOUNT = False
IS_AUTHENTICATED_REQUEST_CHECK_AVAILABLE = True # set True when is_authenticated_request is implemented

SPECIAL_ORDER_TYPES_BY_EXCHANGE_ID: dict[
str, (
str, # symbol
str, # order type key in 'info' dict
str, # order type found in 'info' dict
str, # parsed trading_enums.TradeOrderType
str, # parsed trading_enums.TradeOrderSide
bool, # trigger above (on higher price than order price)
)
] = {
"6799804660": (
"BNB/USDT", "type", "TAKE_PROFIT",
octobot_trading.enums.TradeOrderType.LIMIT.value, octobot_trading.enums.TradeOrderSide.SELL.value, True
),
'6799810041': (
"BNB/USDT", "type", "STOP_LOSS",
octobot_trading.enums.TradeOrderType.STOP_LOSS.value, octobot_trading.enums.TradeOrderSide.SELL.value, False
),
'6799798838': (
"BNB/USDT", "type", "TAKE_PROFIT_LIMIT",
octobot_trading.enums.TradeOrderType.LIMIT.value, octobot_trading.enums.TradeOrderSide.SELL.value, True
),
'6799795001': (
"BNB/USDT", "type", "STOP_LOSS_LIMIT",
octobot_trading.enums.TradeOrderType.STOP_LOSS.value, octobot_trading.enums.TradeOrderSide.SELL.value, False
),
} # stop loss / take profit and other special order types to be successfully parsed
# details of an order that exists but can"t be cancelled
UNCANCELLABLE_ORDER_ID_SYMBOL_TYPE: tuple[str, str, octobot_trading.enums.TraderOrderType] = (
"6799798838", "BNB/USDT", octobot_trading.enums.TraderOrderType.BUY_LIMIT.value
)


async def test_get_portfolio(self):
await super().test_get_portfolio()
Expand Down Expand Up @@ -69,6 +102,9 @@ async def test_get_not_found_order(self):
async def test_is_valid_account(self):
await super().test_is_valid_account()

async def test_get_special_orders(self):
await super().test_get_special_orders()

async def test_create_and_cancel_limit_orders(self):
await super().test_create_and_cancel_limit_orders()

Expand Down
36 changes: 36 additions & 0 deletions additional_tests/exchanges_tests/test_binance_futures.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# License along with OctoBot. If not, see <https://www.gnu.org/licenses/>.
import pytest

import octobot_trading.enums
from additional_tests.exchanges_tests import abstract_authenticated_future_exchange_tester, \
abstract_authenticated_exchange_tester

Expand All @@ -38,6 +39,38 @@ class TestBinanceFuturesAuthenticatedExchange(
EXPECTED_QUOTE_MIN_ORDER_SIZE = 200 # min quote value of orders to create (used to check market status parsing)
IS_AUTHENTICATED_REQUEST_CHECK_AVAILABLE = True # set True when is_authenticated_request is implemented

SPECIAL_ORDER_TYPES_BY_EXCHANGE_ID: dict[
str, (
str, # symbol
str, # order type key in 'info' dict
str, # order type found in 'info' dict
str, # parsed trading_enums.TradeOrderType
str, # parsed trading_enums.TradeOrderSide
bool, # trigger above (on higher price than order price)
)
] = {
"4075521283": (
"BTC/USDT:USDT", "type", "TAKE_PROFIT_MARKET",
octobot_trading.enums.TradeOrderType.LIMIT.value, octobot_trading.enums.TradeOrderSide.SELL.value, True
),
'622529': (
"BTC/USDC:USDC", "type", "STOP_MARKET",
octobot_trading.enums.TradeOrderType.STOP_LOSS.value, octobot_trading.enums.TradeOrderSide.SELL.value, False
),
'4076521927': (
"BTC/USDT:USDT", "type", "TAKE_PROFIT",
octobot_trading.enums.TradeOrderType.LIMIT.value, octobot_trading.enums.TradeOrderSide.BUY.value, False
),
'4076521976': (
"BTC/USDT:USDT", "type", "STOP",
octobot_trading.enums.TradeOrderType.STOP_LOSS.value, octobot_trading.enums.TradeOrderSide.SELL.value, False
),
} # stop loss / take profit and other special order types to be successfully parsed
# details of an order that exists but can"t be cancelled
UNCANCELLABLE_ORDER_ID_SYMBOL_TYPE: tuple[str, str, octobot_trading.enums.TraderOrderType] = (
"4076521927", "BTC/USDT:USDT", octobot_trading.enums.TraderOrderType.BUY_LIMIT.value
)

async def _set_account_types(self, account_types):
# todo remove this and use both types when exchange-side multi portfolio is enabled
self.exchange_manager.exchange._futures_account_types = account_types
Expand Down Expand Up @@ -86,6 +119,9 @@ async def test_get_and_set_leverage(self):
async def test_is_valid_account(self):
await super().test_is_valid_account()

async def test_get_special_orders(self):
await super().test_get_special_orders()

async def test_create_and_cancel_limit_orders(self):
await super().test_create_and_cancel_limit_orders()

Expand Down
36 changes: 36 additions & 0 deletions additional_tests/exchanges_tests/test_bingx.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
# You should have received a copy of the GNU General Public
# License along with OctoBot. If not, see <https://www.gnu.org/licenses/>.
import pytest
import octobot_trading.enums

from additional_tests.exchanges_tests import abstract_authenticated_exchange_tester

Expand All @@ -38,6 +39,38 @@ class TestBingxAuthenticatedExchange(

VALID_ORDER_ID = "1812980957928929280"

SPECIAL_ORDER_TYPES_BY_EXCHANGE_ID: dict[
str, (
str, # symbol
str, # order type key in 'info' dict
str, # order type found in 'info' dict
str, # parsed trading_enums.TradeOrderType
str, # parsed trading_enums.TradeOrderSide
bool, # trigger above (on higher price than order price)
)
] = {
"1877004154170146816": (
"TAO/USDT", "type", "TAKE_STOP_MARKET",
octobot_trading.enums.TradeOrderType.STOP_LOSS.value, octobot_trading.enums.TradeOrderSide.SELL.value, False
),
'1877004191864356864': (
"TAO/USDT", "type", "TAKE_STOP_MARKET",
octobot_trading.enums.TradeOrderType.LIMIT.value, octobot_trading.enums.TradeOrderSide.SELL.value, True
),
'1877004220704391168': (
"TAO/USDT", "type", "TAKE_STOP_LIMIT",
octobot_trading.enums.TradeOrderType.UNSUPPORTED.value, octobot_trading.enums.TradeOrderSide.SELL.value, None
),
'1877004292053696512': (
"TAO/USDT", "type", "TAKE_STOP_LIMIT",
octobot_trading.enums.TradeOrderType.UNSUPPORTED.value, octobot_trading.enums.TradeOrderSide.SELL.value, None
),
} # stop loss / take profit and other special order types to be successfully parsed
# details of an order that exists but can"t be cancelled
UNCANCELLABLE_ORDER_ID_SYMBOL_TYPE: tuple[str, str, octobot_trading.enums.TraderOrderType] = (
"1877004292053696512", "TAO/USDT", octobot_trading.enums.TraderOrderType.SELL_LIMIT.value
)

async def test_get_portfolio(self):
await super().test_get_portfolio()

Expand Down Expand Up @@ -65,6 +98,9 @@ async def test_get_not_found_order(self):
async def test_is_valid_account(self):
await super().test_is_valid_account()

async def test_get_special_orders(self):
await super().test_get_special_orders()

async def test_create_and_cancel_limit_orders(self):
await super().test_create_and_cancel_limit_orders()

Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_bitget.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ async def test_get_not_found_order(self):
async def test_is_valid_account(self):
await super().test_is_valid_account()

async def test_get_special_orders(self):
await super().test_get_special_orders()

async def test_create_and_cancel_limit_orders(self):
await super().test_create_and_cancel_limit_orders()

Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_bitmart.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ async def test_get_not_found_order(self):
async def test_is_valid_account(self):
await super().test_is_valid_account()

async def test_get_special_orders(self):
await super().test_get_special_orders()

async def test_create_and_cancel_limit_orders(self):
await super().test_create_and_cancel_limit_orders()

Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_bybit.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ async def test_get_not_found_order(self):
async def test_is_valid_account(self):
await super().test_is_valid_account()

async def test_get_special_orders(self):
await super().test_get_special_orders()

async def test_create_and_cancel_limit_orders(self):
await super().test_create_and_cancel_limit_orders()

Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_bybit_futures.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ async def test_get_and_set_leverage(self):
async def test_is_valid_account(self):
await super().test_is_valid_account()

async def test_get_special_orders(self):
await super().test_get_special_orders()

async def test_create_and_cancel_limit_orders(self):
await super().test_create_and_cancel_limit_orders()

Expand Down
Loading
Loading