From 07750518c3e50711a0b8965f2535537b07402ba5 Mon Sep 17 00:00:00 2001 From: Sergey Khliustin Date: Mon, 4 Oct 2021 18:49:57 +0300 Subject: [PATCH 1/2] Added min_profit param to PerformanceFilter --- freqtrade/plugins/pairlist/PerformanceFilter.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/freqtrade/plugins/pairlist/PerformanceFilter.py b/freqtrade/plugins/pairlist/PerformanceFilter.py index 301ee57ab..f235816b8 100644 --- a/freqtrade/plugins/pairlist/PerformanceFilter.py +++ b/freqtrade/plugins/pairlist/PerformanceFilter.py @@ -21,6 +21,7 @@ class PerformanceFilter(IPairList): super().__init__(exchange, pairlistmanager, config, pairlistconfig, pairlist_pos) self._minutes = pairlistconfig.get('minutes', 0) + self._min_profit = pairlistconfig.get('min_profit', None) @property def needstickers(self) -> bool: @@ -68,6 +69,8 @@ class PerformanceFilter(IPairList): sorted_df = list_df.merge(performance, on='pair', how='left')\ .fillna(0).sort_values(by=['count', 'pair'], ascending=True)\ .sort_values(by=['profit'], ascending=False) + if self._min_profit is not None: + sorted_df = sorted_df[sorted_df['profit'] >= self._min_profit] pairlist = sorted_df['pair'].tolist() return pairlist From c02a538187340fffe3515396e052c18d4116e467 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 14 Oct 2021 19:33:32 +0200 Subject: [PATCH 2/2] Add documentation and log to PerformanceFilter --- docs/includes/pairlists.md | 9 +++++++-- freqtrade/plugins/pairlist/PerformanceFilter.py | 6 ++++++ tests/plugins/test_pairlist.py | 7 ++++--- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/docs/includes/pairlists.md b/docs/includes/pairlists.md index b612a4ddf..3d10747d3 100644 --- a/docs/includes/pairlists.md +++ b/docs/includes/pairlists.md @@ -194,17 +194,22 @@ Trade count is used as a tie breaker. You can use the `minutes` parameter to only consider performance of the past X minutes (rolling window). Not defining this parameter (or setting it to 0) will use all-time performance. +The optional `min_profit` parameter defines the minimum profit a pair must have to be considered. +Pairs below this level will be filtered out. +Using this parameter without `minutes` is highly discouraged, as it can lead to an empty pairlist without without a way to recover. + ```json "pairlists": [ // ... { "method": "PerformanceFilter", - "minutes": 1440 // rolling 24h + "minutes": 1440, // rolling 24h + "min_profit": 0.01 } ], ``` -!!! Note +!!! Warning "Backtesting" `PerformanceFilter` does not support backtesting mode. #### PrecisionFilter diff --git a/freqtrade/plugins/pairlist/PerformanceFilter.py b/freqtrade/plugins/pairlist/PerformanceFilter.py index f235816b8..671b6362b 100644 --- a/freqtrade/plugins/pairlist/PerformanceFilter.py +++ b/freqtrade/plugins/pairlist/PerformanceFilter.py @@ -70,7 +70,13 @@ class PerformanceFilter(IPairList): .fillna(0).sort_values(by=['count', 'pair'], ascending=True)\ .sort_values(by=['profit'], ascending=False) if self._min_profit is not None: + removed = sorted_df[sorted_df['profit'] < self._min_profit] + for _, row in removed.iterrows(): + self.log_once( + f"Removing pair {row['pair']} since {row['profit']} is " + f"below {self._min_profit}", logger.info) sorted_df = sorted_df[sorted_df['profit'] >= self._min_profit] + pairlist = sorted_df['pair'].tolist() return pairlist diff --git a/tests/plugins/test_pairlist.py b/tests/plugins/test_pairlist.py index cf918e2a0..c6246dccb 100644 --- a/tests/plugins/test_pairlist.py +++ b/tests/plugins/test_pairlist.py @@ -665,11 +665,11 @@ def test_PerformanceFilter_error(mocker, whitelist_conf, caplog) -> None: @pytest.mark.usefixtures("init_persistence") -def test_PerformanceFilter_lookback(mocker, whitelist_conf, fee) -> None: +def test_PerformanceFilter_lookback(mocker, whitelist_conf, fee, caplog) -> None: whitelist_conf['exchange']['pair_whitelist'].append('XRP/BTC') whitelist_conf['pairlists'] = [ {"method": "StaticPairList"}, - {"method": "PerformanceFilter", "minutes": 60} + {"method": "PerformanceFilter", "minutes": 60, "min_profit": 0.01} ] mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True)) exchange = get_patched_exchange(mocker, whitelist_conf) @@ -681,7 +681,8 @@ def test_PerformanceFilter_lookback(mocker, whitelist_conf, fee) -> None: with time_machine.travel("2021-09-01 05:00:00 +00:00") as t: create_mock_trades(fee) pm.refresh_pairlist() - assert pm.whitelist == ['XRP/BTC', 'ETH/BTC', 'TKN/BTC'] + assert pm.whitelist == ['XRP/BTC'] + assert log_has_re(r'Removing pair .* since .* is below .*', caplog) # Move to "outside" of lookback window, so original sorting is restored. t.move_to("2021-09-01 07:00:00 +00:00")