Fix locking - should round before storing to have a consistent picture
This commit is contained in:
parent
9c54c9a2bf
commit
6c913fa617
@ -704,7 +704,7 @@ To verify if a pair is currently locked, use `self.is_pair_locked(pair)`.
|
|||||||
Locked pairs will always be rounded up to the next candle. So assuming a `5m` timeframe, a lock with `until` set to 10:18 will lock the pair until the candle from 10:15-10:20 will be finished.
|
Locked pairs will always be rounded up to the next candle. So assuming a `5m` timeframe, a lock with `until` set to 10:18 will lock the pair until the candle from 10:15-10:20 will be finished.
|
||||||
|
|
||||||
!!! Warning
|
!!! Warning
|
||||||
Locking pairs is not functioning during backtesting.
|
Locking pairs is not available during backtesting.
|
||||||
|
|
||||||
#### Pair locking example
|
#### Pair locking example
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ Freqtrade is the main module of this bot. It contains the class Freqtrade()
|
|||||||
import copy
|
import copy
|
||||||
import logging
|
import logging
|
||||||
import traceback
|
import traceback
|
||||||
from datetime import datetime
|
from datetime import datetime, timezone
|
||||||
from math import isclose
|
from math import isclose
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
from typing import Any, Dict, List, Optional
|
from typing import Any, Dict, List, Optional
|
||||||
@ -19,10 +19,10 @@ from freqtrade.data.dataprovider import DataProvider
|
|||||||
from freqtrade.edge import Edge
|
from freqtrade.edge import Edge
|
||||||
from freqtrade.exceptions import (DependencyException, ExchangeError, InsufficientFundsError,
|
from freqtrade.exceptions import (DependencyException, ExchangeError, InsufficientFundsError,
|
||||||
InvalidOrderException, PricingError)
|
InvalidOrderException, PricingError)
|
||||||
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_next_date
|
from freqtrade.exchange import timeframe_to_minutes
|
||||||
from freqtrade.misc import safe_value_fallback, safe_value_fallback2
|
from freqtrade.misc import safe_value_fallback, safe_value_fallback2
|
||||||
from freqtrade.pairlist.pairlistmanager import PairListManager
|
from freqtrade.pairlist.pairlistmanager import PairListManager
|
||||||
from freqtrade.persistence import Order, Trade, cleanup_db, init_db
|
from freqtrade.persistence import Order, Trade, cleanup_db, init_db, PairLocks
|
||||||
from freqtrade.resolvers import ExchangeResolver, StrategyResolver
|
from freqtrade.resolvers import ExchangeResolver, StrategyResolver
|
||||||
from freqtrade.rpc import RPCManager, RPCMessageType
|
from freqtrade.rpc import RPCManager, RPCMessageType
|
||||||
from freqtrade.state import State
|
from freqtrade.state import State
|
||||||
@ -72,6 +72,8 @@ class FreqtradeBot:
|
|||||||
|
|
||||||
self.wallets = Wallets(self.config, self.exchange)
|
self.wallets = Wallets(self.config, self.exchange)
|
||||||
|
|
||||||
|
PairLocks.timeframe = self.config['timeframe']
|
||||||
|
|
||||||
self.pairlists = PairListManager(self.exchange, self.config)
|
self.pairlists = PairListManager(self.exchange, self.config)
|
||||||
|
|
||||||
self.dataprovider = DataProvider(self.config, self.exchange, self.pairlists)
|
self.dataprovider = DataProvider(self.config, self.exchange, self.pairlists)
|
||||||
@ -363,9 +365,9 @@ class FreqtradeBot:
|
|||||||
except DependencyException as exception:
|
except DependencyException as exception:
|
||||||
logger.warning('Unable to create trade for %s: %s', pair, exception)
|
logger.warning('Unable to create trade for %s: %s', pair, exception)
|
||||||
|
|
||||||
if not trades_created:
|
if not trades_created:
|
||||||
logger.debug("Found no buy signals for whitelisted currencies. "
|
logger.debug("Found no buy signals for whitelisted currencies. "
|
||||||
"Trying again...")
|
"Trying again...")
|
||||||
|
|
||||||
return trades_created
|
return trades_created
|
||||||
|
|
||||||
@ -937,7 +939,7 @@ class FreqtradeBot:
|
|||||||
self.update_trade_state(trade, trade.stoploss_order_id, stoploss_order,
|
self.update_trade_state(trade, trade.stoploss_order_id, stoploss_order,
|
||||||
stoploss_order=True)
|
stoploss_order=True)
|
||||||
# Lock pair for one candle to prevent immediate rebuys
|
# Lock pair for one candle to prevent immediate rebuys
|
||||||
self.strategy.lock_pair(trade.pair, timeframe_to_next_date(self.config['timeframe']),
|
self.strategy.lock_pair(trade.pair, datetime.now(timezone.utc),
|
||||||
reason='Auto lock')
|
reason='Auto lock')
|
||||||
self._notify_sell(trade, "stoploss")
|
self._notify_sell(trade, "stoploss")
|
||||||
return True
|
return True
|
||||||
@ -1264,7 +1266,7 @@ class FreqtradeBot:
|
|||||||
Trade.session.flush()
|
Trade.session.flush()
|
||||||
|
|
||||||
# Lock pair for one candle to prevent immediate rebuys
|
# Lock pair for one candle to prevent immediate rebuys
|
||||||
self.strategy.lock_pair(trade.pair, timeframe_to_next_date(self.config['timeframe']),
|
self.strategy.lock_pair(trade.pair, datetime.now(timezone.utc),
|
||||||
reason='Auto lock')
|
reason='Auto lock')
|
||||||
|
|
||||||
self._notify_sell(trade, order_type)
|
self._notify_sell(trade, order_type)
|
||||||
|
@ -694,7 +694,7 @@ class PairLock(_DECL_BASE):
|
|||||||
if not now:
|
if not now:
|
||||||
now = datetime.now(timezone.utc)
|
now = datetime.now(timezone.utc)
|
||||||
|
|
||||||
filters = [func.datetime(PairLock.lock_end_time) >= now,
|
filters = [PairLock.lock_end_time > now,
|
||||||
# Only active locks
|
# Only active locks
|
||||||
PairLock.active.is_(True), ]
|
PairLock.active.is_(True), ]
|
||||||
if pair:
|
if pair:
|
||||||
|
@ -5,6 +5,7 @@ from datetime import datetime, timezone
|
|||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from freqtrade.persistence.models import PairLock
|
from freqtrade.persistence.models import PairLock
|
||||||
|
from freqtrade.exchange import timeframe_to_next_date
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -19,12 +20,14 @@ class PairLocks():
|
|||||||
use_db = True
|
use_db = True
|
||||||
locks: List[PairLock] = []
|
locks: List[PairLock] = []
|
||||||
|
|
||||||
|
timeframe: str = ''
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def lock_pair(pair: str, until: datetime, reason: str = None) -> None:
|
def lock_pair(pair: str, until: datetime, reason: str = None) -> None:
|
||||||
lock = PairLock(
|
lock = PairLock(
|
||||||
pair=pair,
|
pair=pair,
|
||||||
lock_time=datetime.now(timezone.utc),
|
lock_time=datetime.now(timezone.utc),
|
||||||
lock_end_time=until,
|
lock_end_time=timeframe_to_next_date(PairLocks.timeframe, until),
|
||||||
reason=reason,
|
reason=reason,
|
||||||
active=True
|
active=True
|
||||||
)
|
)
|
||||||
@ -49,7 +52,7 @@ class PairLocks():
|
|||||||
return PairLock.query_pair_locks(pair, now).all()
|
return PairLock.query_pair_locks(pair, now).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)
|
||||||
)]
|
)]
|
||||||
|
@ -388,7 +388,8 @@ def test_is_pair_locked(default_conf):
|
|||||||
pair = 'BTC/USDT'
|
pair = 'BTC/USDT'
|
||||||
# Lock until 14:30
|
# Lock until 14:30
|
||||||
lock_time = datetime(2020, 5, 1, 14, 30, 0, tzinfo=timezone.utc)
|
lock_time = datetime(2020, 5, 1, 14, 30, 0, tzinfo=timezone.utc)
|
||||||
strategy.lock_pair(pair, lock_time)
|
# Subtract 2 seconds, as locking rounds up to the next candle.
|
||||||
|
strategy.lock_pair(pair, lock_time - timedelta(seconds=2))
|
||||||
|
|
||||||
assert not strategy.is_pair_locked(pair)
|
assert not strategy.is_pair_locked(pair)
|
||||||
# latest candle is from 14:20, lock goes to 14:30
|
# latest candle is from 14:20, lock goes to 14:30
|
||||||
|
@ -15,7 +15,7 @@ from freqtrade.exceptions import (DependencyException, ExchangeError, Insufficie
|
|||||||
InvalidOrderException, OperationalException, PricingError,
|
InvalidOrderException, OperationalException, PricingError,
|
||||||
TemporaryError)
|
TemporaryError)
|
||||||
from freqtrade.freqtradebot import FreqtradeBot
|
from freqtrade.freqtradebot import FreqtradeBot
|
||||||
from freqtrade.persistence import Order, PairLocks, Trade
|
from freqtrade.persistence import Order, Trade
|
||||||
from freqtrade.persistence.models import PairLock
|
from freqtrade.persistence.models import PairLock
|
||||||
from freqtrade.rpc import RPCMessageType
|
from freqtrade.rpc import RPCMessageType
|
||||||
from freqtrade.state import RunMode, State
|
from freqtrade.state import RunMode, State
|
||||||
|
Loading…
Reference in New Issue
Block a user