Add duration_explanation functions

This commit is contained in:
Matthias 2020-12-07 11:08:54 +01:00
parent c993831a04
commit 0e2a43ab4d
6 changed files with 63 additions and 14 deletions

View File

@ -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()

View File

@ -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:
"""

View File

@ -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:
"""

View File

@ -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)

View File

@ -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:
"""

View File

@ -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):