Add locks per pair

This commit is contained in:
Matthias 2020-10-24 16:52:26 +02:00
parent ff7ba23477
commit 2a66c33a4e
6 changed files with 101 additions and 2 deletions

View File

@ -81,6 +81,10 @@
"lookback_period": 60, "lookback_period": 60,
"trade_limit": 4, "trade_limit": 4,
"stopduration": 60 "stopduration": 60
},
{
"method": "CooldownPeriod",
"stopduration": 20
} }
], ],
"exchange": { "exchange": {

View File

@ -27,7 +27,7 @@ AVAILABLE_PAIRLISTS = ['StaticPairList', 'VolumePairList',
'AgeFilter', 'PerformanceFilter', 'PrecisionFilter', 'AgeFilter', 'PerformanceFilter', 'PrecisionFilter',
'PriceFilter', 'RangeStabilityFilter', 'ShuffleFilter', 'PriceFilter', 'RangeStabilityFilter', 'ShuffleFilter',
'SpreadFilter'] 'SpreadFilter']
AVAILABLE_PROTECTIONS = ['StoplossGuard'] AVAILABLE_PROTECTIONS = ['StoplossGuard', 'CooldownPeriod']
AVAILABLE_DATAHANDLERS = ['json', 'jsongz', 'hdf5'] AVAILABLE_DATAHANDLERS = ['json', 'jsongz', 'hdf5']
DRY_RUN_WALLET = 1000 DRY_RUN_WALLET = 1000
DATETIME_PRINT_FORMAT = '%Y-%m-%d %H:%M:%S' DATETIME_PRINT_FORMAT = '%Y-%m-%d %H:%M:%S'

View File

@ -57,3 +57,12 @@ class ProtectionManager():
PairLocks.lock_pair('*', until, reason) PairLocks.lock_pair('*', until, reason)
return True return True
return False return False
def stop_per_pair(self, pair) -> bool:
now = datetime.now(timezone.utc)
for protection_handler in self._protection_handlers:
result, until, reason = protection_handler.stop_per_pair(pair, now)
if result and until:
PairLocks.lock_pair(pair, until, reason)
return True
return False

View File

@ -0,0 +1,68 @@
import logging
from datetime import datetime, timedelta
from typing import Any, Dict
from freqtrade.persistence import Trade
from freqtrade.plugins.protections import IProtection, ProtectionReturn
logger = logging.getLogger(__name__)
class CooldownPeriod(IProtection):
def __init__(self, config: Dict[str, Any], protection_config: Dict[str, Any]) -> None:
super().__init__(config, protection_config)
self._stopduration = protection_config.get('stopduration', 60)
def _reason(self) -> str:
"""
LockReason to use
"""
return (f'Cooldown period for {self._stopduration} min.')
def short_desc(self) -> str:
"""
Short method description - used for startup-messages
"""
return (f"{self.name} - Cooldown period.")
def _cooldown_period(self, pair: str, date_now: datetime, ) -> ProtectionReturn:
"""
Get last trade for this pair
"""
look_back_until = date_now - timedelta(minutes=self._stopduration)
filters = [
Trade.is_open.is_(False),
Trade.close_date > look_back_until,
Trade.pair == pair,
]
trade = Trade.get_trades(filters).first()
if trade:
self.log_on_refresh(logger.info, f"Cooldown for {pair} for {self._stopduration}.")
until = trade.close_date + timedelta(minutes=self._stopduration)
return True, until, self._reason()
return False, None, None
def global_stop(self, date_now: datetime) -> 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>
"""
# Not implemented for cooldown period.
return False, None, None
def stop_per_pair(self, pair: str, date_now: datetime) -> 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 self._cooldown_period(pair, date_now)

View File

@ -36,3 +36,12 @@ class IProtection(LoggingMixin, ABC):
Stops trading (position entering) for all pairs Stops trading (position entering) for all pairs
This must evaluate to true for the whole period of the "cooldown period". This must evaluate to true for the whole period of the "cooldown period".
""" """
@abstractmethod
def stop_per_pair(self, pair: str, date_now: datetime) -> 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>
"""

View File

@ -1,7 +1,7 @@
import logging import logging
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Any, Dict, Tuple from typing import Any, Dict
from sqlalchemy import and_, or_ from sqlalchemy import and_, or_
@ -68,3 +68,12 @@ class StoplossGuard(IProtection):
If true, all pairs will be locked with <reason> until <until> If true, all pairs will be locked with <reason> until <until>
""" """
return self._stoploss_guard(date_now, pair=None) return self._stoploss_guard(date_now, pair=None)
def stop_per_pair(self, pair: str, date_now: datetime) -> 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 False, None, None