enter_tag can be used to determine roi

This commit is contained in:
Sam Germain 2022-04-03 02:41:29 -06:00
parent 9029833c8c
commit 0310d1cdf2
5 changed files with 57 additions and 17 deletions

View File

@ -138,7 +138,7 @@ CONF_SCHEMA = {
'minimal_roi': { 'minimal_roi': {
'type': 'object', 'type': 'object',
'patternProperties': { 'patternProperties': {
'^[0-9.]+$': {'type': 'number'} '^[0-9a-zA-Z.]+$': {'type': ['number', 'dict']}
}, },
'minProperties': 1 'minProperties': 1
}, },

View File

@ -932,7 +932,16 @@ class FreqtradeBot(LoggingMixin):
logger.debug('checking exit') logger.debug('checking exit')
exit_rate = self.exchange.get_rate( exit_rate = self.exchange.get_rate(
trade.pair, side='exit', is_short=trade.is_short, refresh=True) trade.pair, side='exit', is_short=trade.is_short, refresh=True)
if self._check_and_execute_exit(trade, exit_rate, enter, exit_, exit_tag):
enter_tag = # TODO
if self._check_and_execute_exit(
trade=trade,
exit_rate=exit_rate,
enter=enter,
exit_=exit_,
enter_tag=enter_tag,
exit_tag=exit_tag,
):
return True return True
logger.debug(f'Found no {exit_signal_type} signal for %s.', trade) logger.debug(f'Found no {exit_signal_type} signal for %s.', trade)
@ -1089,8 +1098,15 @@ class FreqtradeBot(LoggingMixin):
logger.warning(f"Could not create trailing stoploss order " logger.warning(f"Could not create trailing stoploss order "
f"for pair {trade.pair}.") f"for pair {trade.pair}.")
def _check_and_execute_exit(self, trade: Trade, exit_rate: float, def _check_and_execute_exit(
enter: bool, exit_: bool, exit_tag: Optional[str]) -> bool: self,
trade: Trade,
exit_rate: float,
enter: bool,
exit_: bool,
enter_tag: Optional[str],
exit_tag: Optional[str],
) -> bool:
""" """
Check and execute trade exit Check and execute trade exit
""" """
@ -1100,7 +1116,8 @@ class FreqtradeBot(LoggingMixin):
datetime.now(timezone.utc), datetime.now(timezone.utc),
enter=enter, enter=enter,
exit_=exit_, exit_=exit_,
force_stoploss=self.edge.stoploss(trade.pair) if self.edge else 0 force_stoploss=self.edge.stoploss(trade.pair) if self.edge else 0,
enter_tag=enter_tag,
) )
if should_exit.exit_flag: if should_exit.exit_flag:

View File

@ -143,8 +143,14 @@ class StrategyResolver(IResolver):
# Sort and apply type conversions # Sort and apply type conversions
if hasattr(strategy, 'minimal_roi'): if hasattr(strategy, 'minimal_roi'):
strategy.minimal_roi = dict(sorted( strategy.minimal_roi = dict(sorted(
{int(key): value for (key, value) in strategy.minimal_roi.items()}.items(), {
key=lambda t: t[0])) {int(k): v for (k, v) in value.items()}
if type(value is dict)
else int(key): value
for (key, value) in strategy.minimal_roi.items()
}.items(),
key=lambda t: t[0]
))
if hasattr(strategy, 'stoploss'): if hasattr(strategy, 'stoploss'):
strategy.stoploss = float(strategy.stoploss) strategy.stoploss = float(strategy.stoploss)
return strategy return strategy

View File

@ -160,7 +160,7 @@ class ShowConfig(BaseModel):
available_capital: Optional[float] available_capital: Optional[float]
stake_currency_decimals: int stake_currency_decimals: int
max_open_trades: int max_open_trades: int
minimal_roi: Dict[str, Any] minimal_roi: Dict[str, Union[Dict[str, float], float]]
stoploss: Optional[float] stoploss: Optional[float]
trailing_stop: Optional[bool] trailing_stop: Optional[bool]
trailing_stop_positive: Optional[float] trailing_stop_positive: Optional[float]

View File

