Fix extremely optimistic results when using a combination of custom_stoploss and trailing_stop.

This commit is contained in:
Rokas Kupstys 2021-06-29 16:17:52 +03:00
parent eb5cee4934
commit bc0742ae67
3 changed files with 24 additions and 4 deletions

View File

@ -228,16 +228,18 @@ class Backtesting:
# Special case: trailing triggers within same candle as trade opened. Assume most # Special case: trailing triggers within same candle as trade opened. Assume most
# pessimistic price movement, which is moving just enough to arm stoploss and # pessimistic price movement, which is moving just enough to arm stoploss and
# immediately going down to stop price. # immediately going down to stop price.
if (sell.sell_type == SellType.TRAILING_STOP_LOSS and trade_dur == 0 if sell.sell_type == SellType.TRAILING_STOP_LOSS and trade_dur == 0:
and self.strategy.trailing_stop_positive): if not self.strategy.use_custom_stoploss and self.strategy.trailing_stop and \
if self.strategy.trailing_only_offset_is_reached: self.strategy.trailing_only_offset_is_reached and \
self.strategy.trailing_stop_positive_offset is not None and \
self.strategy.trailing_stop_positive:
# Worst case: price reaches stop_positive_offset and dives down. # Worst case: price reaches stop_positive_offset and dives down.
stop_rate = (sell_row[OPEN_IDX] * stop_rate = (sell_row[OPEN_IDX] *
(1 + abs(self.strategy.trailing_stop_positive_offset) - (1 + abs(self.strategy.trailing_stop_positive_offset) -
abs(self.strategy.trailing_stop_positive))) abs(self.strategy.trailing_stop_positive)))
else: else:
# Worst case: price ticks tiny bit above open and dives down. # Worst case: price ticks tiny bit above open and dives down.
stop_rate = sell_row[OPEN_IDX] * (1 - abs(self.strategy.trailing_stop_positive)) stop_rate = sell_row[OPEN_IDX] * (1 - abs(trade.stop_loss_pct))
assert stop_rate < sell_row[HIGH_IDX] assert stop_rate < sell_row[HIGH_IDX]
return stop_rate return stop_rate

View File

@ -34,6 +34,7 @@ class BTContainer(NamedTuple):
trailing_stop_positive: Optional[float] = None trailing_stop_positive: Optional[float] = None
trailing_stop_positive_offset: float = 0.0 trailing_stop_positive_offset: float = 0.0
use_sell_signal: bool = False use_sell_signal: bool = False
use_custom_stoploss: bool = False
def _get_frame_time_from_offset(offset): def _get_frame_time_from_offset(offset):

View File

@ -501,6 +501,21 @@ tc31 = BTContainer(data=[
trades=[BTrade(sell_reason=SellType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)] trades=[BTrade(sell_reason=SellType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)]
) )
# Test 32: trailing_stop should be triggered immediately on trade open candle.
# stop-loss: 1%, ROI: 10% (should not apply)
tc32 = BTContainer(data=[
# D O H L C V B S
[0, 5000, 5050, 4950, 5000, 6172, 1, 0],
[1, 5000, 5500, 5000, 4900, 6172, 0, 0], # enter trade (signal on last candle) and stop
[2, 4900, 5250, 4500, 5100, 6172, 0, 0],
[3, 5100, 5100, 4650, 4750, 6172, 0, 0],
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
stop_loss=-0.01, roi={"0": 0.10}, profit_perc=-0.01, trailing_stop=True,
trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.02,
trailing_stop_positive=0.01, use_custom_stoploss=True,
trades=[BTrade(sell_reason=SellType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)]
)
TESTS = [ TESTS = [
tc0, tc0,
tc1, tc1,
@ -534,6 +549,7 @@ TESTS = [
tc29, tc29,
tc30, tc30,
tc31, tc31,
tc32,
] ]
@ -561,6 +577,7 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None:
backtesting._set_strategy(backtesting.strategylist[0]) backtesting._set_strategy(backtesting.strategylist[0])
backtesting.strategy.advise_buy = lambda a, m: frame backtesting.strategy.advise_buy = lambda a, m: frame
backtesting.strategy.advise_sell = lambda a, m: frame backtesting.strategy.advise_sell = lambda a, m: frame
backtesting.strategy.use_custom_stoploss = data.use_custom_stoploss
caplog.set_level(logging.DEBUG) caplog.set_level(logging.DEBUG)
pair = "UNITTEST/BTC" pair = "UNITTEST/BTC"