Add "allow_position_stacking" value to config, which allows rebuys of a pair

Add function unlock_reason(str: pair) which removes all PairLocks with reason
Provide demo strategy that allows buying the same pair multiple times
This commit is contained in:
incrementby1
2021-10-26 00:04:40 +02:00
parent b4bedc22d7
commit c3f3bdaa2a
6 changed files with 727 additions and 5 deletions

View File

@@ -137,6 +137,12 @@ class Configuration:
setup_logging(config)
def _process_trading_options(self, config: Dict[str, Any]) -> None:
# Allow_position_stacking defaults to False
if not config.get('allow_position_stacking'):
config['allow_position_stacking'] = False
logger.info('Allow_position_stacking is set to ' + str(config['allow_position_stacking']))
if config['runmode'] not in TRADING_MODES:
return

View File

@@ -4,7 +4,7 @@ Freqtrade is the main module of this bot. It contains the class Freqtrade()
import copy
import logging
import traceback
from datetime import datetime, timezone
from datetime import datetime, timedelta, timezone
from math import isclose
from threading import Lock
from typing import Any, Dict, List, Optional
@@ -359,10 +359,12 @@ class FreqtradeBot(LoggingMixin):
logger.info("Active pair whitelist is empty.")
return trades_created
# Remove pairs for currently opened trades from the whitelist
for trade in Trade.get_open_trades():
if trade.pair in whitelist:
whitelist.remove(trade.pair)
logger.debug('Ignoring %s in pair whitelist', trade.pair)
# Allow rebuying of the same pair if allow_position_stacking is set to True
if not self.config['allow_position_stacking']:
for trade in Trade.get_open_trades():
if trade.pair in whitelist:
whitelist.remove(trade.pair)
logger.debug('Ignoring %s in pair whitelist', trade.pair)
if not whitelist:
logger.info("No currency pair in active pair whitelist, "
@@ -592,6 +594,11 @@ class FreqtradeBot(LoggingMixin):
self._notify_enter(trade, order_type)
# Lock pair for 1 timeframe duration to prevent immediate rebuys
if self.config['allow_position_stacking']:
self.strategy.lock_pair(trade.pair, datetime.now(timezone.utc) + timedelta(minutes=timeframe_to_minutes(self.config['timeframe'])),
reason='Prevent immediate rebuys')
return True
def _notify_enter(self, trade: Trade, order_type: str) -> None:

View File

@@ -103,6 +103,24 @@ class PairLocks():
if PairLocks.use_db:
PairLock.query.session.commit()
@staticmethod
def unlock_reason(reason: str, now: Optional[datetime] = None) -> None:
"""
Release all locks for this reason.
:param reason: Which reason to unlock
:param now: Datetime object (generated via datetime.now(timezone.utc)).
defaults to datetime.now(timezone.utc)
"""
if not now:
now = datetime.now(timezone.utc)
logger.info(f"Releasing all locks with reason \'{reason}\'.")
locks = PairLocks.get_all_locks()
for lock in locks:
if lock.reason == reason:
lock.active = False
if PairLocks.use_db:
PairLock.query.session.commit()
@staticmethod
def is_global_lock(now: Optional[datetime] = None) -> bool:
"""

View File

@@ -443,6 +443,15 @@ class IStrategy(ABC, HyperStrategyMixin):
"""
PairLocks.unlock_pair(pair, datetime.now(timezone.utc))
def unlock_reason(self, reason: str) -> None:
"""
Unlocks all pairs previously locked using lock_pair with specified reason.
Not used by freqtrade itself, but intended to be used if users lock pairs
manually from within the strategy, to allow an easy way to unlock pairs.
:param reason: Unlock pairs to allow trading again
"""
PairLocks.unlock_reason(reason, datetime.now(timezone.utc))
def is_pair_locked(self, pair: str, candle_date: datetime = None) -> bool:
"""
Checks if a pair is currently locked