@ -843,7 +843,7 @@ class IStrategy(ABC, HyperStrategyMixin):
def should_exit(self, trade: Trade, rate: float, current_time: datetime, *, def should_exit(self, trade: Trade, rate: float, current_time: datetime, *,
enter: bool, exit_: bool, enter: bool, exit_: bool,
low: float = None, high: float = None, low: float = None, high: float = None,
force_stoploss: float = 0) -> ExitCheckTuple: force_stoploss: float = 0, enter_tag: Optional[str] = None) -> ExitCheckTuple:
""" """
This function evaluates if one of the conditions required to trigger an exit order This function evaluates if one of the conditions required to trigger an exit order
has been reached, which can either be a stop-loss, ROI or exit-signal. has been reached, which can either be a stop-loss, ROI or exit-signal.
@ -868,9 +868,15 @@ class IStrategy(ABC, HyperStrategyMixin):
current_profit = trade.calc_profit_ratio(current_rate) current_profit = trade.calc_profit_ratio(current_rate)
# if enter signal and ignore_roi is set, we don't need to evaluate min_roi. # if enter signal and ignore_roi is set, we don't need to evaluate min_roi.
roi_reached = (not (enter and self.ignore_roi_if_entry_signal) roi_reached = (
and self.min_roi_reached(trade=trade, current_profit=current_profit, not (enter and self.ignore_roi_if_entry_signal) and
current_time=current_time)) self.min_roi_reached(
trade=trade,
current_profit=current_profit,
current_time=current_time,
enter_tag=enter_tag,
)
)
exit_signal = ExitType.NONE exit_signal = ExitType.NONE
custom_reason = '' custom_reason = ''
@ -1007,20 +1013,31 @@ class IStrategy(ABC, HyperStrategyMixin):
return ExitCheckTuple(exit_type=ExitType.NONE) return ExitCheckTuple(exit_type=ExitType.NONE)
def min_roi_reached_entry(self, trade_dur: int) -> Tuple[Optional[int], Optional[float]]: def min_roi_reached_entry(
self,
trade_dur: int,
enter_tag: Optional[str] = None,
) -> Tuple[Optional[int], Optional[float]]:
""" """
Based on trade duration defines the ROI entry that may have been reached. Based on trade duration defines the ROI entry that may have been reached.
:param trade_dur: trade duration in minutes :param trade_dur: trade duration in minutes
:return: minimal ROI entry value or None if none proper ROI entry was found. :return: minimal ROI entry value or None if none proper ROI entry was found.
""" """
minimal_roi = self.minimal_roi[enter_tag] if enter_tag else self.minimal_roi
# Get highest entry in ROI dict where key <= trade-duration # Get highest entry in ROI dict where key <= trade-duration
roi_list = list(filter(lambda x: x <= trade_dur, self.minimal_roi.keys())) roi_list = list(filter(lambda x: x <= trade_dur, minimal_roi.keys()))
if not roi_list: if not roi_list:
return None, None return None, None
roi_entry = max(roi_list) roi_entry = max(roi_list)
return roi_entry, self.minimal_roi[roi_entry] return roi_entry, minimal_roi[roi_entry]
def min_roi_reached(self, trade: Trade, current_profit: float, current_time: datetime) -> bool: def min_roi_reached(
self,
trade: Trade,
current_profit: float,
current_time: datetime,
enter_tag: Optional[str] = None,
) -> bool:
""" """
Based on trade duration, current profit of the trade and ROI configuration, Based on trade duration, current profit of the trade and ROI configuration,
decides whether bot should exit. decides whether bot should exit.
@ -1029,7 +1046,7 @@ class IStrategy(ABC, HyperStrategyMixin):
""" """
# Check if time matches and current rate is above threshold # Check if time matches and current rate is above threshold
trade_dur = int((current_time.timestamp() - trade.open_date_utc.timestamp()) // 60) trade_dur = int((current_time.timestamp() - trade.open_date_utc.timestamp()) // 60)
_, roi = self.min_roi_reached_entry(trade_dur) _, roi = self.min_roi_reached_entry(trade_dur, enter_tag)
if roi is None: if roi is None:
return False return False
else: else: