parent
89cfcc8ba6
commit
2869d5368d
@ -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.
|
||||||
|
@ -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."
|
||||||
|
@ -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 (
|
||||||
|
@ -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:
|
||||||
|
@ -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))
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user