Improve tests for backtest protections

This commit is contained in:
Matthias 2020-12-02 07:42:39 +01:00
parent 5849d07497
commit effc96e92b
8 changed files with 37 additions and 31 deletions

View File

@ -121,8 +121,8 @@ The base-class provides an instance of the exchange (`self._exchange`) the pairl
self._pairlist_pos = pairlist_pos
```
!!! Note
You'll need to register your pairlist in `constants.py` under the variable `AVAILABLE_PAIRLISTS` - otherwise it will not be selectable.
!!! Tip
Don't forget to register your pairlist in `constants.py` under the variable `AVAILABLE_PAIRLISTS` - otherwise it will not be selectable.
Now, let's step through the methods which require actions:
@ -184,6 +184,7 @@ No protection should use datetime directly, but use the provided `date_now` vari
!!! Tip "Writing a new Protection"
Best copy one of the existing Protections to have a good example.
Don't forget to register your protection in `constants.py` under the variable `AVAILABLE_PROTECTIONS` - otherwise it will not be selectable.
#### Implementation of a new protection

View File

@ -1,7 +1,7 @@
## Protections
!!! Warning "Beta feature"
This feature is still in it's testing phase. Should you notice something you think is wrong please let us know via Discord, Slack or via Issue.
This feature is still in it's testing phase. Should you notice something you think is wrong please let us know via Discord, Slack or via Github Issue.
Protections will protect your strategy from unexpected events and market conditions by temporarily stop trading for either one pair, or for all pairs.
All protection end times are rounded up to the next candle to avoid sudden, unexpected intra-candle buys.
@ -13,7 +13,7 @@ All protection end times are rounded up to the next candle to avoid sudden, unex
Each Protection can be configured multiple times with different parameters, to allow different levels of protection (short-term / long-term).
!!! Note "Backtesting"
Protections are supported by backtesting and hyperopt, but must be enabled by using the `--enable-protections` flag.
Protections are supported by backtesting and hyperopt, but must be explicitly enabled by using the `--enable-protections` flag.
### Available Protections

View File

@ -1,5 +1,3 @@
from typing import Callable
from cachetools import TTLCache, cached

View File

@ -1,2 +0,0 @@
# flake8: noqa: F401
# from freqtrade.plugins.protectionmanager import ProtectionManager

View File

@ -3,8 +3,6 @@ import logging
from datetime import datetime, timedelta
from typing import Any, Dict
from sqlalchemy import and_, or_
from freqtrade.persistence import Trade
from freqtrade.plugins.protections import IProtection, ProtectionReturn
from freqtrade.strategy.interface import SellType

View File

@ -79,7 +79,7 @@ def load_data_test(what, testdatadir):
fill_missing=True)}
def simple_backtest(config, contour, num_results, mocker, testdatadir) -> None:
def simple_backtest(config, contour, mocker, testdatadir) -> None:
patch_exchange(mocker)
config['timeframe'] = '1m'
backtesting = Backtesting(config)
@ -98,7 +98,7 @@ def simple_backtest(config, contour, num_results, mocker, testdatadir) -> None:
enable_protections=config.get('enable_protections', False),
)
# results :: <class 'pandas.core.frame.DataFrame'>
assert len(results) == num_results
return results
# FIX: fixturize this?
@ -532,23 +532,9 @@ def test_processed(default_conf, mocker, testdatadir) -> None:
assert col in cols
def test_backtest_pricecontours(default_conf, fee, mocker, testdatadir) -> None:
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
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
# While this test IS a copy of test_backtest_pricecontours, it's needed to ensure
# results do not carry-over to the next run, which is not given by using parametrize.
default_conf['protections'] = [
{
"method": "CooldownPeriod",
@ -567,7 +553,31 @@ def test_backtest_pricecontours_protections(default_conf, fee, mocker, testdatad
# 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)
assert len(simple_backtest(default_conf, contour, mocker, testdatadir)) == numres
@pytest.mark.parametrize('protections,contour,expected', [
(None, 'sine', 35),
(None, 'raise', 19),
(None, 'lower', 0),
(None, 'sine', 35),
(None, 'raise', 19),
([{"method": "CooldownPeriod", "stop_duration": 3}], 'sine', 9),
([{"method": "CooldownPeriod", "stop_duration": 3}], 'raise', 10),
([{"method": "CooldownPeriod", "stop_duration": 3}], 'lower', 0),
([{"method": "CooldownPeriod", "stop_duration": 3}], 'sine', 9),
([{"method": "CooldownPeriod", "stop_duration": 3}], 'raise', 10),
])
def test_backtest_pricecontours(default_conf, fee, mocker, testdatadir,
protections, contour, expected) -> None:
if protections:
default_conf['protections'] = protections
default_conf['enable_protections'] = True
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
# While buy-signals are unrealistic, running backtesting
# over and over again should not cause different results
assert len(simple_backtest(default_conf, contour, mocker, testdatadir)) == expected
def test_backtest_clash_buy_sell(mocker, default_conf, testdatadir):

View File

@ -76,7 +76,8 @@ def test_generate_backtest_stats(default_conf, testdatadir):
"sell_reason": [SellType.ROI, SellType.STOP_LOSS,
SellType.ROI, SellType.FORCE_SELL]
}),
'config': default_conf}
'config': default_conf,
'locks': []}
}
timerange = TimeRange.parse_timerange('1510688220-1510700340')
min_date = Arrow.fromtimestamp(1510688220)

View File

@ -1,5 +1,5 @@
import random
from datetime import datetime, timedelta, timezone
from datetime import datetime, timedelta
import pytest