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

[Tests] add tradable symbols test #2858

Merged
merged 1 commit into from
Jan 13, 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 @@ -16,6 +16,7 @@
import asyncio
import contextlib
import decimal
import random
import time
import typing
import ccxt
Expand Down Expand Up @@ -53,6 +54,7 @@ class AbstractAuthenticatedExchangeTester:
ORDER_CURRENCY = "BTC"
SETTLEMENT_CURRENCY = "USDT"
SYMBOL = f"{ORDER_CURRENCY}/{SETTLEMENT_CURRENCY}"
TIME_FRAME = "1h"
VALID_ORDER_ID = "8bb80a81-27f7-4415-aa50-911ea46d841c"
SPECIAL_ORDER_TYPES_BY_EXCHANGE_ID: dict[
str, (
Expand Down Expand Up @@ -104,6 +106,8 @@ class AbstractAuthenticatedExchangeTester:
CHECK_EMPTY_ACCOUNT = False # set True when the account to check has no funds. Warning: does not check order
# parse/create/fill/cancel or portfolio & trades parsing
IS_BROKER_ENABLED_ACCOUNT = True # set False when this test account can't generate broker fees
# set True when this exchange used to have symbols that can't be traded through API (ex: MEXC)
USED_TO_HAVE_UNTRADABLE_SYMBOL = False
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


# Implement all "test_[name]" methods, call super() to run the test, pass to ignore it.
# Override the "inner_test_[name]" method to override a test content.
Expand Down Expand Up @@ -158,6 +162,98 @@ def check_portfolio_content(self, portfolio):
at_least_one_value = True
assert at_least_one_value

async def test_untradable_symbols(self):
await self.inner_test_untradable_symbols()

async def inner_test_untradable_symbols(self):
if not self.USED_TO_HAVE_UNTRADABLE_SYMBOL:
# nothing to do
return
async with self.local_exchange_manager():
all_symbols = self.exchange_manager.exchange.get_all_available_symbols()
tradable_symbols = await self.exchange_manager.exchange.get_all_tradable_symbols()
assert len(all_symbols) > len(tradable_symbols)
untradable_symbols = [
symbol
for symbol in all_symbols
if symbol not in tradable_symbols
and symbol.endswith(f"/{self.SETTLEMENT_CURRENCY}")
and (
symbols.parse_symbol(symbol).is_spot()
if self.EXCHANGE_TYPE == trading_enums.ExchangeTypes.SPOT.value
else symbols.parse_symbol(symbol).is_future()
)
]
tradable_symbols = [
symbol
for symbol in all_symbols
if symbol in tradable_symbols
and symbol.endswith(f"/{self.SETTLEMENT_CURRENCY}")
and (
symbols.parse_symbol(symbol).is_spot()
if self.EXCHANGE_TYPE == trading_enums.ExchangeTypes.SPOT.value
else symbols.parse_symbol(symbol).is_future()
)
]
# has untradable symbols of this trading type
assert len(untradable_symbols) > 0
first_untradable_symbol = untradable_symbols[0]
# Public data
# market status is available
assert ccxt_constants.CCXT_INFO in self.exchange_manager.exchange.get_market_status(first_untradable_symbol)
# fetching ohlcv is ok
assert len(
await self.exchange_manager.exchange.get_symbol_prices(
first_untradable_symbol, commons_enums.TimeFrames(self.TIME_FRAME)
)
) > 5
# fetching kline is ok
kline = await self.exchange_manager.exchange.get_kline_price(
first_untradable_symbol, commons_enums.TimeFrames(self.TIME_FRAME)
)
assert len(kline) == 1
assert len(kline[0]) == 6
# fetching ticker is ok
ticker = await self.exchange_manager.exchange.get_price_ticker(first_untradable_symbol)
assert ticker
price = ticker[trading_enums.ExchangeConstantsTickersColumns.CLOSE.value]
assert price > 0
# fetching recent trades is ok
recent_trades = await self.exchange_manager.exchange.get_recent_trades(first_untradable_symbol)
assert len(recent_trades) > 1
# fetching order book is ok
order_book = await self.exchange_manager.exchange.get_order_book(first_untradable_symbol)
assert len(order_book[trading_enums.ExchangeConstantsOrderBookInfoColumns.ASKS.value]) > 0
# is in all tickers
all_tickers = await self.exchange_manager.exchange.get_all_currencies_price_ticker()
assert all_tickers[first_untradable_symbol][trading_enums.ExchangeConstantsTickersColumns.CLOSE.value] > 0
# Orders
# try creating & cancelling orders on 5 random tradable and untradable symbols
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

symbols_to_test = 5
tradable_stepper = random.randint(1, len(tradable_symbols) - 2)
tradable_indexes = [tradable_stepper * i for i in range(0, symbols_to_test)]
untradable_stepper = random.randint(1, len(untradable_symbols) - 2)
untradable_indexes = [untradable_stepper * i for i in range(0, symbols_to_test)]
to_test_symbols = [
tradable_symbols[i % (len(tradable_symbols) - 1)] for i in tradable_indexes
] + [
untradable_symbols[i % (len(untradable_symbols) - 1)] for i in untradable_indexes
]
for i, symbol in enumerate(to_test_symbols):
ticker = await self.exchange_manager.exchange.get_price_ticker(symbol)
price = ticker[trading_enums.ExchangeConstantsTickersColumns.CLOSE.value]
price = self.get_order_price(decimal.Decimal(str(price)), False, symbol=symbol)
size = self.get_order_size(
await self.get_portfolio(), price, symbol=symbol,
settlement_currency=self.SETTLEMENT_CURRENCY
)
buy_limit = await self.create_limit_order(
price, size, trading_enums.TradeOrderSide.BUY,
symbol=symbol
)
await self.cancel_order(buy_limit)
print(f"{i+1}/{len(to_test_symbols)} : {symbol} Create & cancel order OK")

async def test_get_account_id(self):
async with self.local_exchange_manager():
await self.inner_test_get_account_id()
Expand Down Expand Up @@ -1432,7 +1528,7 @@ def get_exchange_data(self, symbol=None, all_symbols=None) -> exchange_data_impo
exchange_details={"name": self.exchange_manager.exchange_name},
markets=[
{
"id": s, "symbol": s, "info": {}, "time_frame": "1h",
"id": s, "symbol": s, "info": {}, "time_frame": self.TIME_FRAME,
"close": [0], "open": [0], "high": [0], "low": [0], "volume": [0], "time": [0] # todo
}
for s in _symbols
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 @@ -40,6 +40,9 @@ async def test_get_portfolio_with_market_filter(self):
# pass if not implemented
pass

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

async def test_get_account_id(self):
# pass if not implemented
pass
Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_binance.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ async def test_get_portfolio(self):
async def test_get_portfolio_with_market_filter(self):
await super().test_get_portfolio_with_market_filter()

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

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

Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_binance_futures.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ async def test_get_portfolio(self):
async def test_get_portfolio_with_market_filter(self):
await super().test_get_portfolio_with_market_filter() # can have small variations failing the test when positions are open

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

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

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

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

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

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 @@ -42,6 +42,9 @@ async def test_get_portfolio_with_market_filter(self):
# pass if not implemented
pass

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

async def test_get_account_id(self):
# pass if not implemented
pass
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 @@ -40,6 +40,9 @@ async def test_get_portfolio(self):
async def test_get_portfolio_with_market_filter(self):
await super().test_get_portfolio_with_market_filter()

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

async def test_get_account_id(self):
# pass if not implemented
pass
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 @@ -44,6 +44,9 @@ async def test_get_portfolio_with_market_filter(self):
# pass if not implemented
pass

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

async def test_get_account_id(self):
# pass if not implemented
pass
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 @@ -47,6 +47,9 @@ async def test_get_portfolio_with_market_filter(self):
# pass if not implemented
pass

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

async def test_get_account_id(self):
# pass if not implemented
pass
Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_coinbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ async def test_get_portfolio(self):
async def test_get_portfolio_with_market_filter(self):
await super().test_get_portfolio_with_market_filter()

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

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

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

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

async def test_get_account_id(self):
# pass if not implemented
pass
Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_cryptocom.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ async def test_get_portfolio_with_market_filter(self):
# pass if not implemented
pass

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

async def test_get_account_id(self):
# pass if not implemented
pass
Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_gateio.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ async def test_get_portfolio(self):
async def test_get_portfolio_with_market_filter(self):
await super().test_get_portfolio_with_market_filter()

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

async def test_get_account_id(self):
# pass if not implemented
pass
Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_hollaex.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ async def test_get_portfolio(self):
async def test_get_portfolio_with_market_filter(self):
await super().test_get_portfolio_with_market_filter()

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

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

Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_htx.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ async def test_get_portfolio_with_market_filter(self):
# pass if not implemented
pass

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

async def test_get_account_id(self):
# pass if not implemented
pass
Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_kucoin.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ async def test_get_portfolio(self):
async def test_get_portfolio_with_market_filter(self):
await super().test_get_portfolio_with_market_filter()

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

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

Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_kucoin_futures.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ async def test_get_portfolio(self):
async def test_get_portfolio_with_market_filter(self):
await super().test_get_portfolio_with_market_filter() # can have small variations failing the test when positions are open

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

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

Expand Down
6 changes: 5 additions & 1 deletion additional_tests/exchanges_tests/test_mexc.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,25 @@ class TestMEXCAuthenticatedExchange(
EXCHANGE_NAME = "mexc"
EXCHANGE_TENTACLE_NAME = "MEXC"
ORDER_CURRENCY = "BTC"
SETTLEMENT_CURRENCY = "USDC"
SETTLEMENT_CURRENCY = "USDT"
SYMBOL = f"{ORDER_CURRENCY}/{SETTLEMENT_CURRENCY}"
ORDER_SIZE = 30 # % of portfolio to include in test orders
CONVERTS_ORDER_SIZE_BEFORE_PUSHING_TO_EXCHANGES = True
CANCELLED_ORDERS_IN_CLOSED_ORDERS = True
EXPECT_MISSING_FEE_IN_CANCELLED_ORDERS = False
IS_ACCOUNT_ID_AVAILABLE = False
USE_ORDER_OPERATION_TO_CHECK_API_KEY_RIGHTS = True
USED_TO_HAVE_UNTRADABLE_SYMBOL = True

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

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

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

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

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

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

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

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

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

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

Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_phemex.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ async def test_get_portfolio_with_market_filter(self):
# pass if not implemented
pass

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

async def test_get_account_id(self):
# pass if not implemented
pass
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Drakkar-Software requirements
OctoBot-Commons==1.9.70
OctoBot-Trading==2.4.145
OctoBot-Trading==2.4.146
OctoBot-Evaluators==1.9.7
OctoBot-Tentacles-Manager==2.9.16
OctoBot-Services==1.6.23
Expand Down
Loading