Skip to content

Commit

Permalink
Merge pull request #2884 from Drakkar-Software/dev
Browse files Browse the repository at this point in the history
Dev merge
  • Loading branch information
GuillaumeDSM authored Feb 3, 2025
2 parents 7891fe0 + 189ab52 commit 55a2b0a
Show file tree
Hide file tree
Showing 23 changed files with 122 additions and 33 deletions.
14 changes: 11 additions & 3 deletions additional_tests/exchanges_tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import os
import dotenv
import mock
import time
import asyncio

import trading_backend
import octobot_commons.constants as commons_constants
Expand Down Expand Up @@ -101,13 +103,17 @@ async def get_authenticated_exchange_manager(
)
exchange_manager_instance.exchange.__class__.PRINT_DEBUG_LOGS = True
set_mocked_required_channels(exchange_manager_instance)
t0 = time.time()
try:
yield exchange_manager_instance
except errors.UnreachableExchange as err:
raise errors.UnreachableExchange(f"{exchange_name} can't be reached, it is either offline or you are not connected "
"to the internet (or a proxy is preventing connecting to this exchange).") \
from err
finally:
if time.time() - t0 < 1:
print("Stopping the exchange manager too quickly can end in infinite loop, ensuring at least 1s passed")
await asyncio.sleep(1)
await exchange_manager_instance.stop()
trading_api.cancel_ccxt_throttle_task()
# let updaters gracefully shutdown
Expand Down Expand Up @@ -159,9 +165,11 @@ def _invalidate(exchange_config: dict):
updated_decoded = decoded
for numb in range(9):
if str(numb) in decoded:
number_index = decoded.index(str(numb))
updated_decoded = f"{decoded[:number_index]}{numb + 1}{decoded[number_index+1:]}"
break
# replace from the end first: coinbase-like api keys have a prefix that can be changed and remain valid
number_rindex = decoded.rindex(str(numb))
if number_rindex != len(decoded) - 1:
updated_decoded = f"{decoded[:number_rindex]}{numb + 1}{decoded[number_rindex+1:]}"
break
if updated_decoded == decoded:
raise ValueError("No number to invalid api key")
exchange_config[commons_constants.CONFIG_EXCHANGE_KEY] = configuration.encrypt(updated_decoded).decode()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,8 @@ async def test_invalid_api_key_error(self):
async with self.local_exchange_manager(use_invalid_creds=True):
created_exchange()
# should fail
await self.get_portfolio()
raise AssertionError("Did not raise")
portfolio = await self.get_portfolio()
raise AssertionError(f"Did not raise on invalid api keys, fetched portfolio: {portfolio}")
# ensure self.local_exchange_manager did not raise
created_exchange.assert_called_once()

Expand Down Expand Up @@ -428,6 +428,19 @@ async def inner_test_missing_trading_api_key_permissions(self):
# ensure AuthenticationError is raised when creating order
assert "inner_test_create_and_cancel_limit_orders#create_limit_order" in str(err)

async def test_api_key_ip_whitelist_error(self):
if not self._supports_ip_whitelist_error():
return
with pytest.raises(trading_errors.InvalidAPIKeyIPWhitelistError):
created_exchange = mock.Mock()
async with self.local_exchange_manager(identifiers_suffix="_INVALID_IP_WHITELIST"):
created_exchange()
# should fail
portfolio = await self.get_portfolio()
raise AssertionError(f"Did not raise on invalid IP whitelist error, fetched portfolio: {portfolio}")
# ensure self.local_exchange_manager did not raise
created_exchange.assert_called_once()

async def test_get_not_found_order(self):
async with self.local_exchange_manager():
await self.inner_test_get_not_found_order()
Expand Down Expand Up @@ -1077,29 +1090,6 @@ async def get_price(self, symbol=None):
]
))

@contextlib.asynccontextmanager
async def local_exchange_manager(
self, market_filter=None, identifiers_suffix=None, use_invalid_creds=False, http_proxy_callback_factory=None
):
try:
exchange_tentacle_name = self.EXCHANGE_TENTACLE_NAME or self.EXCHANGE_NAME.capitalize()
credentials_exchange_name = self.CREDENTIALS_EXCHANGE_NAME or self.EXCHANGE_NAME
if identifiers_suffix:
credentials_exchange_name = f"{credentials_exchange_name}{identifiers_suffix}"
async with get_authenticated_exchange_manager(
self.EXCHANGE_NAME,
exchange_tentacle_name,
self.get_config(),
credentials_exchange_name=credentials_exchange_name,
market_filter=market_filter,
use_invalid_creds=use_invalid_creds,
http_proxy_callback_factory=http_proxy_callback_factory,
) as exchange_manager:
self.exchange_manager = exchange_manager
yield
finally:
self.exchange_manager = None

async def get_order(self, exchange_order_id, symbol=None):
assert self.exchange_manager.exchange.connector.client.has["fetchOrder"] is \
self.EXPECT_FETCH_ORDER_TO_BE_AVAILABLE
Expand Down Expand Up @@ -1554,6 +1544,37 @@ def market_filter(market):

return market_filter

@contextlib.asynccontextmanager
async def local_exchange_manager(
self, market_filter=None, identifiers_suffix=None, use_invalid_creds=False, http_proxy_callback_factory=None
):
try:
credentials_exchange_name = self.CREDENTIALS_EXCHANGE_NAME or self.EXCHANGE_NAME
if identifiers_suffix:
credentials_exchange_name = f"{credentials_exchange_name}{identifiers_suffix}"
async with get_authenticated_exchange_manager(
self.EXCHANGE_NAME,
self._get_exchange_tentacle_name(),
self.get_config(),
credentials_exchange_name=credentials_exchange_name,
market_filter=market_filter,
use_invalid_creds=use_invalid_creds,
http_proxy_callback_factory=http_proxy_callback_factory,
) as exchange_manager:
self.exchange_manager = exchange_manager
yield
finally:
self.exchange_manager = None

