Add duration_explanation functions
This commit is contained in:
parent
c993831a04
commit
0e2a43ab4d
@ -22,13 +22,13 @@ class CooldownPeriod(IProtection):
|
||||
"""
|
||||
LockReason to use
|
||||
"""
|
||||
return (f'Cooldown period for {self._stop_duration} min.')
|
||||
return (f'Cooldown period for {self.stop_duration_str}.')
|
||||
|
||||
def short_desc(self) -> str:
|
||||
"""
|
||||
Short method description - used for startup-messages
|
||||
"""
|
||||
return (f"{self.name} - Cooldown period of {self._stop_duration} min.")
|
||||
return (f"{self.name} - Cooldown period of {self.stop_duration_str}.")
|
||||
|
||||
def _cooldown_period(self, pair: str, date_now: datetime, ) -> ProtectionReturn:
|
||||
"""
|
||||
@ -42,7 +42,7 @@ class CooldownPeriod(IProtection):
|
||||
]
|
||||
trade = Trade.get_trades(filters).first()
|
||||
if trade:
|
||||
self.log_once(f"Cooldown for {pair} for {self._stop_duration}.", logger.info)
|
||||
self.log_once(f"Cooldown for {pair} for {self.stop_duration_str}.", logger.info)
|
||||
until = self.calculate_lock_end([trade], self._stop_duration)
|
||||
|
||||
return True, until, self._reason()
|
||||
|
@ -5,6 +5,7 @@ from datetime import datetime, timedelta, timezone
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
from freqtrade.exchange import timeframe_to_minutes
|
||||
from freqtrade.misc import plural
|
||||
from freqtrade.mixins import LoggingMixin
|
||||
from freqtrade.persistence import Trade
|
||||
|
||||
@ -26,12 +27,16 @@ class IProtection(LoggingMixin, ABC):
|
||||
self._protection_config = protection_config
|
||||
tf_in_min = timeframe_to_minutes(config['timeframe'])
|
||||
if 'stop_duration_candles' in protection_config:
|
||||
self._stop_duration = (tf_in_min * protection_config.get('stop_duration_candles'))
|
||||
self._stop_duration_candles = protection_config.get('stop_duration_candles', 1)
|
||||
self._stop_duration = (tf_in_min * self._stop_duration_candles)
|
||||
else:
|
||||
self._stop_duration_candles = None
|
||||
self._stop_duration = protection_config.get('stop_duration', 60)
|
||||
if 'lookback_period_candles' in protection_config:
|
||||
self._lookback_period = tf_in_min * protection_config.get('lookback_period_candles', 60)
|
||||
self._lookback_period_candles = protection_config.get('lookback_period_candles', 1)
|
||||
self._lookback_period = tf_in_min * self._lookback_period_candles
|
||||
else:
|
||||
self._lookback_period_candles = None
|
||||
self._lookback_period = protection_config.get('lookback_period', 60)
|
||||
|
||||
LoggingMixin.__init__(self, logger)
|
||||
@ -40,6 +45,30 @@ class IProtection(LoggingMixin, ABC):
|
||||
def name(self) -> str:
|
||||
return self.__class__.__name__
|
||||
|
||||
@property
|
||||
def stop_duration_str(self) -> str:
|
||||
"""
|
||||
Output configured stop duration in either candles or minutes
|
||||
"""
|
||||
if self._stop_duration_candles:
|
||||
return (f"{self._stop_duration_candles} "
|
||||
f"{plural(self._stop_duration_candles, 'candle', 'candles')}")
|
||||
else:
|
||||
return (f"{self._stop_duration} "
|
||||
f"{plural(self._stop_duration, 'minute', 'minutes')}")
|
||||
|
||||
@property
|
||||
def lookback_period_str(self) -> str:
|
||||
"""
|
||||
Output configured lookback period in either candles or minutes
|
||||
"""
|
||||
if self._lookback_period_candles:
|
||||
return (f"{self._lookback_period_candles} "
|
||||
f"{plural(self._lookback_period_candles, 'candle', 'candles')}")
|
||||
else:
|
||||
return (f"{self._lookback_period} "
|
||||
f"{plural(self._lookback_period, 'minute', 'minutes')}")
|
||||
|
||||
@abstractmethod
|
||||
def short_desc(self) -> str:
|
||||
"""
|
||||
|
@ -26,14 +26,14 @@ class LowProfitPairs(IProtection):
|
||||
Short method description - used for startup-messages
|
||||
"""
|
||||
return (f"{self.name} - Low Profit Protection, locks pairs with "
|
||||
f"profit < {self._required_profit} within {self._lookback_period} minutes.")
|
||||
f"profit < {self._required_profit} within {self.lookback_period_str}.")
|
||||
|
||||
def _reason(self, profit: float) -> str:
|
||||
"""
|
||||
LockReason to use
|
||||
"""
|
||||
return (f'{profit} < {self._required_profit} in {self._lookback_period} min, '
|
||||
f'locking for {self._stop_duration} min.')
|
||||
return (f'{profit} < {self._required_profit} in {self.lookback_period_str}, '
|
||||
f'locking for {self.stop_duration_str}.')
|
||||
|
||||
def _low_profit(self, date_now: datetime, pair: str) -> ProtectionReturn:
|
||||
"""
|
||||
|
@ -30,14 +30,14 @@ class MaxDrawdown(IProtection):
|
||||
Short method description - used for startup-messages
|
||||
"""
|
||||
return (f"{self.name} - Max drawdown protection, stop trading if drawdown is > "
|
||||
f"{self._max_allowed_drawdown} within {self._lookback_period} minutes.")
|
||||
f"{self._max_allowed_drawdown} within {self.lookback_period_str}.")
|
||||
|
||||
def _reason(self, drawdown: float) -> str:
|
||||
"""
|
||||
LockReason to use
|
||||
"""
|
||||
return (f'{drawdown} > {self._max_allowed_drawdown} in {self._lookback_period} min, '
|
||||
f'locking for {self._stop_duration} min.')
|
||||
return (f'{drawdown} > {self._max_allowed_drawdown} in {self.lookback_period_str}, '
|
||||
f'locking for {self.stop_duration_str}.')
|
||||
|
||||
def _max_drawdown(self, date_now: datetime) -> ProtectionReturn:
|
||||
"""
|
||||
@ -62,7 +62,7 @@ class MaxDrawdown(IProtection):
|
||||
if drawdown > self._max_allowed_drawdown:
|
||||
self.log_once(
|
||||
f"Trading stopped due to Max Drawdown {drawdown:.2f} < {self._max_allowed_drawdown}"
|
||||
f" within {self._lookback_period} minutes.", logger.info)
|
||||
f" within {self.lookback_period_str}.", logger.info)
|
||||
until = self.calculate_lock_end(trades, self._stop_duration)
|
||||
|
||||
return True, until, self._reason(drawdown)
|
||||
|
@ -29,7 +29,7 @@ class StoplossGuard(IProtection):
|
||||
Short method description - used for startup-messages
|
||||
"""
|
||||
return (f"{self.name} - Frequent Stoploss Guard, {self._trade_limit} stoplosses "
|
||||
f"within {self._lookback_period} minutes.")
|
||||
f"within {self.lookback_period_str}.")
|
||||
|
||||
def _reason(self) -> str:
|
||||
"""
|
||||
|
@ -350,7 +350,7 @@ def test_MaxDrawdown(mocker, default_conf, fee, caplog):
|
||||
None
|
||||
),
|
||||
({"method": "CooldownPeriod", "stop_duration": 60},
|
||||
"[{'CooldownPeriod': 'CooldownPeriod - Cooldown period of 60 min.'}]",
|
||||
"[{'CooldownPeriod': 'CooldownPeriod - Cooldown period of 60 minutes.'}]",
|
||||
None
|
||||
),
|
||||
({"method": "LowProfitPairs", "lookback_period": 60, "stop_duration": 60},
|
||||
@ -363,6 +363,26 @@ def test_MaxDrawdown(mocker, default_conf, fee, caplog):
|
||||
"within 60 minutes.'}]",
|
||||
None
|
||||
),
|
||||
({"method": "StoplossGuard", "lookback_period_candles": 12, "trade_limit": 2,
|
||||
"stop_duration": 60},
|
||||
"[{'StoplossGuard': 'StoplossGuard - Frequent Stoploss Guard, "
|
||||
"2 stoplosses within 12 candles.'}]",
|
||||
None
|
||||
),
|
||||
({"method": "CooldownPeriod", "stop_duration_candles": 5},
|
||||
"[{'CooldownPeriod': 'CooldownPeriod - Cooldown period of 5 candles.'}]",
|
||||
None
|
||||
),
|
||||
({"method": "LowProfitPairs", "lookback_period_candles": 11, "stop_duration": 60},
|
||||
"[{'LowProfitPairs': 'LowProfitPairs - Low Profit Protection, locks pairs with "
|
||||
"profit < 0.0 within 11 candles.'}]",
|
||||
None
|
||||
),
|
||||
({"method": "MaxDrawdown", "lookback_period_candles": 20, "stop_duration": 60},
|
||||
"[{'MaxDrawdown': 'MaxDrawdown - Max drawdown protection, stop trading if drawdown is > 0.0 "
|
||||
"within 20 candles.'}]",
|
||||
None
|
||||
),
|
||||
])
|
||||
def test_protection_manager_desc(mocker, default_conf, protectionconf,
|
||||
desc_expected, exception_expected):
|
||||
|
Loading…
Reference in New Issue
Block a user