diff --git a/freqtrade/configuration/config_validation.py b/freqtrade/configuration/config_validation.py index 6a14841ff..536feb535 100644 --- a/freqtrade/configuration/config_validation.py +++ b/freqtrade/configuration/config_validation.py @@ -1,7 +1,6 @@ import logging from collections import Counter from copy import deepcopy -from datetime import datetime from typing import Any, Dict from jsonschema import Draft4Validator, validators @@ -84,7 +83,6 @@ def validate_config_consistency(conf: Dict[str, Any], *, preliminary: bool = Fal _validate_price_config(conf) _validate_edge(conf) _validate_whitelist(conf) - _validate_protections(conf) _validate_unlimited_amount(conf) _validate_ask_orderbook(conf) _validate_freqai_hyperopt(conf) @@ -196,41 +194,6 @@ def _validate_whitelist(conf: Dict[str, Any]) -> None: raise ConfigurationError("StaticPairList requires pair_whitelist to be set.") -def _validate_protections(conf: Dict[str, Any]) -> None: - """ - Validate protection configuration validity - """ - - for prot in conf.get("protections", []): - parsed_unlock_at = None - if (config_unlock_at := prot.get("unlock_at")) is not None: - try: - parsed_unlock_at = datetime.strptime(config_unlock_at, "%H:%M") - except ValueError: - raise ConfigurationError(f"Invalid date format for unlock_at: {config_unlock_at}.") - - if "stop_duration" in prot and "stop_duration_candles" in prot: - raise ConfigurationError( - "Protections must specify either `stop_duration` or `stop_duration_candles`.\n" - f"Please fix the protection {prot.get('method')}." - ) - - if "lookback_period" in prot and "lookback_period_candles" in prot: - raise ConfigurationError( - "Protections must specify either `lookback_period` or `lookback_period_candles`.\n" - f"Please fix the protection {prot.get('method')}." - ) - - if parsed_unlock_at is not None and ( - "stop_duration" in prot or "stop_duration_candles" in prot - ): - raise ConfigurationError( - "Protections must specify either `unlock_at`, `stop_duration` or " - "`stop_duration_candles`.\n" - f"Please fix the protection {prot.get('method')}." - ) - - def _validate_ask_orderbook(conf: Dict[str, Any]) -> None: ask_strategy = conf.get("exit_pricing", {}) ob_min = ask_strategy.get("order_book_min") diff --git a/freqtrade/plugins/protectionmanager.py b/freqtrade/plugins/protectionmanager.py index 4f60ae0e0..1b07261d4 100644 --- a/freqtrade/plugins/protectionmanager.py +++ b/freqtrade/plugins/protectionmanager.py @@ -4,9 +4,10 @@ Protection manager class import logging from datetime import datetime, timezone -from typing import Dict, List, Optional +from typing import Any, Dict, List, Optional from freqtrade.constants import Config, LongShort +from freqtrade.exceptions import ConfigurationError from freqtrade.persistence import PairLocks from freqtrade.persistence.models import PairLock from freqtrade.plugins.protections import IProtection @@ -21,6 +22,7 @@ class ProtectionManager: self._config = config self._protection_handlers: List[IProtection] = [] + self.validate_protections(protections) for protection_handler_config in protections: protection_handler = ProtectionResolver.load_protection( protection_handler_config["method"], @@ -76,3 +78,40 @@ class ProtectionManager: pair, lock.until, lock.reason, now=now, side=lock.lock_side ) return result + + @staticmethod + def validate_protections(protections: List[Dict[str, Any]]) -> None: + """ + Validate protection setup validity + """ + + for prot in protections: + parsed_unlock_at = None + if (config_unlock_at := prot.get("unlock_at")) is not None: + try: + parsed_unlock_at = datetime.strptime(config_unlock_at, "%H:%M") + except ValueError: + raise ConfigurationError( + f"Invalid date format for unlock_at: {config_unlock_at}." + ) + + if "stop_duration" in prot and "stop_duration_candles" in prot: + raise ConfigurationError( + "Protections must specify either `stop_duration` or `stop_duration_candles`.\n" + f"Please fix the protection {prot.get('method')}." + ) + + if "lookback_period" in prot and "lookback_period_candles" in prot: + raise ConfigurationError( + "Protections must specify either `lookback_period` or " + f"`lookback_period_candles`.\n Please fix the protection {prot.get('method')}." + ) + + if parsed_unlock_at is not None and ( + "stop_duration" in prot or "stop_duration_candles" in prot + ): + raise ConfigurationError( + "Protections must specify either `unlock_at`, `stop_duration` or " + "`stop_duration_candles`.\n" + f"Please fix the protection {prot.get('method')}." + )