Improve exit signal sequence
This commit is contained in:
parent
ce3bfd59f5
commit
3692fcd3d5
@ -18,3 +18,6 @@ class ExitCheckTuple:
|
|||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return self.exit_type == other.exit_type and self.exit_reason == other.exit_reason
|
return self.exit_type == other.exit_type and self.exit_reason == other.exit_reason
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"ExitCheckTuple({self.exit_type}, {self.exit_reason})"
|
||||||
|
@ -942,15 +942,22 @@ class IStrategy(ABC, HyperStrategyMixin):
|
|||||||
|
|
||||||
# Sequence:
|
# Sequence:
|
||||||
# Exit-signal
|
# Exit-signal
|
||||||
# ROI (if not stoploss)
|
|
||||||
# Stoploss
|
# Stoploss
|
||||||
if roi_reached and stoplossflag.exit_type != ExitType.STOP_LOSS:
|
# ROI
|
||||||
|
# Trailing stoploss
|
||||||
|
|
||||||
|
if stoplossflag.exit_type == ExitType.STOP_LOSS:
|
||||||
|
|
||||||
|
logger.debug(f"{trade.pair} - Stoploss hit. exit_type={stoplossflag.exit_type}")
|
||||||
|
exits.append(stoplossflag)
|
||||||
|
|
||||||
|
if roi_reached:
|
||||||
logger.debug(f"{trade.pair} - Required profit reached. exit_type=ExitType.ROI")
|
logger.debug(f"{trade.pair} - Required profit reached. exit_type=ExitType.ROI")
|
||||||
exits.append(ExitCheckTuple(exit_type=ExitType.ROI))
|
exits.append(ExitCheckTuple(exit_type=ExitType.ROI))
|
||||||
|
|
||||||
if stoplossflag.exit_flag:
|
if stoplossflag.exit_type == ExitType.TRAILING_STOP_LOSS:
|
||||||
|
|
||||||
logger.debug(f"{trade.pair} - Stoploss hit. exit_type={stoplossflag.exit_type}")
|
logger.debug(f"{trade.pair} - Trailing stoploss hit.")
|
||||||
exits.append(stoplossflag)
|
exits.append(stoplossflag)
|
||||||
|
|
||||||
return exits
|
return exits
|
||||||
|
@ -525,7 +525,7 @@ def test_custom_exit(default_conf, fee, caplog) -> None:
|
|||||||
assert log_has_re('Custom exit reason returned from custom_exit is too long.*', caplog)
|
assert log_has_re('Custom exit reason returned from custom_exit is too long.*', caplog)
|
||||||
|
|
||||||
|
|
||||||
def test_should_sell(default_conf, fee, caplog) -> None:
|
def test_should_sell(default_conf, fee) -> None:
|
||||||
|
|
||||||
strategy = StrategyResolver.load_strategy(default_conf)
|
strategy = StrategyResolver.load_strategy(default_conf)
|
||||||
trade = Trade(
|
trade = Trade(
|
||||||
@ -561,22 +561,24 @@ def test_should_sell(default_conf, fee, caplog) -> None:
|
|||||||
low=None, high=None)
|
low=None, high=None)
|
||||||
assert len(res) == 2
|
assert len(res) == 2
|
||||||
assert res == [
|
assert res == [
|
||||||
ExitCheckTuple(exit_type=ExitType.ROI),
|
|
||||||
ExitCheckTuple(exit_type=ExitType.STOP_LOSS),
|
ExitCheckTuple(exit_type=ExitType.STOP_LOSS),
|
||||||
|
ExitCheckTuple(exit_type=ExitType.ROI),
|
||||||
]
|
]
|
||||||
|
|
||||||
strategy.custom_exit = MagicMock(return_value='hello world')
|
strategy.custom_exit = MagicMock(return_value='hello world')
|
||||||
|
# custom-exit and exit-signal is first
|
||||||
res = strategy.should_exit(trade, 1, now,
|
res = strategy.should_exit(trade, 1, now,
|
||||||
enter=False, exit_=False,
|
enter=False, exit_=False,
|
||||||
low=None, high=None)
|
low=None, high=None)
|
||||||
assert len(res) == 3
|
assert len(res) == 3
|
||||||
assert res == [
|
assert res == [
|
||||||
ExitCheckTuple(exit_type=ExitType.CUSTOM_EXIT, exit_reason='hello world'),
|
ExitCheckTuple(exit_type=ExitType.CUSTOM_EXIT, exit_reason='hello world'),
|
||||||
ExitCheckTuple(exit_type=ExitType.ROI),
|
|
||||||
ExitCheckTuple(exit_type=ExitType.STOP_LOSS),
|
ExitCheckTuple(exit_type=ExitType.STOP_LOSS),
|
||||||
|
ExitCheckTuple(exit_type=ExitType.ROI),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
strategy.stop_loss_reached = MagicMock(
|
||||||
|
return_value=ExitCheckTuple(exit_type=ExitType.TRAILING_STOP_LOSS))
|
||||||
# Regular exit signal
|
# Regular exit signal
|
||||||
res = strategy.should_exit(trade, 1, now,
|
res = strategy.should_exit(trade, 1, now,
|
||||||
enter=False, exit_=True,
|
enter=False, exit_=True,
|
||||||
@ -585,7 +587,7 @@ def test_should_sell(default_conf, fee, caplog) -> None:
|
|||||||
assert res == [
|
assert res == [
|
||||||
ExitCheckTuple(exit_type=ExitType.EXIT_SIGNAL),
|
ExitCheckTuple(exit_type=ExitType.EXIT_SIGNAL),
|
||||||
ExitCheckTuple(exit_type=ExitType.ROI),
|
ExitCheckTuple(exit_type=ExitType.ROI),
|
||||||
ExitCheckTuple(exit_type=ExitType.STOP_LOSS),
|
ExitCheckTuple(exit_type=ExitType.TRAILING_STOP_LOSS),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Regular exit signal, no ROI
|
# Regular exit signal, no ROI
|
||||||
@ -596,9 +598,10 @@ def test_should_sell(default_conf, fee, caplog) -> None:
|
|||||||
assert len(res) == 2
|
assert len(res) == 2
|
||||||
assert res == [
|
assert res == [
|
||||||
ExitCheckTuple(exit_type=ExitType.EXIT_SIGNAL),
|
ExitCheckTuple(exit_type=ExitType.EXIT_SIGNAL),
|
||||||
ExitCheckTuple(exit_type=ExitType.STOP_LOSS),
|
ExitCheckTuple(exit_type=ExitType.TRAILING_STOP_LOSS),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('side', TRADE_SIDES)
|
@pytest.mark.parametrize('side', TRADE_SIDES)
|
||||||
def test_leverage_callback(default_conf, side) -> None:
|
def test_leverage_callback(default_conf, side) -> None:
|
||||||
default_conf['strategy'] = 'StrategyTestV2'
|
default_conf['strategy'] = 'StrategyTestV2'
|
||||||
|
Loading…
Reference in New Issue
Block a user