def _get_exchange_tentacle_name(self):
return self.EXCHANGE_TENTACLE_NAME or self.EXCHANGE_NAME.capitalize()

def _get_exchange_tentacle_class(self):
return tentacles_manager_api.get_tentacle_class_from_string(self._get_exchange_tentacle_name())

def _supports_ip_whitelist_error(self):
return bool(self._get_exchange_tentacle_class().EXCHANGE_IP_WHITELIST_ERRORS)


def _get_encoded_value(raw) -> str:
return commons_configuration.encrypt(raw).decode()
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 @@ -60,6 +60,9 @@ async def test_get_api_key_permissions(self):
async def test_missing_trading_api_key_permissions(self):
pass

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

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

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 @@ -99,6 +99,9 @@ async def test_get_api_key_permissions(self):
async def test_missing_trading_api_key_permissions(self):
await super().test_missing_trading_api_key_permissions()

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

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

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 @@ -99,6 +99,9 @@ async def test_get_api_key_permissions(self):
async def test_missing_trading_api_key_permissions(self):
pass

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

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

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 @@ -95,6 +95,9 @@ async def test_get_api_key_permissions(self):
async def test_missing_trading_api_key_permissions(self):
pass

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

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

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 @@ -62,6 +62,9 @@ async def test_get_api_key_permissions(self):
async def test_missing_trading_api_key_permissions(self):
pass

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

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

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 @@ -60,6 +60,9 @@ async def test_get_api_key_permissions(self):
async def test_missing_trading_api_key_permissions(self):
pass

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

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

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 @@ -64,6 +64,9 @@ async def test_get_api_key_permissions(self):
async def test_missing_trading_api_key_permissions(self):
pass

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

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

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 @@ -67,6 +67,9 @@ async def test_get_api_key_permissions(self):
async def test_missing_trading_api_key_permissions(self):
pass

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

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

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 @@ -90,6 +90,9 @@ async def test_get_api_key_permissions(self):
async def test_missing_trading_api_key_permissions(self):
await super().test_missing_trading_api_key_permissions()

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

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

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 @@ -59,6 +59,9 @@ async def test_get_api_key_permissions(self):
async def test_missing_trading_api_key_permissions(self):
pass

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

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

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 @@ -60,6 +60,9 @@ async def test_get_api_key_permissions(self):
async def test_missing_trading_api_key_permissions(self):
pass

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

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

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 @@ -62,6 +62,9 @@ async def test_get_api_key_permissions(self):
async def test_missing_trading_api_key_permissions(self):
pass

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

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

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 @@ -62,6 +62,9 @@ async def test_get_api_key_permissions(self):
async def test_missing_trading_api_key_permissions(self):
await super().test_missing_trading_api_key_permissions()

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

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

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 @@ -61,6 +61,9 @@ async def test_get_api_key_permissions(self):
async def test_missing_trading_api_key_permissions(self):
pass

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

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

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 @@ -102,6 +102,9 @@ async def test_get_api_key_permissions(self):
async def test_missing_trading_api_key_permissions(self):
await super().test_missing_trading_api_key_permissions()

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

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

Expand Down
5 changes: 4 additions & 1 deletion additional_tests/exchanges_tests/test_kucoin_futures.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,10 @@ async def test_get_api_key_permissions(self):
await super().test_get_api_key_permissions()

async def test_missing_trading_api_key_permissions(self):
pass
await super().test_missing_trading_api_key_permissions()

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

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

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

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

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 @@ -69,6 +69,9 @@ async def test_get_api_key_permissions(self):
async def test_missing_trading_api_key_permissions(self):
pass

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

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

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 @@ -61,6 +61,9 @@ async def test_get_api_key_permissions(self):
async def test_missing_trading_api_key_permissions(self):
pass

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

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

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 @@ -59,6 +59,9 @@ async def test_get_api_key_permissions(self):
async def test_missing_trading_api_key_permissions(self):
pass

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

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

Expand Down
8 changes: 4 additions & 4 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Drakkar-Software requirements
OctoBot-Commons==1.9.70
OctoBot-Trading==2.4.153
OctoBot-Trading==2.4.155
OctoBot-Evaluators==1.9.7
OctoBot-Tentacles-Manager==2.9.16
OctoBot-Services==1.6.23
OctoBot-Backtesting==1.9.7
Async-Channel==2.2.1
trading-backend==1.2.34
trading-backend==1.2.36

## Others
colorlog==6.8.0
Expand All @@ -22,7 +22,7 @@ gmqtt==0.7.0
pgpy==0.6.0

# Error tracking
sentry-sdk==2.19.2 # always make sure sentry_aiohttp_transport.py keep working
sentry-sdk==2.20.0 # always make sure sentry_aiohttp_transport.py keep working

# Supabase ensure supabase_backend_tests keep passing when updating any of those
supabase==2.11.0 # Supabase client
Expand All @@ -33,4 +33,4 @@ postgrest # Supabase posgres calls (required by supabase and enforced to allow
aiohttp==3.10.4
# updating to aiodns==3.2.0 is incompatible (and failing CI)
# raises RuntimeError: aiodns needs a SelectorEventLoop on Windows. See more: https://github.com/saghul/aiodns/issues/86
aiodns==3.1.1 # used by aiohttp
aiodns==3.1.1 # used by aiohttp

0 comments on commit 55a2b0a

Please sign in to comment.