From 54226b45b1913383da8cc2922421ce01f83ffeac Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 7 Jun 2020 16:02:08 +0200 Subject: [PATCH 1/3] Add test verifying failure --- tests/optimize/test_backtesting.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index 40c106975..b1e9dec56 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -401,6 +401,33 @@ def test_backtesting_no_pair_left(default_conf, mocker, caplog, testdatadir) -> Backtesting(default_conf) + +def test_backtesting_pairlist_list(default_conf, mocker, caplog, testdatadir, tickers) -> None: + mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True)) + mocker.patch('freqtrade.exchange.Exchange.get_tickers', tickers) + mocker.patch('freqtrade.exchange.Exchange.price_to_precision', lambda s, x, y: y) + mocker.patch('freqtrade.data.history.get_timerange', get_timerange) + patch_exchange(mocker) + mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest') + mocker.patch('freqtrade.pairlist.pairlistmanager.PairListManager.whitelist', + PropertyMock(return_value=['XRP/BTC'])) + mocker.patch('freqtrade.pairlist.pairlistmanager.PairListManager.refresh_pairlist') + + default_conf['ticker_interval'] = "1m" + default_conf['datadir'] = testdatadir + default_conf['export'] = None + # Use stoploss from strategy + del default_conf['stoploss'] + default_conf['timerange'] = '20180101-20180102' + + default_conf['pairlists'] = [{"method": "VolumePairList", "number_assets": 5}] + with pytest.raises(OperationalException, match='VolumePairList not allowed for backtesting.'): + Backtesting(default_conf) + + default_conf['pairlists'] = [{"method": "StaticPairList"}, {"method": "PrecisionFilter"}, ] + Backtesting(default_conf) + + def test_backtest(default_conf, fee, mocker, testdatadir) -> None: default_conf['ask_strategy']['use_sell_signal'] = False mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) From 72ae4b15002801a47ad4b3ae0576b414d37020f4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 7 Jun 2020 16:06:20 +0200 Subject: [PATCH 2/3] Load pairlist after strategy to use strategy-config fail in certain conditions when using strategy-list Fix #3363 --- freqtrade/optimize/backtesting.py | 33 +++++++++++++++++------------- tests/optimize/test_backtesting.py | 7 ++++++- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index b47b38ea4..0c5bb1a0c 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -65,20 +65,6 @@ class Backtesting: self.strategylist: List[IStrategy] = [] self.exchange = ExchangeResolver.load_exchange(self.config['exchange']['name'], self.config) - self.pairlists = PairListManager(self.exchange, self.config) - if 'VolumePairList' in self.pairlists.name_list: - raise OperationalException("VolumePairList not allowed for backtesting.") - - self.pairlists.refresh_pairlist() - - if len(self.pairlists.whitelist) == 0: - raise OperationalException("No pair in whitelist.") - - if config.get('fee'): - self.fee = config['fee'] - else: - self.fee = self.exchange.get_fee(symbol=self.pairlists.whitelist[0]) - if self.config.get('runmode') != RunMode.HYPEROPT: self.dataprovider = DataProvider(self.config, self.exchange) IStrategy.dp = self.dataprovider @@ -101,6 +87,25 @@ class Backtesting: self.timeframe = str(self.config.get('ticker_interval')) self.timeframe_min = timeframe_to_minutes(self.timeframe) + self.pairlists = PairListManager(self.exchange, self.config) + if 'VolumePairList' in self.pairlists.name_list: + raise OperationalException("VolumePairList not allowed for backtesting.") + + if len(self.strategylist) > 1 and 'PrecisionFilter' in self.pairlists.name_list: + raise OperationalException( + "PrecisionFilter not allowed for backtesting multiple strategies." + ) + + self.pairlists.refresh_pairlist() + + if len(self.pairlists.whitelist) == 0: + raise OperationalException("No pair in whitelist.") + + if config.get('fee'): + self.fee = config['fee'] + else: + self.fee = self.exchange.get_fee(symbol=self.pairlists.whitelist[0]) + # Get maximum required startup period self.required_startup = max([strat.startup_candle_count for strat in self.strategylist]) # Load one (first) strategy diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index b1e9dec56..fc03223d2 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -401,7 +401,6 @@ def test_backtesting_no_pair_left(default_conf, mocker, caplog, testdatadir) -> Backtesting(default_conf) - def test_backtesting_pairlist_list(default_conf, mocker, caplog, testdatadir, tickers) -> None: mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True)) mocker.patch('freqtrade.exchange.Exchange.get_tickers', tickers) @@ -427,6 +426,12 @@ def test_backtesting_pairlist_list(default_conf, mocker, caplog, testdatadir, ti default_conf['pairlists'] = [{"method": "StaticPairList"}, {"method": "PrecisionFilter"}, ] Backtesting(default_conf) + # Multiple strategies + default_conf['strategy_list'] = ['DefaultStrategy', 'TestStrategyLegacy'] + with pytest.raises(OperationalException, + match='PrecisionFilter not allowed for backtesting multiple strategies.'): + Backtesting(default_conf) + def test_backtest(default_conf, fee, mocker, testdatadir) -> None: default_conf['ask_strategy']['use_sell_signal'] = False From ab0003f56517a51e358e24245f53ea054032d151 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 9 Jun 2020 14:33:57 +0200 Subject: [PATCH 3/3] fix #3463 by explicitly failing if no stoploss is defined --- freqtrade/pairlist/PrecisionFilter.py | 6 +++++- tests/pairlist/test_pairlist.py | 11 +++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/freqtrade/pairlist/PrecisionFilter.py b/freqtrade/pairlist/PrecisionFilter.py index 0331347be..45baf656c 100644 --- a/freqtrade/pairlist/PrecisionFilter.py +++ b/freqtrade/pairlist/PrecisionFilter.py @@ -5,7 +5,7 @@ import logging from typing import Any, Dict from freqtrade.pairlist.IPairList import IPairList - +from freqtrade.exceptions import OperationalException logger = logging.getLogger(__name__) @@ -17,6 +17,10 @@ class PrecisionFilter(IPairList): pairlist_pos: int) -> None: super().__init__(exchange, pairlistmanager, config, pairlistconfig, pairlist_pos) + if 'stoploss' not in self._config: + raise OperationalException( + 'PrecisionFilter can only work with stoploss defined. Please add the ' + 'stoploss key to your configuration (overwrites eventual strategy settings).') self._stoploss = self._config['stoploss'] self._enabled = self._stoploss != 0 diff --git a/tests/pairlist/test_pairlist.py b/tests/pairlist/test_pairlist.py index 421f06911..07f853342 100644 --- a/tests/pairlist/test_pairlist.py +++ b/tests/pairlist/test_pairlist.py @@ -362,6 +362,17 @@ def test_VolumePairList_whitelist_gen(mocker, whitelist_conf, shitcoinmarkets, t assert not log_has(logmsg, caplog) +def test_PrecisionFilter_error(mocker, whitelist_conf, tickers) -> None: + whitelist_conf['pairlists'] = [{"method": "StaticPairList"}, {"method": "PrecisionFilter"}] + del whitelist_conf['stoploss'] + + mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True)) + + with pytest.raises(OperationalException, + match=r"PrecisionFilter can only work with stoploss defined\..*"): + PairListManager(MagicMock, whitelist_conf) + + def test_gen_pair_whitelist_not_supported(mocker, default_conf, tickers) -> None: default_conf['pairlists'] = [{'method': 'VolumePairList', 'number_assets': 10}]