implement pairlock side further
This commit is contained in:
parent
420836b1b2
commit
fc201bb4ff
@ -1445,7 +1445,7 @@ class PairLock(_DECL_BASE):
|
|||||||
f'lock_end_time={lock_end_time}, reason={self.reason}, active={self.active})')
|
f'lock_end_time={lock_end_time}, reason={self.reason}, active={self.active})')
|
||||||
|
|
||||||
@staticmethod
|
@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
|
Get all currently active locks for this pair
|
||||||
:param pair: Pair to check for. Returns all current locks if pair is empty
|
: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), ]
|
PairLock.active.is_(True), ]
|
||||||
if pair:
|
if pair:
|
||||||
filters.append(PairLock.pair == pair)
|
filters.append(PairLock.pair == pair)
|
||||||
|
if side != '*':
|
||||||
|
filters.append(PairLock.direction == side)
|
||||||
|
|
||||||
return PairLock.query.filter(
|
return PairLock.query.filter(
|
||||||
*filters
|
*filters
|
||||||
)
|
)
|
||||||
|
@ -31,7 +31,7 @@ class PairLocks():
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def lock_pair(pair: str, until: datetime, reason: str = None, *,
|
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".
|
Create PairLock from now to "until".
|
||||||
Uses database by default, unless PairLocks.use_db is set to False,
|
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 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 reason: Reason string that will be shown as reason for the lock
|
||||||
:param now: Current timestamp. Used to determine lock start time.
|
:param now: Current timestamp. Used to determine lock start time.
|
||||||
|
:param side: Side to lock pair, can be 'long', 'short' or '*'
|
||||||
"""
|
"""
|
||||||
lock = PairLock(
|
lock = PairLock(
|
||||||
pair=pair,
|
pair=pair,
|
||||||
lock_time=now or datetime.now(timezone.utc),
|
lock_time=now or datetime.now(timezone.utc),
|
||||||
lock_end_time=timeframe_to_next_date(PairLocks.timeframe, until),
|
lock_end_time=timeframe_to_next_date(PairLocks.timeframe, until),
|
||||||
reason=reason,
|
reason=reason,
|
||||||
|
direction=side,
|
||||||
active=True
|
active=True
|
||||||
)
|
)
|
||||||
if PairLocks.use_db:
|
if PairLocks.use_db:
|
||||||
@ -56,7 +58,8 @@ class PairLocks():
|
|||||||
return lock
|
return lock
|
||||||
|
|
||||||
@staticmethod
|
@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
|
Get all currently active locks for this pair
|
||||||
:param pair: Pair to check for. Returns all current locks if pair is empty
|
: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)
|
now = datetime.now(timezone.utc)
|
||||||
|
|
||||||
if PairLocks.use_db:
|
if PairLocks.use_db:
|
||||||
return PairLock.query_pair_locks(pair, now).all()
|
return PairLock.query_pair_locks(pair, now, side).all()
|
||||||
else:
|
else:
|
||||||
locks = [lock for lock in PairLocks.locks if (
|
locks = [lock for lock in PairLocks.locks if (
|
||||||
lock.lock_end_time >= now
|
lock.lock_end_time >= now
|
||||||
and lock.active is True
|
and lock.active is True
|
||||||
and (pair is None or lock.pair == pair)
|
and (pair is None or lock.pair == pair)
|
||||||
|
and (side == '*' or lock.direction == side)
|
||||||
)]
|
)]
|
||||||
return locks
|
return locks
|
||||||
|
|
||||||
@ -134,7 +138,7 @@ class PairLocks():
|
|||||||
lock.active = False
|
lock.active = False
|
||||||
|
|
||||||
@staticmethod
|
@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)).
|
:param now: Datetime object (generated via datetime.now(timezone.utc)).
|
||||||
defaults to datetime.now(timezone.utc)
|
defaults to datetime.now(timezone.utc)
|
||||||
@ -142,10 +146,10 @@ class PairLocks():
|
|||||||
if not now:
|
if not now:
|
||||||
now = datetime.now(timezone.utc)
|
now = datetime.now(timezone.utc)
|
||||||
|
|
||||||
return len(PairLocks.get_pair_locks('*', now)) > 0
|
return len(PairLocks.get_pair_locks('*', now, side)) > 0
|
||||||
|
|
||||||
@staticmethod
|
@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 pair: Pair to check for
|
||||||
:param now: Datetime object (generated via datetime.now(timezone.utc)).
|
:param now: Datetime object (generated via datetime.now(timezone.utc)).
|
||||||
@ -154,7 +158,10 @@ class PairLocks():
|
|||||||
if not now:
|
if not now:
|
||||||
now = datetime.now(timezone.utc)
|
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
|
@staticmethod
|
||||||
def get_all_locks() -> List[PairLock]:
|
def get_all_locks() -> List[PairLock]:
|
||||||
|
@ -54,8 +54,9 @@ class ProtectionManager():
|
|||||||
if protection_handler.has_global_stop:
|
if protection_handler.has_global_stop:
|
||||||
lock = protection_handler.global_stop(date_now=now, side=side)
|
lock = protection_handler.global_stop(date_now=now, side=side)
|
||||||
if lock and lock.until:
|
if lock and lock.until:
|
||||||
if not PairLocks.is_global_lock(lock.until):
|
if not PairLocks.is_global_lock(lock.until, lock.lock_side):
|
||||||
result = PairLocks.lock_pair('*', lock.until, lock.reason, now=now)
|
result = PairLocks.lock_pair(
|
||||||
|
'*', lock.until, lock.reason, now=now, side=lock.lock_side)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def stop_per_pair(self, pair, now: Optional[datetime] = None,
|
def stop_per_pair(self, pair, now: Optional[datetime] = None,
|
||||||
@ -68,6 +69,7 @@ class ProtectionManager():
|
|||||||
lock = protection_handler.stop_per_pair(
|
lock = protection_handler.stop_per_pair(
|
||||||
pair=pair, date_now=now, side=side)
|
pair=pair, date_now=now, side=side)
|
||||||
if lock and lock.until:
|
if lock and lock.until:
|
||||||
if not PairLocks.is_pair_locked(pair, lock.until):
|
if not PairLocks.is_pair_locked(pair, lock.until, lock.lock_side):
|
||||||
result = PairLocks.lock_pair(pair, lock.until, lock.reason, now=now)
|
result = PairLocks.lock_pair(
|
||||||
|
pair, lock.until, lock.reason, now=now, side=lock.lock_side)
|
||||||
return result
|
return result
|
||||||
|
@ -20,7 +20,7 @@ class ProtectionReturn:
|
|||||||
lock: bool
|
lock: bool
|
||||||
until: datetime
|
until: datetime
|
||||||
reason: Optional[str]
|
reason: Optional[str]
|
||||||
lock_side: Optional[str] = None
|
lock_side: str = '*'
|
||||||
|
|
||||||
|
|
||||||
class IProtection(LoggingMixin, ABC):
|
class IProtection(LoggingMixin, ABC):
|
||||||
|
@ -65,7 +65,7 @@ class StoplossGuard(IProtection):
|
|||||||
lock=True,
|
lock=True,
|
||||||
until=until,
|
until=until,
|
||||||
reason=self._reason(),
|
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]:
|
def global_stop(self, date_now: datetime, side: LongShort) -> Optional[ProtectionReturn]:
|
||||||
|
@ -541,7 +541,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
|||||||
"""
|
"""
|
||||||
return self.__class__.__name__
|
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.
|
Locks pair until a given timestamp happens.
|
||||||
Locked pairs are not analyzed, and are prevented from opening new trades.
|
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)`
|
Needs to be timezone aware `datetime.now(timezone.utc)`
|
||||||
:param reason: Optional string explaining why the pair was locked.
|
: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:
|
def unlock_pair(self, pair: str) -> None:
|
||||||
"""
|
"""
|
||||||
|
Loading…
Reference in New Issue
Block a user