Support multis-strategy backtests with protections

This commit is contained in:
Matthias 2020-11-25 09:53:13 +01:00
parent a3f9cd2c26
commit 75a5161650
5 changed files with 64 additions and 4 deletions

View File

@ -120,8 +120,10 @@ class Backtesting:
self.fee = self.exchange.get_fee(symbol=self.pairlists.whitelist[0])
Trade.use_db = False
Trade.reset_trades()
PairLocks.timeframe = self.config['timeframe']
PairLocks.use_db = False
PairLocks.reset_locks()
if self.config.get('enable_protections', False):
self.protections = ProtectionManager(self.config)
@ -130,6 +132,11 @@ class Backtesting:
# Load one (first) strategy
self._set_strategy(self.strategylist[0])
def __del__(self):
LoggingMixin.show_output = True
PairLocks.use_db = True
Trade.use_db = True
def _set_strategy(self, strategy):
"""
Load strategy into backtesting
@ -321,6 +328,13 @@ class Backtesting:
f"max_open_trades: {max_open_trades}, position_stacking: {position_stacking}"
)
trades = []
PairLocks.use_db = False
Trade.use_db = False
if enable_protections:
# Reset persisted data - used for protections only
PairLocks.reset_locks()
Trade.reset_trades()
# Use dict of lists with data for performance
# (looping lists is a lot faster than pandas DataFrames)

View File

@ -327,6 +327,14 @@ class Trade(_DECL_BASE):
'open_order_id': self.open_order_id,
}
@staticmethod
def reset_trades() -> None:
"""
Resets all trades. Only active for backtesting mode.
"""
if not Trade.use_db:
Trade.trades = []
def adjust_min_max_rates(self, current_price: float) -> None:
"""
Adjust the max_rate and min_rate.

View File

@ -21,6 +21,14 @@ class PairLocks():
timeframe: str = ''
@staticmethod
def reset_locks() -> None:
"""
Resets all locks. Only active for backtesting mode.
"""
if not PairLocks.use_db:
PairLocks.locks = []
@staticmethod
def lock_pair(pair: str, until: datetime, reason: str = None, *, now: datetime = None) -> None:
"""

View File

@ -55,8 +55,8 @@ class StoplossGuard(IProtection):
# trades = Trade.get_trades(filters).all()
trades1 = Trade.get_trades_proxy(pair=pair, is_open=False, close_date=look_back_until)
trades = [trade for trade in trades1 if trade.sell_reason == SellType.STOP_LOSS
or (trade.sell_reason == SellType.TRAILING_STOP_LOSS
trades = [trade for trade in trades1 if str(trade.sell_reason) == SellType.STOP_LOSS.value
or (str(trade.sell_reason) == SellType.TRAILING_STOP_LOSS.value
and trade.close_profit < 0)]
if len(trades) > self._trade_limit:

View File

@ -95,6 +95,7 @@ def simple_backtest(config, contour, num_results, mocker, testdatadir) -> None:
end_date=max_date,
max_open_trades=1,
position_stacking=False,
enable_protections=config.get('enable_protections', False),
)
# results :: <class 'pandas.core.frame.DataFrame'>
assert len(results) == num_results
@ -532,10 +533,39 @@ def test_processed(default_conf, mocker, testdatadir) -> None:
def test_backtest_pricecontours(default_conf, fee, mocker, testdatadir) -> None:
# TODO: Evaluate usefullness of this, the patterns and buy-signls are unrealistic
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
tests = [['raise', 19], ['lower', 0], ['sine', 35]]
tests = [
['sine', 35],
['raise', 19],
['lower', 0],
['sine', 35],
['raise', 19]
]
# While buy-signals are unrealistic, running backtesting
# over and over again should not cause different results
for [contour, numres] in tests:
simple_backtest(default_conf, contour, numres, mocker, testdatadir)
def test_backtest_pricecontours_protections(default_conf, fee, mocker, testdatadir) -> None:
# TODO: Evaluate usefullness of this, the patterns and buy-signls are unrealistic
default_conf['protections'] = [
{
"method": "CooldownPeriod",
"stop_duration": 3,
}]
default_conf['enable_protections'] = True
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
tests = [
['sine', 9],
['raise', 10],
['lower', 0],
['sine', 9],
['raise', 10],
]
# While buy-signals are unrealistic, running backtesting
# over and over again should not cause different results
for [contour, numres] in tests:
simple_backtest(default_conf, contour, numres, mocker, testdatadir)