diff --git a/packages/commons/octobot_commons/configuration/historical_configuration.py b/packages/commons/octobot_commons/configuration/historical_configuration.py index ea2e6125f2..0443524823 100644 --- a/packages/commons/octobot_commons/configuration/historical_configuration.py +++ b/packages/commons/octobot_commons/configuration/historical_configuration.py @@ -72,10 +72,7 @@ def get_historical_tentacle_configs( for config_start_time_and_config in master_config[ constants.CONFIG_HISTORICAL_CONFIGURATION ] - if ( - config_start_time_and_config[0] >= from_time - and config_start_time_and_config[0] <= to_time - ) + if from_time <= config_start_time_and_config[0] <= to_time ] except KeyError: raise KeyError( diff --git a/packages/trading/octobot_trading/exchange_data/kline/kline_manager.py b/packages/trading/octobot_trading/exchange_data/kline/kline_manager.py index 994dfef208..dac2685c79 100644 --- a/packages/trading/octobot_trading/exchange_data/kline/kline_manager.py +++ b/packages/trading/octobot_trading/exchange_data/kline/kline_manager.py @@ -34,14 +34,14 @@ def _reset_kline(self): def _update_kline_key(self, kline_key, kline_update): try: - if kline_update[kline_key] is not math.nan: + if not math.isnan(kline_update[kline_key]): self.kline[kline_key] = kline_update[kline_key] except KeyError: pass def _update_kline_init_only_key(self, kline_key, kline_update): try: - if self.kline[kline_key] is math.nan: + if math.isnan(self.kline[kline_key]): self.kline[kline_key] = kline_update[kline_key] except KeyError: pass @@ -58,11 +58,11 @@ def kline_update(self, kline): self._update_kline_key(enums.PriceIndexes.IND_PRICE_VOL.value, kline) self._update_kline_key(enums.PriceIndexes.IND_PRICE_CLOSE.value, kline) - if self.kline[enums.PriceIndexes.IND_PRICE_HIGH.value] is math.nan or \ + if math.isnan(self.kline[enums.PriceIndexes.IND_PRICE_HIGH.value]) or \ self.kline[enums.PriceIndexes.IND_PRICE_HIGH.value] < kline[enums.PriceIndexes.IND_PRICE_HIGH.value]: self._update_kline_key(enums.PriceIndexes.IND_PRICE_HIGH.value, kline) - if self.kline[enums.PriceIndexes.IND_PRICE_LOW.value] is math.nan or \ + if math.isnan(self.kline[enums.PriceIndexes.IND_PRICE_LOW.value]) or \ self.kline[enums.PriceIndexes.IND_PRICE_LOW.value] > kline[enums.PriceIndexes.IND_PRICE_LOW.value]: self._update_kline_key(enums.PriceIndexes.IND_PRICE_LOW.value, kline) except TypeError as e: diff --git a/packages/trading/octobot_trading/exchanges/connectors/ccxt/enums.py b/packages/trading/octobot_trading/exchanges/connectors/ccxt/enums.py index 00b02fe02b..dcb45838eb 100644 --- a/packages/trading/octobot_trading/exchanges/connectors/ccxt/enums.py +++ b/packages/trading/octobot_trading/exchanges/connectors/ccxt/enums.py @@ -154,6 +154,7 @@ class ExchangeColumns(enum.Enum): REST = "rest" WEBSOCKET = "ws" LOGO_URL = "logo" + ICON_URL = "icon" REFERRAL = "referral" diff --git a/packages/trading/octobot_trading/exchanges/util/exchange_market_status_fixer.py b/packages/trading/octobot_trading/exchanges/util/exchange_market_status_fixer.py index 4fd45b2722..afacf9b074 100644 --- a/packages/trading/octobot_trading/exchanges/util/exchange_market_status_fixer.py +++ b/packages/trading/octobot_trading/exchanges/util/exchange_market_status_fixer.py @@ -27,7 +27,7 @@ def is_ms_valid(value, zero_valid=False): value = float(value) except ValueError: return False - return value is not None and value is not math.nan and (value >= 0 if zero_valid else value > 0) + return value is not None and not math.isnan(value) and (value >= 0 if zero_valid else value > 0) def check_market_status_limits(market_limit): diff --git a/packages/trading/octobot_trading/exchanges/util/exchange_util.py b/packages/trading/octobot_trading/exchanges/util/exchange_util.py index 75203abf89..9fca52d763 100644 --- a/packages/trading/octobot_trading/exchanges/util/exchange_util.py +++ b/packages/trading/octobot_trading/exchanges/util/exchange_util.py @@ -175,7 +175,7 @@ async def get_exchange_details( exchange.name, exchange.urls[ccxt_enums.ExchangeColumns.WEBSITE.value], exchange.urls[ccxt_enums.ExchangeColumns.API.value], - exchange.urls[ccxt_enums.ExchangeColumns.LOGO_URL.value], + _get_exchange_image_url_from_exchange_metadata(exchange.describe()), False, ) except AttributeError as err: @@ -748,6 +748,17 @@ def _to_available_trading_types(exchange_name: str) -> list[protocol_models.Trad ] +def _get_exchange_image_url_from_exchange_metadata(exchange_metadata: dict) -> typing.Optional[str]: + options = exchange_metadata.get("options") or {} + octobot_options = options.get("octobot") or {} + octobot_urls = octobot_options.get("urls") or {} + icon_url = octobot_urls.get(ccxt_enums.ExchangeColumns.ICON_URL.value) + if icon_url: + return icon_url + exchange_urls = exchange_metadata.get("urls") or {} + return exchange_urls.get(ccxt_enums.ExchangeColumns.LOGO_URL.value) + + def _get_register_url_from_exchange_urls(exchange_urls: dict) -> typing.Optional[str]: referral = exchange_urls.get(ccxt_enums.ExchangeColumns.REFERRAL.value) if isinstance(referral, dict): @@ -767,7 +778,7 @@ def _build_ccxt_exchange_availability(exchange_name: str) -> protocol_models.Exc return protocol_models.ExchangeAvailability( internal_name=exchange_name, name=exchange_metadata.get("name") or exchange_name, - logo=exchange_urls.get(ccxt_enums.ExchangeColumns.LOGO_URL.value), + logo=_get_exchange_image_url_from_exchange_metadata(exchange_metadata), available_trading_types=_to_available_trading_types(exchange_name), support_type=_get_exchange_support_status(exchange_name), sandboxable=_is_exchange_sandboxable(exchange_metadata), diff --git a/packages/trading/requirements.txt b/packages/trading/requirements.txt index 42a94cd62a..b37e0b9514 100644 --- a/packages/trading/requirements.txt +++ b/packages/trading/requirements.txt @@ -1,7 +1,7 @@ numpy # Exchange connection requirements -octobot-ccxt==0.0.13 # always ensure real exchanges tests (in tests_additional and authenticated exchange tests) are passing before changing the ccxt version +octobot-ccxt==0.0.14 # always ensure real exchanges tests (in tests_additional and authenticated exchange tests) are passing before changing the ccxt version cryptography # Never specify a version (managed by https://github.com/Drakkar-Software/OctoBot-PyPi-Linux-Deployer) diff --git a/packages/trading/tests/exchanges/util/test_exchange_util.py b/packages/trading/tests/exchanges/util/test_exchange_util.py index 572f7a392f..6047b10f47 100644 --- a/packages/trading/tests/exchanges/util/test_exchange_util.py +++ b/packages/trading/tests/exchanges/util/test_exchange_util.py @@ -297,7 +297,7 @@ async def test_get_exchange_details(tentacles_setup_config, supported_exchanges) assert details.name == "Binance" assert details.url == "https://www.binance.com" assert len(details.api) > 1 - assert "https://github.com/user-attachments/assets" in details.logo_url + assert details.logo_url == "https://exchanges-icons.octobot.cloud/binance-icon.webp" assert details.has_websocket is False # default value get_tentacle_config_mock.assert_not_called() @@ -634,6 +634,32 @@ def test_builds_exchange_availability_from_metadata( protocol_models.TradingType.FUTURES, ] + @mock.patch.object(exchange_util, "is_broker_enabled_on_exchange", return_value=False) + @mock.patch.object(exchange_util, "get_supported_exchange_types") + @mock.patch.object(exchange_util, "_get_ccxt_exchange_metadata") + def test_prefers_icon_over_logo_in_availability( + self, + metadata_mock, + supported_types_mock, + _broker_enabled_mock, + ): + metadata_mock.return_value = { + "name": "Binance", + "options": { + "octobot": { + "urls": { + "icon": "https://exchanges-icons.octobot.cloud/binance-icon.webp", + }, + }, + }, + "urls": { + "logo": "https://logo.example/binance", + }, + } + supported_types_mock.return_value = [enums.ExchangeTypes.SPOT] + availability = exchange_util._build_ccxt_exchange_availability("binance") + assert availability.logo == "https://exchanges-icons.octobot.cloud/binance-icon.webp" + @mock.patch.object(exchange_util, "is_broker_enabled_on_exchange", return_value=False) @mock.patch.object(exchange_util, "get_supported_exchange_types") @mock.patch.object(exchange_util, "_get_ccxt_exchange_metadata")