Allow edge to use dynamic pairlists

closes #4298
This commit is contained in:
Matthias 2021-03-30 20:20:24 +02:00
parent 89cfcc8ba6
commit 2869d5368d
7 changed files with 11 additions and 33 deletions

View File

@ -1,9 +1,9 @@
# Edge positioning # 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 !!! 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 !!! 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. `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. 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!" !!! 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. 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.

View File

@ -149,11 +149,6 @@ def _validate_edge(conf: Dict[str, Any]) -> None:
if not conf.get('edge', {}).get('enabled'): if not conf.get('edge', {}).get('enabled'):
return 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): if not conf.get('ask_strategy', {}).get('use_sell_signal', True):
raise OperationalException( raise OperationalException(
"Edge requires `use_sell_signal` to be True, otherwise no sells will happen." "Edge requires `use_sell_signal` to be True, otherwise no sells will happen."

View File

@ -84,9 +84,8 @@ class Edge:
self.fee = self.exchange.get_fee(symbol=expand_pairlist( self.fee = self.exchange.get_fee(symbol=expand_pairlist(
self.config['exchange']['pair_whitelist'], list(self.exchange.markets))[0]) self.config['exchange']['pair_whitelist'], list(self.exchange.markets))[0])
def calculate(self) -> bool: def calculate(self, pairs: List[str]) -> bool:
pairs = expand_pairlist(self.config['exchange']['pair_whitelist'],
list(self.exchange.markets))
heartbeat = self.edge_config.get('process_throttle_secs') heartbeat = self.edge_config.get('process_throttle_secs')
if (self._last_updated > 0) and ( if (self._last_updated > 0) and (

View File

@ -225,7 +225,7 @@ class FreqtradeBot(LoggingMixin):
# Calculating Edge positioning # Calculating Edge positioning
if self.edge: if self.edge:
self.edge.calculate() self.edge.calculate(_whitelist)
_whitelist = self.edge.adjust(_whitelist) _whitelist = self.edge.adjust(_whitelist)
if trades: if trades:

View File

@ -44,7 +44,7 @@ class EdgeCli:
'timerange') is None else str(self.config.get('timerange'))) 'timerange') is None else str(self.config.get('timerange')))
def start(self) -> None: def start(self) -> None:
result = self.edge.calculate() result = self.edge.calculate(self.config['exchange']['pair_whitelist'])
if result: if result:
print('') # blank line for readability print('') # blank line for readability
print(generate_edge_table(self.edge._cached_pairs)) print(generate_edge_table(self.edge._cached_pairs))

View File

@ -266,7 +266,7 @@ def test_edge_heartbeat_calculate(mocker, edge_conf):
# should not recalculate if heartbeat not reached # should not recalculate if heartbeat not reached
edge._last_updated = arrow.utcnow().int_timestamp - heartbeat + 1 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', 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) mocker.patch('freqtrade.edge.edge_positioning.load_data', mocked_load_data)
edge = Edge(edge_conf, freqtrade.exchange, freqtrade.strategy) 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 len(edge._cached_pairs) == 2
assert edge._last_updated <= arrow.utcnow().int_timestamp + 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={})) mocker.patch('freqtrade.edge.edge_positioning.load_data', MagicMock(return_value={}))
edge = Edge(edge_conf, freqtrade.exchange, freqtrade.strategy) 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 len(edge._cached_pairs) == 0
assert log_has("No data found. Edge is stopped ...", caplog) assert log_has("No data found. Edge is stopped ...", caplog)
assert edge._last_updated == 0 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=[])) mocker.patch('freqtrade.edge.Edge._find_trades_for_stoploss_range', MagicMock(return_value=[]))
edge = Edge(edge_conf, freqtrade.exchange, freqtrade.strategy) 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 len(edge._cached_pairs) == 0
assert log_has("No trades found.", caplog) assert log_has("No trades found.", caplog)

View File

@ -860,22 +860,6 @@ def test_validate_tsl(default_conf):
validate_config_consistency(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): def test_validate_edge2(edge_conf):
edge_conf.update({"ask_strategy": { edge_conf.update({"ask_strategy": {
"use_sell_signal": True, "use_sell_signal": True,