implement pairlock side further

This commit is contained in:
Matthias 2022-04-24 11:23:26 +02:00
parent 420836b1b2
commit fc201bb4ff
6 changed files with 28 additions and 16 deletions

View File

@ -1445,7 +1445,7 @@ class PairLock(_DECL_BASE):
f'lock_end_time={lock_end_time}, reason={self.reason}, active={self.active})')
@staticmethod
def query_pair_locks(pair: Optional[str], now: datetime) -> Query:
def query_pair_locks(pair: Optional[str], now: datetime, side: str = '*') -> Query:
"""
Get all currently active locks for this pair
:param pair: Pair to check for. Returns all current locks if pair is empty
@ -1456,6 +1456,9 @@ class PairLock(_DECL_BASE):
PairLock.active.is_(True), ]
if pair:
filters.append(PairLock.pair == pair)
if side != '*':
filters.append(PairLock.direction == side)
return PairLock.query.filter(
*filters
)

View File

@ -31,7 +31,7 @@ class PairLocks():
@staticmethod
def lock_pair(pair: str, until: datetime, reason: str = None, *,
now: datetime = None) -> PairLock:
now: datetime = None, side: str) -> PairLock:
"""
Create PairLock from now to "until".
Uses database by default, unless PairLocks.use_db is set to False,
@ -40,12 +40,14 @@ class PairLocks():
:param until: End time of the lock. Will be rounded up to the next candle.
:param reason: Reason string that will be shown as reason for the lock
:param now: Current timestamp. Used to determine lock start time.
:param side: Side to lock pair, can be 'long', 'short' or '*'
"""
lock = PairLock(
pair=pair,
lock_time=now or datetime.now(timezone.utc),
lock_end_time=timeframe_to_next_date(PairLocks.timeframe, until),
reason=reason,
direction=side,
active=True
)
if PairLocks.use_db:
@ -56,7 +58,8 @@ class PairLocks():
return lock
@staticmethod
def get_pair_locks(pair: Optional[str], now: Optional[datetime] = None) -> List[PairLock]:
def get_pair_locks(
pair: Optional[str], now: Optional[datetime] = None, side: str = '*') -> List[PairLock]:
"""
Get all currently active locks for this pair
:param pair: Pair to check for. Returns all current locks if pair is empty
@ -67,12 +70,13 @@ class PairLocks():
now = datetime.now(timezone.utc)
if PairLocks.use_db:
return PairLock.query_pair_locks(pair, now).all()
return PairLock.query_pair_locks(pair, now, side).all()
else:
locks = [lock for lock in PairLocks.locks if (
lock.lock_end_time >= now
and lock.active is True
and (pair is None or lock.pair == pair)
and (side == '*' or lock.direction == side)
)]
return locks
@ -134,7 +138,7 @@ class PairLocks():
lock.active = False
@staticmethod
def is_global_lock(now: Optional[datetime] = None) -> bool:
def is_global_lock(now: Optional[datetime] = None, side: str = '*') -> bool:
"""
:param now: Datetime object (generated via datetime.now(timezone.utc)).
defaults to datetime.now(timezone.utc)
@ -142,10 +146,10 @@ class PairLocks():
if not now:
now = datetime.now(timezone.utc)
return len(PairLocks.get_pair_locks('*', now)) > 0
return len(PairLocks.get_pair_locks('*', now, side)) > 0
@staticmethod
def is_pair_locked(pair: str, now: Optional[datetime] = None) -> bool:
def is_pair_locked(pair: str, now: Optional[datetime] = None, side: str = '*') -> bool:
"""
:param pair: Pair to check for
:param now: Datetime object (generated via datetime.now(timezone.utc)).
@ -154,7 +158,10 @@ class PairLocks():
if not now:
now = datetime.now(timezone.utc)
return len(PairLocks.get_pair_locks(pair, now)) > 0 or PairLocks.is_global_lock(now)
return (
len(PairLocks.get_pair_locks(pair, now, side)) > 0
or PairLocks.is_global_lock(now, side)
)
@staticmethod
def get_all_locks() -> List[PairLock]:

View File

@ -54,8 +54,9 @@ class ProtectionManager():
if protection_handler.has_global_stop:
lock = protection_handler.global_stop(date_now=now, side=side)
if lock and lock.until:
if not PairLocks.is_global_lock(lock.until):
result = PairLocks.lock_pair('*', lock.until, lock.reason, now=now)
if not PairLocks.is_global_lock(lock.until, lock.lock_side):
result = PairLocks.lock_pair(
'*', lock.until, lock.reason, now=now, side=lock.lock_side)
return result
def stop_per_pair(self, pair, now: Optional[datetime] = None,
@ -68,6 +69,7 @@ class ProtectionManager():
lock = protection_handler.stop_per_pair(
pair=pair, date_now=now, side=side)
if lock and lock.until:
if not PairLocks.is_pair_locked(pair, lock.until):
result = PairLocks.lock_pair(pair, lock.until, lock.reason, now=now)
if not PairLocks.is_pair_locked(pair, lock.until, lock.lock_side):
result = PairLocks.lock_pair(
pair, lock.until, lock.reason, now=now, side=lock.lock_side)
return result

View File

@ -20,7 +20,7 @@ class ProtectionReturn:
lock: bool
until: datetime
reason: Optional[str]
lock_side: Optional[str] = None
lock_side: str = '*'
class IProtection(LoggingMixin, ABC):

View File

@ -65,7 +65,7 @@ class StoplossGuard(IProtection):
lock=True,
until=until,
reason=self._reason(),
lock_side=(side if self._only_per_side else None)
lock_side=(side if self._only_per_side else '*')
)
def global_stop(self, date_now: datetime, side: LongShort) -> Optional[ProtectionReturn]:

View File

@ -541,7 +541,7 @@ class IStrategy(ABC, HyperStrategyMixin):
"""
return self.__class__.__name__
def lock_pair(self, pair: str, until: datetime, reason: str = None) -> None:
def lock_pair(self, pair: str, until: datetime, reason: str = None, side: str = '*') -> None:
"""
Locks pair until a given timestamp happens.
Locked pairs are not analyzed, and are prevented from opening new trades.
@ -552,7 +552,7 @@ class IStrategy(ABC, HyperStrategyMixin):
Needs to be timezone aware `datetime.now(timezone.utc)`
:param reason: Optional string explaining why the pair was locked.
"""
PairLocks.lock_pair(pair, until, reason)
PairLocks.lock_pair(pair, until, reason, side=side)
def unlock_pair(self, pair: str) -> None:
"""