From 4d4fee98742282826df6591a6f0bd3593bb54528 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 2 Jan 2026 11:02:04 +0100 Subject: [PATCH] feat: add futures validation to validate_exchange --- freqtrade/exchange/check_exchange.py | 2 +- freqtrade/exchange/exchange_utils.py | 16 ++++++++++++---- freqtrade/ft_types/valid_exchanges_type.py | 1 + 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/freqtrade/exchange/check_exchange.py b/freqtrade/exchange/check_exchange.py index 4c19c31f8..583868744 100644 --- a/freqtrade/exchange/check_exchange.py +++ b/freqtrade/exchange/check_exchange.py @@ -47,7 +47,7 @@ def check_exchange(config: Config, check_for_bad: bool = True) -> bool: f"{', '.join(available_exchanges())}" ) - valid, reason, _ = validate_exchange(exchange) + valid, reason, _, _ = validate_exchange(exchange) if not valid: if check_for_bad: raise OperationalException( diff --git a/freqtrade/exchange/exchange_utils.py b/freqtrade/exchange/exchange_utils.py index 3b6488b29..43d7acbd6 100644 --- a/freqtrade/exchange/exchange_utils.py +++ b/freqtrade/exchange/exchange_utils.py @@ -22,6 +22,7 @@ from ccxt import ( from freqtrade.exchange.common import ( BAD_EXCHANGES, EXCHANGE_HAS_OPTIONAL, + EXCHANGE_HAS_OPTIONAL_FUTURES, EXCHANGE_HAS_REQUIRED, MAP_EXCHANGE_CHILDCLASS, SUPPORTED_EXCHANGES, @@ -68,7 +69,7 @@ def _exchange_has_helper(ex_mod: ccxt.Exchange, required: dict[str, list[str]]) ] -def validate_exchange(exchange: str) -> tuple[bool, str, ccxt.Exchange | None]: +def validate_exchange(exchange: str) -> tuple[bool, str, str, ccxt.Exchange | None]: """ returns: can_use, reason, exchange_object with Reason including both missing and missing_opt @@ -79,10 +80,11 @@ def validate_exchange(exchange: str) -> tuple[bool, str, ccxt.Exchange | None]: ex_mod = getattr(ccxt.async_support, exchange.lower())() if not ex_mod or not ex_mod.has: - return False, "", None + return False, "", "", None result = True reasons = [] + reasons_fut = "" missing = _exchange_has_helper(ex_mod, EXCHANGE_HAS_REQUIRED) if missing: result = False @@ -90,6 +92,8 @@ def validate_exchange(exchange: str) -> tuple[bool, str, ccxt.Exchange | None]: missing_opt = _exchange_has_helper(ex_mod, EXCHANGE_HAS_OPTIONAL) + missing_futures = _exchange_has_helper(ex_mod, EXCHANGE_HAS_OPTIONAL_FUTURES) + if exchange.lower() in BAD_EXCHANGES: result = False reasons.append(BAD_EXCHANGES.get(exchange.lower(), "")) @@ -97,14 +101,17 @@ def validate_exchange(exchange: str) -> tuple[bool, str, ccxt.Exchange | None]: if missing_opt: reasons.append(f"missing opt: {', '.join(missing_opt)}") - return result, "; ".join(reasons), ex_mod + if missing_futures: + reasons_fut = f"missing futures opt: {', '.join(missing_futures)}" + + return result, "; ".join(reasons), reasons_fut, ex_mod def _build_exchange_list_entry( exchange_name: str, exchangeClasses: dict[str, Any] ) -> ValidExchangesType: exchange_name = exchange_name.lower() - valid, comment, ex_mod = validate_exchange(exchange_name) + valid, comment, comment_fut, ex_mod = validate_exchange(exchange_name) mapped_exchange_name = MAP_EXCHANGE_CHILDCLASS.get(exchange_name, exchange_name).lower() is_alias = getattr(ex_mod, "alias", False) result: ValidExchangesType = { @@ -113,6 +120,7 @@ def _build_exchange_list_entry( "valid": valid, "supported": mapped_exchange_name in SUPPORTED_EXCHANGES and not is_alias, "comment": comment, + "comment_futures": comment_fut, "dex": getattr(ex_mod, "dex", False), "is_alias": is_alias, "alias_for": inspect.getmro(ex_mod.__class__)[1]().id diff --git a/freqtrade/ft_types/valid_exchanges_type.py b/freqtrade/ft_types/valid_exchanges_type.py index d6b93f4b2..2d0e6ae2f 100644 --- a/freqtrade/ft_types/valid_exchanges_type.py +++ b/freqtrade/ft_types/valid_exchanges_type.py @@ -14,6 +14,7 @@ class ValidExchangesType(TypedDict): valid: bool supported: bool comment: str + comment_futures: str dex: bool is_alias: bool alias_for: str | None