stable/freqtrade/plugins/protections/profit_limit.py
smarmau a0b7e4d4c8
Update profit_limit.py
make flake8 compliant
2022-09-29 21:40:08 +10:00

92 lines
3.3 KiB
Python

import logging
from datetime import datetime, timedelta
from typing import Any, Dict, Optional
from freqtrade.constants import Config, LongShort
from freqtrade.persistence import Trade
from freqtrade.plugins.protections import IProtection, ProtectionReturn
logger = logging.getLogger(__name__)
class ProfitLimit(IProtection):
has_global_stop: bool = True
has_local_stop: bool = False
def __init__(self, config: Config, protection_config: Dict[str, Any]) -> None:
super().__init__(config, protection_config)
self._trade_limit = protection_config.get('trade_limit', 1)
self._required_profit = protection_config.get('profit_limit', 1.0)
def short_desc(self) -> str:
"""
Short method description - used for startup-messages
"""
return (f"{self.name} - Profit Limit Protection, locks all pairs when "
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_str}, '
f'locking for {self.stop_duration_str}.')
def _limit_profit(
self, date_now: datetime) -> Optional[ProtectionReturn]:
"""
Evaluate recent trades for pair
"""
look_back_until = date_now - timedelta(minutes=self._lookback_period)
# filters = [
# Trade.is_open.is_(False),
# Trade.close_date > look_back_until,
# ]
# if pair:
# filters.append(Trade.pair == pair)
trades = Trade.get_trades_proxy(is_open=False, close_date=look_back_until)
# trades = Trade.get_trades(filters).all()
if len(trades) < self._trade_limit:
# Not enough trades in the relevant period
return None
profit = sum(
trade.close_profit for trade in trades if trade.close_profit
)
if profit >= self._required_profit:
self.log_once(
f"Trading stopped due to {profit:.2f} >= {self._required_profit} "
f"within {self._lookback_period} minutes.", logger.info)
until = self.calculate_lock_end(trades, self._stop_duration)
return ProtectionReturn(
lock=True,
until=until,
reason=self._reason(profit)
)
return None
def global_stop(self, date_now: datetime, side: LongShort) -> Optional[ProtectionReturn]:
"""
Stops trading (position entering) for all pairs
This must evaluate to true for the whole period of the "cooldown period".
:return: Tuple of [bool, until, reason].
If true, all pairs will be locked with <reason> until <until>
"""
return self._limit_profit(date_now)
def stop_per_pair(
self, pair: str, date_now: datetime, side: LongShort) -> Optional[ProtectionReturn]:
"""
Stops trading (position entering) for this pair
This must evaluate to true for the whole period of the "cooldown period".
:return: Tuple of [bool, until, reason].
If true, this pair will be locked with <reason> until <until>
"""
return None