freqtrade/freqtrade

View on GitHub
freqtrade/plugins/protectionmanager.py

Summary

Maintainability
A
2 hrs
Test Coverage
"""
Protection manager class
"""

import logging
from datetime import datetime, timezone
from typing import Dict, List, Optional

from freqtrade.constants import Config, LongShort
from freqtrade.persistence import PairLocks
from freqtrade.persistence.models import PairLock
from freqtrade.plugins.protections import IProtection
from freqtrade.resolvers import ProtectionResolver


logger = logging.getLogger(__name__)


class ProtectionManager:
    def __init__(self, config: Config, protections: List) -> None:
        self._config = config

        self._protection_handlers: List[IProtection] = []
        for protection_handler_config in protections:
            protection_handler = ProtectionResolver.load_protection(
                protection_handler_config["method"],
                config=config,
                protection_config=protection_handler_config,
            )
            self._protection_handlers.append(protection_handler)

        if not self._protection_handlers:
            logger.info("No protection Handlers defined.")

    @property
    def name_list(self) -> List[str]:
        """
        Get list of loaded Protection Handler names
        """
        return [p.name for p in self._protection_handlers]

    def short_desc(self) -> List[Dict]:
        """
        List of short_desc for each Pairlist Handler
        """
        return [{p.name: p.short_desc()} for p in self._protection_handlers]

    def global_stop(
        self, now: Optional[datetime] = None, side: LongShort = "long"
    ) -> Optional[PairLock]:
        if not now:
            now = datetime.now(timezone.utc)
        result = None
        for protection_handler in self._protection_handlers:
            if protection_handler.has_global_stop:
                lock = protection_handler.global_stop(date_now=now, side=side)
                if lock and lock.until:
                    if not PairLocks.is_global_lock(lock.until, side=lock.lock_side):
                        result = PairLocks.lock_pair(
                            "*", lock.until, lock.reason, now=now, side=lock.lock_side
                        )
        return result

    def stop_per_pair(
        self, pair, now: Optional[datetime] = None, side: LongShort = "long"
    ) -> Optional[PairLock]:
        if not now:
            now = datetime.now(timezone.utc)
        result = None
        for protection_handler in self._protection_handlers:
            if protection_handler.has_local_stop:
                lock = protection_handler.stop_per_pair(pair=pair, date_now=now, side=side)
                if lock and lock.until:
                    if not PairLocks.is_pair_locked(pair, lock.until, lock.lock_side):
                        result = PairLocks.lock_pair(
                            pair, lock.until, lock.reason, now=now, side=lock.lock_side
                        )
        return result