From 2869d5368de5868b7dfb0c72d402449cf72c2997 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 30 Mar 2021 20:20:24 +0200 Subject: [PATCH] Allow edge to use dynamic pairlists closes #4298 --- docs/edge.md | 6 +++--- freqtrade/configuration/config_validation.py | 5 ----- freqtrade/edge/edge_positioning.py | 5 ++--- freqtrade/freqtradebot.py | 2 +- freqtrade/optimize/edge_cli.py | 2 +- tests/edge/test_edge.py | 8 ++++---- tests/test_configuration.py | 16 ---------------- 7 files changed, 11 insertions(+), 33 deletions(-) diff --git a/docs/edge.md b/docs/edge.md index 5565ca2f9..0aa76cd12 100644 --- a/docs/edge.md +++ b/docs/edge.md @@ -1,9 +1,9 @@ # Edge positioning -The `Edge Positioning` module uses probability to calculate your win rate and risk reward ratio. It will use these statistics to control your strategy trade entry points, position size and, stoploss. +The `Edge Positioning` module uses probability to calculate your win rate and risk reward ratio. It will use these statistics to control your strategy trade entry points, position size and, stoploss. !!! Warning - `Edge positioning` is not compatible with dynamic (volume-based) whitelist. + WHen using `Edge positioning` with a dynamic whitelist (VolumePairList), make sure to also use `AgeFilter` and set it to at least `calculate_since_number_of_days` to avoid problems with missing data. !!! Note `Edge Positioning` only considers *its own* buy/sell/stoploss signals. It ignores the stoploss, trailing stoploss, and ROI settings in the strategy configuration file. @@ -14,7 +14,7 @@ The `Edge Positioning` module uses probability to calculate your win rate and ri Trading strategies are not perfect. They are frameworks that are susceptible to the market and its indicators. Because the market is not at all predictable, sometimes a strategy will win and sometimes the same strategy will lose. -To obtain an edge in the market, a strategy has to make more money than it loses. Making money in trading is not only about *how often* the strategy makes or loses money. +To obtain an edge in the market, a strategy has to make more money than it loses. Making money in trading is not only about *how often* the strategy makes or loses money. !!! tip "It doesn't matter how often, but how much!" A bad strategy might make 1 penny in *ten* transactions but lose 1 dollar in *one* transaction. If one only checks the number of winning trades, it would be misleading to think that the strategy is actually making a profit. diff --git a/freqtrade/configuration/config_validation.py b/freqtrade/configuration/config_validation.py index c7e49f33d..31e38d572 100644 --- a/freqtrade/configuration/config_validation.py +++ b/freqtrade/configuration/config_validation.py @@ -149,11 +149,6 @@ def _validate_edge(conf: Dict[str, Any]) -> None: if not conf.get('edge', {}).get('enabled'): return - if conf.get('pairlist', {}).get('method') == 'VolumePairList': - raise OperationalException( - "Edge and VolumePairList are incompatible, " - "Edge will override whatever pairs VolumePairlist selects." - ) if not conf.get('ask_strategy', {}).get('use_sell_signal', True): raise OperationalException( "Edge requires `use_sell_signal` to be True, otherwise no sells will happen." diff --git a/freqtrade/edge/edge_positioning.py b/freqtrade/edge/edge_positioning.py index ff86e522e..d1f76c21f 100644 --- a/freqtrade/edge/edge_positioning.py +++ b/freqtrade/edge/edge_positioning.py @@ -84,9 +84,8 @@ class Edge: self.fee = self.exchange.get_fee(symbol=expand_pairlist( self.config['exchange']['pair_whitelist'], list(self.exchange.markets))[0]) - def calculate(self) -> bool: - pairs = expand_pairlist(self.config['exchange']['pair_whitelist'], - list(self.exchange.markets)) + def calculate(self, pairs: List[str]) -> bool: + heartbeat = self.edge_config.get('process_throttle_secs') if (self._last_updated > 0) and ( diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 73f4c91be..dd6966848 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -225,7 +225,7 @@ class FreqtradeBot(LoggingMixin): # Calculating Edge positioning if self.edge: - self.edge.calculate() + self.edge.calculate(_whitelist) _whitelist = self.edge.adjust(_whitelist) if trades: diff --git a/freqtrade/optimize/edge_cli.py b/freqtrade/optimize/edge_cli.py index a5f505bee..aab7def05 100644 --- a/freqtrade/optimize/edge_cli.py +++ b/freqtrade/optimize/edge_cli.py @@ -44,7 +44,7 @@ class EdgeCli: 'timerange') is None else str(self.config.get('timerange'))) def start(self) -> None: - result = self.edge.calculate() + result = self.edge.calculate(self.config['exchange']['pair_whitelist']) if result: print('') # blank line for readability print(generate_edge_table(self.edge._cached_pairs)) diff --git a/tests/edge/test_edge.py b/tests/edge/test_edge.py index c30bce6a4..5142dd985 100644 --- a/tests/edge/test_edge.py +++ b/tests/edge/test_edge.py @@ -266,7 +266,7 @@ def test_edge_heartbeat_calculate(mocker, edge_conf): # should not recalculate if heartbeat not reached edge._last_updated = arrow.utcnow().int_timestamp - heartbeat + 1 - assert edge.calculate() is False + assert edge.calculate(edge_conf['exchange']['pair_whitelist']) is False def mocked_load_data(datadir, pairs=[], timeframe='0m', @@ -310,7 +310,7 @@ def test_edge_process_downloaded_data(mocker, edge_conf): mocker.patch('freqtrade.edge.edge_positioning.load_data', mocked_load_data) edge = Edge(edge_conf, freqtrade.exchange, freqtrade.strategy) - assert edge.calculate() + assert edge.calculate(edge_conf['exchange']['pair_whitelist']) assert len(edge._cached_pairs) == 2 assert edge._last_updated <= arrow.utcnow().int_timestamp + 2 @@ -322,7 +322,7 @@ def test_edge_process_no_data(mocker, edge_conf, caplog): mocker.patch('freqtrade.edge.edge_positioning.load_data', MagicMock(return_value={})) edge = Edge(edge_conf, freqtrade.exchange, freqtrade.strategy) - assert not edge.calculate() + assert not edge.calculate(edge_conf['exchange']['pair_whitelist']) assert len(edge._cached_pairs) == 0 assert log_has("No data found. Edge is stopped ...", caplog) assert edge._last_updated == 0 @@ -337,7 +337,7 @@ def test_edge_process_no_trades(mocker, edge_conf, caplog): mocker.patch('freqtrade.edge.Edge._find_trades_for_stoploss_range', MagicMock(return_value=[])) edge = Edge(edge_conf, freqtrade.exchange, freqtrade.strategy) - assert not edge.calculate() + assert not edge.calculate(edge_conf['exchange']['pair_whitelist']) assert len(edge._cached_pairs) == 0 assert log_has("No trades found.", caplog) diff --git a/tests/test_configuration.py b/tests/test_configuration.py index a0824e65c..15fbab7f8 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -860,22 +860,6 @@ def test_validate_tsl(default_conf): validate_config_consistency(default_conf) -def test_validate_edge(edge_conf): - edge_conf.update({"pairlist": { - "method": "VolumePairList", - }}) - - with pytest.raises(OperationalException, - match="Edge and VolumePairList are incompatible, " - "Edge will override whatever pairs VolumePairlist selects."): - validate_config_consistency(edge_conf) - - edge_conf.update({"pairlist": { - "method": "StaticPairList", - }}) - validate_config_consistency(edge_conf) - - def test_validate_edge2(edge_conf): edge_conf.update({"ask_strategy": { "use_sell_signal": True,