Update custom_sell to custom_exit

This commit is contained in:
Matthias
2022-03-12 11:15:27 +01:00
parent fe62a71f4c
commit b044dd2c45
6 changed files with 74 additions and 22 deletions

View File

@@ -222,21 +222,25 @@ class StrategyResolver(IResolver):
if strategy:
if strategy.config.get('trading_mode', TradingMode.SPOT) != TradingMode.SPOT:
# Require new method
if check_override(strategy, IStrategy, 'populate_entry_trend'):
if not check_override(strategy, IStrategy, 'populate_entry_trend'):
raise OperationalException("`populate_entry_trend` must be implemented.")
if check_override(strategy, IStrategy, 'populate_exit_trend'):
if not check_override(strategy, IStrategy, 'populate_exit_trend'):
raise OperationalException("`populate_exit_trend` must be implemented.")
if check_override(strategy, IStrategy, 'custom_sell'):
raise OperationalException(
"Please migrate your implementation of `custom_sell` to `custom_exit`.")
else:
# TODO: Implementing buy_trend and sell_trend should show a deprecation warning
# TODO: Implementing one of the following methods should show a deprecation warning
# buy_trend and sell_trend, custom_sell
if (
check_override(strategy, IStrategy, 'populate_buy_trend')
and check_override(strategy, IStrategy, 'populate_entry_trend')
not check_override(strategy, IStrategy, 'populate_buy_trend')
and not check_override(strategy, IStrategy, 'populate_entry_trend')
):
raise OperationalException(
"`populate_entry_trend` or `populate_buy_trend` must be implemented.")
if (
check_override(strategy, IStrategy, 'populate_sell_trend')
and check_override(strategy, IStrategy, 'populate_exit_trend')
not check_override(strategy, IStrategy, 'populate_sell_trend')
and not check_override(strategy, IStrategy, 'populate_exit_trend')
):
raise OperationalException(
"`populate_exit_trend` or `populate_sell_trend` must be implemented.")
@@ -262,5 +266,6 @@ class StrategyResolver(IResolver):
def check_override(object, parentclass, attribute):
"""
Checks if a object overrides the parent class attribute.
:returns: True if the object is overridden.
"""
return getattr(type(object), attribute) == getattr(parentclass, attribute)
return getattr(type(object), attribute) != getattr(parentclass, attribute)

View File

@@ -29,7 +29,7 @@ from freqtrade.wallets import Wallets
logger = logging.getLogger(__name__)
CUSTOM_SELL_MAX_LENGTH = 64
CUSTOM_EXIT_MAX_LENGTH = 64
class SellCheckTuple:
@@ -380,6 +380,7 @@ class IStrategy(ABC, HyperStrategyMixin):
def custom_sell(self, pair: str, trade: Trade, current_time: datetime, current_rate: float,
current_profit: float, **kwargs) -> Optional[Union[str, bool]]:
"""
DEPRECATED - please use custom_exit instead.
Custom exit signal logic indicating that specified position should be sold. Returning a
string or True from this method is equal to setting exit signal on a candle at specified
time. This method is not called when exit signal is set.
@@ -401,6 +402,30 @@ class IStrategy(ABC, HyperStrategyMixin):
"""
return None
def custom_exit(self, pair: str, trade: Trade, current_time: datetime, current_rate: float,
current_profit: float, **kwargs) -> Optional[Union[str, bool]]:
"""
Custom exit signal logic indicating that specified position should be sold. Returning a
string or True from this method is equal to setting exit signal on a candle at specified
time. This method is not called when exit signal is set.
This method should be overridden to create exit signals that depend on trade parameters. For
example you could implement an exit relative to the candle when the trade was opened,
or a custom 1:2 risk-reward ROI.
Custom exit reason max length is 64. Exceeding characters will be removed.
:param pair: Pair that's currently analyzed
:param trade: trade object.
:param current_time: datetime object, containing the current datetime
:param current_rate: Rate, calculated based on pricing settings in ask_strategy.
:param current_profit: Current profit (as ratio), calculated based on current_rate.
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
:return: To execute exit, return a string with custom sell reason or True. Otherwise return
None or False.
"""
return self.custom_sell(pair, trade, current_time, current_rate, current_profit, **kwargs)
def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float,
proposed_stake: float, min_stake: float, max_stake: float,
entry_tag: Optional[str], side: str, **kwargs) -> float:
@@ -866,17 +891,17 @@ class IStrategy(ABC, HyperStrategyMixin):
sell_signal = SellType.SELL_SIGNAL
else:
trade_type = "exit_short" if trade.is_short else "sell"
custom_reason = strategy_safe_wrapper(self.custom_sell, default_retval=False)(
custom_reason = strategy_safe_wrapper(self.custom_exit, default_retval=False)(
pair=trade.pair, trade=trade, current_time=current_time,
current_rate=current_rate, current_profit=current_profit)
if custom_reason:
sell_signal = SellType.CUSTOM_SELL
if isinstance(custom_reason, str):
if len(custom_reason) > CUSTOM_SELL_MAX_LENGTH:
if len(custom_reason) > CUSTOM_EXIT_MAX_LENGTH:
logger.warning(f'Custom {trade_type} reason returned from '
f'custom_{trade_type} is too long and was trimmed'
f'to {CUSTOM_SELL_MAX_LENGTH} characters.')
custom_reason = custom_reason[:CUSTOM_SELL_MAX_LENGTH]
f'custom_exit is too long and was trimmed'
f'to {CUSTOM_EXIT_MAX_LENGTH} characters.')
custom_reason = custom_reason[:CUSTOM_EXIT_MAX_LENGTH]
else:
custom_reason = None
if sell_signal in (SellType.CUSTOM_SELL, SellType.SELL_SIGNAL):

View File

@@ -92,7 +92,7 @@ def custom_stoploss(self, pair: str, trade: 'Trade', current_time: 'datetime',
"""
return self.stoploss
def custom_sell(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float,
def custom_exit(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float,
current_profit: float, **kwargs) -> 'Optional[Union[str, bool]]':
"""
Custom sell signal logic indicating that specified position should be sold. Returning a