From 543aa742789ea3729958c86dbf916df8b2516a14 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 24 Mar 2022 20:33:47 +0100 Subject: [PATCH] update sell_reason to exit_reason --- docs/strategy_migration.md | 1 + docs/webhook-config.md | 6 +- freqtrade/data/btanalysis.py | 2 +- freqtrade/freqtradebot.py | 12 ++- freqtrade/optimize/backtesting.py | 6 +- freqtrade/optimize/optimize_reports.py | 20 ++-- freqtrade/persistence/migrations.py | 6 +- freqtrade/persistence/models.py | 21 ++-- .../plugins/protections/stoploss_guard.py | 2 +- freqtrade/rpc/api_server/api_schemas.py | 3 +- freqtrade/rpc/rpc.py | 12 +-- freqtrade/rpc/telegram.py | 30 +++--- tests/conftest_trades.py | 8 +- tests/conftest_trades_usdt.py | 4 +- tests/edge/test_edge.py | 12 +-- tests/optimize/__init__.py | 2 +- tests/optimize/test_backtest_detail.py | 98 +++++++++---------- tests/optimize/test_backtesting.py | 20 ++-- .../test_backtesting_adjust_position.py | 2 +- tests/optimize/test_hyperopt.py | 4 +- tests/optimize/test_optimize_reports.py | 27 +++-- tests/plugins/test_protections.py | 2 +- tests/rpc/test_rpc.py | 6 +- tests/rpc/test_rpc_apiserver.py | 6 +- tests/rpc/test_rpc_telegram.py | 31 +++--- tests/test_freqtradebot.py | 25 +++-- tests/test_integration.py | 6 +- tests/test_persistence.py | 4 +- 28 files changed, 201 insertions(+), 177 deletions(-) diff --git a/docs/strategy_migration.md b/docs/strategy_migration.md index 1ceb98fa5..64cff5f02 100644 --- a/docs/strategy_migration.md +++ b/docs/strategy_migration.md @@ -25,6 +25,7 @@ You can use the quick summary as checklist. Please refer to the detailed section * [`buy_tag` -> `enter_tag` (used for both long and short trades)](#populate_buy_trend) * [New column `enter_short` and corresponding new column `exit_short`](#populate_sell_trend) * trade-object now has the following new properties: `is_short`, `enter_side`, `exit_side` and `trade_direction`. + * `sell_reason` -> `exit_reason` * [Renamed `trade.nr_of_successful_buys` to `trade.nr_of_successful_entries` (mostly relevant for `adjust_trade_position()`)](#adjust-trade-position-changes) * Introduced new [`leverage` callback](strategy-callbacks.md#leverage-callback). * Informative pairs can now pass a 3rd element in the Tuple, defining the candle type. diff --git a/docs/webhook-config.md b/docs/webhook-config.md index 1266618f6..b974e0041 100644 --- a/docs/webhook-config.md +++ b/docs/webhook-config.md @@ -178,7 +178,7 @@ Possible parameters are: * `stake_currency` * `base_currency` * `fiat_currency` -* `sell_reason` +* `exit_reason` * `order_type` * `open_date` * `close_date` @@ -203,7 +203,7 @@ Possible parameters are: * `stake_currency` * `base_currency` * `fiat_currency` -* `sell_reason` +* `exit_reason` * `order_type` * `open_date` * `close_date` @@ -228,7 +228,7 @@ Possible parameters are: * `stake_currency` * `base_currency` * `fiat_currency` -* `sell_reason` +* `exit_reason` * `order_type` * `open_date` * `close_date` diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index 4df8b2838..c8654cfda 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -22,7 +22,7 @@ logger = logging.getLogger(__name__) BT_DATA_COLUMNS = ['pair', 'stake_amount', 'amount', 'open_date', 'close_date', 'open_rate', 'close_rate', 'fee_open', 'fee_close', 'trade_duration', - 'profit_ratio', 'profit_abs', 'sell_reason', + 'profit_ratio', 'profit_abs', 'exit_reason', 'initial_stop_loss_abs', 'initial_stop_loss_ratio', 'stop_loss_abs', 'stop_loss_ratio', 'min_rate', 'max_rate', 'is_open', 'enter_tag', 'is_short' diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 9a07020ad..5e6730529 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1010,7 +1010,7 @@ class FreqtradeBot(LoggingMixin): # We check if stoploss order is fulfilled if stoploss_order and stoploss_order['status'] in ('closed', 'triggered'): - trade.sell_reason = ExitType.STOPLOSS_ON_EXCHANGE.value + trade.exit_reason = ExitType.STOPLOSS_ON_EXCHANGE.value self.update_trade_state(trade, trade.stoploss_order_id, stoploss_order, stoploss_order=True) # Lock pair for one candle to prevent immediate rebuys @@ -1286,7 +1286,7 @@ class FreqtradeBot(LoggingMixin): trade.close_date = None trade.is_open = True trade.open_order_id = None - trade.sell_reason = None + trade.exit_reason = None cancelled = True else: # TODO: figure out how to handle partially complete sell orders @@ -1416,7 +1416,7 @@ class FreqtradeBot(LoggingMixin): trade.open_order_id = order['id'] trade.sell_order_status = '' trade.close_rate_requested = limit - trade.sell_reason = exit_tag or exit_check.exit_reason + trade.exit_reason = exit_tag or exit_check.sell_reason # Lock pair for one candle to prevent immediate re-trading self.strategy.lock_pair(trade.pair, datetime.now(timezone.utc), @@ -1461,7 +1461,8 @@ class FreqtradeBot(LoggingMixin): 'profit_ratio': profit_ratio, 'buy_tag': trade.enter_tag, 'enter_tag': trade.enter_tag, - 'sell_reason': trade.sell_reason, + 'sell_reason': trade.exit_reason, # Deprecated + 'exit_reason': trade.exit_reason, 'open_date': trade.open_date, 'close_date': trade.close_date or datetime.utcnow(), 'stake_currency': self.config['stake_currency'], @@ -1509,7 +1510,8 @@ class FreqtradeBot(LoggingMixin): 'profit_ratio': profit_ratio, 'buy_tag': trade.enter_tag, 'enter_tag': trade.enter_tag, - 'sell_reason': trade.sell_reason, + 'sell_reason': trade.exit_reason, # Deprecated + 'exit_reason': trade.exit_reason, 'open_date': trade.open_date, 'close_date': trade.close_date or datetime.now(timezone.utc), 'stake_currency': self.config['stake_currency'], diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 9784d426c..943426679 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -555,7 +555,7 @@ class Backtesting: current_time=sell_candle_time): return None - trade.sell_reason = sell.exit_reason + trade.exit_reason = sell.exit_reason # Checks and adds an exit tag, after checking that the length of the # sell_row has the length for an exit tag column @@ -564,7 +564,7 @@ class Backtesting: and sell_row[EXIT_TAG_IDX] is not None and len(sell_row[EXIT_TAG_IDX]) > 0 ): - trade.sell_reason = sell_row[EXIT_TAG_IDX] + trade.exit_reason = sell_row[EXIT_TAG_IDX] self.order_id_counter += 1 order = Order( @@ -810,7 +810,7 @@ class Backtesting: sell_row = data[pair][-1] trade.close_date = sell_row[DATE_IDX].to_pydatetime() - trade.sell_reason = ExitType.FORCE_SELL.value + trade.exit_reason = ExitType.FORCE_SELL.value trade.close(sell_row[OPEN_IDX], show_msg=False) LocalTrade.close_bt_trade(trade) # Deepcopy object to have wallets update correctly diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 97cadd683..155d77f9e 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -166,7 +166,7 @@ def generate_tag_metrics(tag_type: str, return [] -def generate_sell_reason_stats(max_open_trades: int, results: DataFrame) -> List[Dict]: +def generate_exit_reason_stats(max_open_trades: int, results: DataFrame) -> List[Dict]: """ Generate small table outlining Backtest results :param max_open_trades: Max_open_trades parameter @@ -175,8 +175,8 @@ def generate_sell_reason_stats(max_open_trades: int, results: DataFrame) -> List """ tabular_data = [] - for reason, count in results['sell_reason'].value_counts().iteritems(): - result = results.loc[results['sell_reason'] == reason] + for reason, count in results['exit_reason'].value_counts().iteritems(): + result = results.loc[results['exit_reason'] == reason] profit_mean = result['profit_ratio'].mean() profit_sum = result['profit_ratio'].sum() @@ -184,7 +184,7 @@ def generate_sell_reason_stats(max_open_trades: int, results: DataFrame) -> List tabular_data.append( { - 'sell_reason': reason, + 'exit_reason': reason, 'trades': count, 'wins': len(result[result['profit_abs'] > 0]), 'draws': len(result[result['profit_abs'] == 0]), @@ -382,7 +382,7 @@ def generate_strategy_stats(pairlist: List[str], enter_tag_results = generate_tag_metrics("enter_tag", starting_balance=start_balance, results=results, skip_nan=False) - exit_reason_stats = generate_sell_reason_stats(max_open_trades=max_open_trades, + exit_reason_stats = generate_exit_reason_stats(max_open_trades=max_open_trades, results=results) left_open_results = generate_pair_metrics(pairlist, stake_currency=stake_currency, starting_balance=start_balance, @@ -406,7 +406,7 @@ def generate_strategy_stats(pairlist: List[str], 'worst_pair': worst_pair, 'results_per_pair': pair_results, 'results_per_enter_tag': enter_tag_results, - 'sell_reason_summary': exit_reason_stats, + 'exit_reason_summary': exit_reason_stats, 'left_open_trades': left_open_results, # 'days_breakdown_stats': days_breakdown_stats, @@ -572,7 +572,7 @@ def text_table_bt_results(pair_results: List[Dict[str, Any]], stake_currency: st floatfmt=floatfmt, tablefmt="orgtbl", stralign="right") -def text_table_exit_reason(sell_reason_stats: List[Dict[str, Any]], stake_currency: str) -> str: +def text_table_exit_reason(exit_reason_stats: List[Dict[str, Any]], stake_currency: str) -> str: """ Generate small table outlining Backtest results :param sell_reason_stats: Exit reason metrics @@ -590,12 +590,12 @@ def text_table_exit_reason(sell_reason_stats: List[Dict[str, Any]], stake_curren ] output = [[ - t['sell_reason'], t['trades'], + t['exit_reason'], t['trades'], _generate_wins_draws_losses(t['wins'], t['draws'], t['losses']), t['profit_mean_pct'], t['profit_sum_pct'], round_coin_value(t['profit_total_abs'], stake_currency, False), t['profit_total_pct'], - ] for t in sell_reason_stats] + ] for t in exit_reason_stats] return tabulate(output, headers=headers, tablefmt="orgtbl", stralign="right") @@ -813,7 +813,7 @@ def show_backtest_result(strategy: str, results: Dict[str, Any], stake_currency: print(' ENTER TAG STATS '.center(len(table.splitlines()[0]), '=')) print(table) - table = text_table_exit_reason(sell_reason_stats=results['sell_reason_summary'], + table = text_table_exit_reason(exit_reason_stats=results['exit_reason_summary'], stake_currency=stake_currency) if isinstance(table, str) and len(table) > 0: print(' EXIT REASON STATS '.center(len(table.splitlines()[0]), '=')) diff --git a/freqtrade/persistence/migrations.py b/freqtrade/persistence/migrations.py index a84503c74..cc6bd9da9 100644 --- a/freqtrade/persistence/migrations.py +++ b/freqtrade/persistence/migrations.py @@ -74,7 +74,7 @@ def migrate_trades_and_orders_table( stoploss_last_update = get_column_def(cols, 'stoploss_last_update', 'null') max_rate = get_column_def(cols, 'max_rate', '0.0') min_rate = get_column_def(cols, 'min_rate', 'null') - sell_reason = get_column_def(cols, 'sell_reason', 'null') + exit_reason = get_column_def(cols, 'sell_reason', get_column_def(cols, 'exit_reason', 'null')) strategy = get_column_def(cols, 'strategy', 'null') enter_tag = get_column_def(cols, 'buy_tag', get_column_def(cols, 'enter_tag', 'null')) @@ -136,7 +136,7 @@ def migrate_trades_and_orders_table( stake_amount, amount, amount_requested, open_date, close_date, open_order_id, stop_loss, stop_loss_pct, initial_stop_loss, initial_stop_loss_pct, stoploss_order_id, stoploss_last_update, - max_rate, min_rate, sell_reason, sell_order_status, strategy, enter_tag, + max_rate, min_rate, exit_reason, sell_order_status, strategy, enter_tag, timeframe, open_trade_value, close_profit_abs, trading_mode, leverage, liquidation_price, is_short, interest_rate, funding_fees @@ -152,7 +152,7 @@ def migrate_trades_and_orders_table( {initial_stop_loss} initial_stop_loss, {initial_stop_loss_pct} initial_stop_loss_pct, {stoploss_order_id} stoploss_order_id, {stoploss_last_update} stoploss_last_update, - {max_rate} max_rate, {min_rate} min_rate, {sell_reason} sell_reason, + {max_rate} max_rate, {min_rate} min_rate, {exit_reason} exit_reason, {sell_order_status} sell_order_status, {strategy} strategy, {enter_tag} enter_tag, {timeframe} timeframe, {open_trade_value} open_trade_value, {close_profit_abs} close_profit_abs, diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index a23c8e43e..723eebb8c 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -316,7 +316,7 @@ class LocalTrade(): max_rate: float = 0.0 # Lowest price reached min_rate: float = 0.0 - sell_reason: str = '' + exit_reason: str = '' sell_order_status: str = '' strategy: str = '' enter_tag: Optional[str] = None @@ -459,7 +459,8 @@ class LocalTrade(): 'profit_pct': round(self.close_profit * 100, 2) if self.close_profit else None, 'profit_abs': self.close_profit_abs, - 'sell_reason': self.sell_reason, + 'sell_reason': self.exit_reason, # Deprecated + 'exit_reason': self.exit_reason, 'sell_order_status': self.sell_order_status, 'stop_loss_abs': self.stop_loss, 'stop_loss_ratio': self.stop_loss_pct if self.stop_loss_pct else None, @@ -618,7 +619,7 @@ class LocalTrade(): elif order.ft_order_side == 'stoploss': self.stoploss_order_id = None self.close_rate_requested = self.stop_loss - self.sell_reason = ExitType.STOPLOSS_ON_EXCHANGE.value + self.exit_reason = ExitType.STOPLOSS_ON_EXCHANGE.value if self.is_open: logger.info(f'{order.order_type.upper()} is hit for {self}.') self.close(order.safe_price) @@ -947,6 +948,12 @@ class LocalTrade(): """ return len(self.select_filled_orders('sell')) + @property + def sell_reason(self) -> str: + """ DEPRECATED! Please use exit_reason instead.""" + return self.exit_reason + + @staticmethod def get_trades_proxy(*, pair: str = None, is_open: bool = None, open_date: datetime = None, close_date: datetime = None, @@ -1076,7 +1083,7 @@ class Trade(_DECL_BASE, LocalTrade): max_rate = Column(Float, nullable=True, default=0.0) # Lowest price reached min_rate = Column(Float, nullable=True) - sell_reason = Column(String(100), nullable=True) + exit_reason = Column(String(100), nullable=True) sell_order_status = Column(String(100), nullable=True) strategy = Column(String(100), nullable=True) enter_tag = Column(String(100), nullable=True) @@ -1295,12 +1302,12 @@ class Trade(_DECL_BASE, LocalTrade): filters.append(Trade.pair == pair) sell_tag_perf = Trade.query.with_entities( - Trade.sell_reason, + Trade.exit_reason, func.sum(Trade.close_profit).label('profit_sum'), func.sum(Trade.close_profit_abs).label('profit_sum_abs'), func.count(Trade.pair).label('count') ).filter(*filters)\ - .group_by(Trade.sell_reason) \ + .group_by(Trade.exit_reason) \ .order_by(desc('profit_sum_abs')) \ .all() @@ -1330,7 +1337,7 @@ class Trade(_DECL_BASE, LocalTrade): mix_tag_perf = Trade.query.with_entities( Trade.id, Trade.enter_tag, - Trade.sell_reason, + Trade.exit_reason, func.sum(Trade.close_profit).label('profit_sum'), func.sum(Trade.close_profit_abs).label('profit_sum_abs'), func.count(Trade.pair).label('count') diff --git a/freqtrade/plugins/protections/stoploss_guard.py b/freqtrade/plugins/protections/stoploss_guard.py index 7a29c20b1..efca49054 100644 --- a/freqtrade/plugins/protections/stoploss_guard.py +++ b/freqtrade/plugins/protections/stoploss_guard.py @@ -53,7 +53,7 @@ class StoplossGuard(IProtection): # trades = Trade.get_trades(filters).all() trades1 = Trade.get_trades_proxy(pair=pair, is_open=False, close_date=look_back_until) - trades = [trade for trade in trades1 if (str(trade.sell_reason) in ( + trades = [trade for trade in trades1 if (str(trade.exit_reason) in ( ExitType.TRAILING_STOP_LOSS.value, ExitType.STOP_LOSS.value, ExitType.STOPLOSS_ON_EXCHANGE.value) and trade.close_profit and trade.close_profit < 0)] diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index 11baa9560..bd719dc24 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -113,7 +113,7 @@ class SellReason(BaseModel): class Stats(BaseModel): - sell_reasons: Dict[str, SellReason] + exit_reasons: Dict[str, SellReason] durations: Dict[str, Optional[float]] @@ -236,6 +236,7 @@ class TradeSchema(BaseModel): profit_abs: Optional[float] profit_fiat: Optional[float] sell_reason: Optional[str] + exit_reason: Optional[str] sell_order_status: Optional[str] stop_loss_abs: Optional[float] stop_loss_ratio: Optional[float] diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 1388a9bda..cfa1eea3b 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -428,13 +428,13 @@ class RPC: return 'losses' else: return 'draws' - trades = trades = Trade.get_trades([Trade.is_open.is_(False)]) + trades: List[Trade] = Trade.get_trades([Trade.is_open.is_(False)]) # Sell reason - sell_reasons = {} + exit_reasons = {} for trade in trades: - if trade.sell_reason not in sell_reasons: - sell_reasons[trade.sell_reason] = {'wins': 0, 'losses': 0, 'draws': 0} - sell_reasons[trade.sell_reason][trade_win_loss(trade)] += 1 + if trade.exit_reason not in exit_reasons: + exit_reasons[trade.exit_reason] = {'wins': 0, 'losses': 0, 'draws': 0} + exit_reasons[trade.exit_reason][trade_win_loss(trade)] += 1 # Duration dur: Dict[str, List[int]] = {'wins': [], 'draws': [], 'losses': []} @@ -448,7 +448,7 @@ class RPC: losses_dur = sum(dur['losses']) / len(dur['losses']) if len(dur['losses']) > 0 else None durations = {'wins': wins_dur, 'draws': draws_dur, 'losses': losses_dur} - return {'sell_reasons': sell_reasons, 'durations': durations} + return {'exit_reasons': exit_reasons, 'durations': durations} def _rpc_trade_statistics( self, stake_currency: str, fiat_display_currency: str, diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 20ab86aeb..b45762bc2 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -290,7 +290,7 @@ class Telegram(RPCHandler): f"*{'Profit' if is_fill else 'Unrealized Profit'}:* " f"`{msg['profit_ratio']:.2%}{msg['profit_extra']}`\n" f"*Enter Tag:* `{msg['enter_tag']}`\n" - f"*Exit Reason:* `{msg['sell_reason']}`\n" + f"*Exit Reason:* `{msg['exit_reason']}`\n" f"*Duration:* `{msg['duration']} ({msg['duration_min']:.1f} min)`\n" f"*Direction:* `{msg['direction']}`\n" f"{msg['leverage_text']}" @@ -361,7 +361,7 @@ class Telegram(RPCHandler): if isinstance(sell_noti, str): noti = sell_noti else: - noti = sell_noti.get(str(msg['sell_reason']), default_noti) + noti = sell_noti.get(str(msg['exit_reason']), default_noti) else: noti = self._config['telegram'] \ .get('notification_settings', {}).get(str(msg_type), default_noti) @@ -384,7 +384,7 @@ class Telegram(RPCHandler): return "\N{ROCKET}" elif float(msg['profit_percent']) >= 0.0: return "\N{EIGHT SPOKED ASTERISK}" - elif msg['sell_reason'] == "stop_loss": + elif msg['exit_reason'] == "stop_loss": return "\N{WARNING SIGN}" else: return "\N{CROSS MARK}" @@ -466,7 +466,7 @@ class Telegram(RPCHandler): for r in results: r['open_date_hum'] = arrow.get(r['open_date']).humanize() r['num_entries'] = len([o for o in r['orders'] if o['ft_is_entry']]) - r['sell_reason'] = r.get('sell_reason', "") + r['exit_reason'] = r.get('exit_reason', "") lines = [ "*Trade ID:* `{trade_id}`" + ("` (since {open_date_hum})`" if r['is_open'] else ""), @@ -475,7 +475,7 @@ class Telegram(RPCHandler): "*Leverage:* `{leverage}`" if r.get('leverage') else "", "*Amount:* `{amount} ({stake_amount} {base_currency})`", "*Enter Tag:* `{enter_tag}`" if r['enter_tag'] else "", - "*Exit Reason:* `{sell_reason}`" if r['sell_reason'] else "", + "*Exit Reason:* `{exit_reason}`" if r['exit_reason'] else "", ] if position_adjust: @@ -771,23 +771,23 @@ class Telegram(RPCHandler): 'force_sell': 'Forcesell', 'emergency_sell': 'Emergency Sell', } - sell_reasons_tabulate = [ + exit_reasons_tabulate = [ [ reason_map.get(reason, reason), sum(count.values()), count['wins'], count['losses'] - ] for reason, count in stats['sell_reasons'].items() + ] for reason, count in stats['exit_reasons'].items() ] - sell_reasons_msg = 'No trades yet.' - for reason in chunks(sell_reasons_tabulate, 25): - sell_reasons_msg = tabulate( + exit_reasons_msg = 'No trades yet.' + for reason in chunks(exit_reasons_tabulate, 25): + exit_reasons_msg = tabulate( reason, - headers=['Sell Reason', 'Sells', 'Wins', 'Losses'] + headers=['Exit Reason', 'Exits', 'Wins', 'Losses'] ) - if len(sell_reasons_tabulate) > 25: - self._send_msg(sell_reasons_msg, ParseMode.MARKDOWN) - sell_reasons_msg = '' + if len(exit_reasons_tabulate) > 25: + self._send_msg(exit_reasons_msg, ParseMode.MARKDOWN) + exit_reasons_msg = '' durations = stats['durations'] duration_msg = tabulate( @@ -799,7 +799,7 @@ class Telegram(RPCHandler): ], headers=['', 'Avg. Duration'] ) - msg = (f"""```\n{sell_reasons_msg}```\n```\n{duration_msg}```""") + msg = (f"""```\n{exit_reasons_msg}```\n```\n{duration_msg}```""") self._send_msg(msg, ParseMode.MARKDOWN) diff --git a/tests/conftest_trades.py b/tests/conftest_trades.py index 3e3ba9495..4aebecd6a 100644 --- a/tests/conftest_trades.py +++ b/tests/conftest_trades.py @@ -104,7 +104,7 @@ def mock_trade_2(fee, is_short: bool): strategy='StrategyTestV3', timeframe=5, enter_tag='TEST1', - sell_reason='sell_signal', + exit_reason='sell_signal', open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20), close_date=datetime.now(tz=timezone.utc) - timedelta(minutes=2), is_short=is_short @@ -164,7 +164,7 @@ def mock_trade_3(fee, is_short: bool): is_open=False, strategy='StrategyTestV3', timeframe=5, - sell_reason='roi', + exit_reason='roi', open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20), close_date=datetime.now(tz=timezone.utc), is_short=is_short @@ -401,7 +401,7 @@ def short_trade(fee): open_order_id='dry_run_exit_short_12345', strategy='DefaultStrategy', timeframe=5, - sell_reason='sell_signal', + exit_reason='sell_signal', open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20), # close_date=datetime.now(tz=timezone.utc) - timedelta(minutes=2), is_short=True @@ -490,7 +490,7 @@ def leverage_trade(fee): open_order_id='dry_run_leverage_buy_12368', strategy='DefaultStrategy', timeframe=5, - sell_reason='sell_signal', + exit_reason='sell_signal', open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=300), close_date=datetime.now(tz=timezone.utc), interest_rate=0.0005 diff --git a/tests/conftest_trades_usdt.py b/tests/conftest_trades_usdt.py index 508e54f03..59e7f0457 100644 --- a/tests/conftest_trades_usdt.py +++ b/tests/conftest_trades_usdt.py @@ -89,7 +89,7 @@ def mock_trade_usdt_2(fee): open_order_id='dry_run_sell_12345', strategy='StrategyTestV2', timeframe=5, - sell_reason='sell_signal', + exit_reason='sell_signal', open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20), close_date=datetime.now(tz=timezone.utc) - timedelta(minutes=2), ) @@ -148,7 +148,7 @@ def mock_trade_usdt_3(fee): is_open=False, strategy='StrategyTestV2', timeframe=5, - sell_reason='roi', + exit_reason='roi', open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20), close_date=datetime.now(tz=timezone.utc), ) diff --git a/tests/edge/test_edge.py b/tests/edge/test_edge.py index 4ac27adc0..76005c734 100644 --- a/tests/edge/test_edge.py +++ b/tests/edge/test_edge.py @@ -95,8 +95,8 @@ tc1 = BTContainer(data=[ [6, 5000, 5025, 4975, 4987, 6172, 0, 0], # should sell ], stop_loss=-0.99, roi={"0": float('inf')}, profit_perc=0.00, - trades=[BTrade(sell_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=2), - BTrade(sell_reason=ExitType.SELL_SIGNAL, open_tick=4, close_tick=6)] + trades=[BTrade(exit_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=2), + BTrade(exit_reason=ExitType.SELL_SIGNAL, open_tick=4, close_tick=6)] ) # 3) Entered, sl 1%, candle drops 8% => Trade closed, 1% loss @@ -107,7 +107,7 @@ tc2 = BTContainer(data=[ [2, 5000, 5025, 4975, 4987, 6172, 0, 0], ], stop_loss=-0.01, roi={"0": float('inf')}, profit_perc=-0.01, - trades=[BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1)] + trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1)] ) # 4) Entered, sl 3 %, candle drops 4%, recovers to 1 % = > Trade closed, 3 % loss @@ -118,7 +118,7 @@ tc3 = BTContainer(data=[ [2, 5000, 5025, 4975, 4987, 6172, 0, 0], ], stop_loss=-0.03, roi={"0": float('inf')}, profit_perc=-0.03, - trades=[BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1)] + trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1)] ) # 5) Stoploss and sell are hit. should sell on stoploss @@ -129,7 +129,7 @@ tc4 = BTContainer(data=[ [2, 5000, 5025, 4975, 4987, 6172, 0, 0], ], stop_loss=-0.03, roi={"0": float('inf')}, profit_perc=-0.03, - trades=[BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1)] + trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1)] ) TESTS = [ @@ -162,7 +162,7 @@ def test_edge_results(edge_conf, mocker, caplog, data) -> None: for c, trade in enumerate(data.trades): res = results.iloc[c] - assert res.exit_type == trade.sell_reason + assert res.exit_type == trade.exit_reason assert res.open_date == _get_frame_time_from_offset(trade.open_tick).replace(tzinfo=None) assert res.close_date == _get_frame_time_from_offset(trade.close_tick).replace(tzinfo=None) diff --git a/tests/optimize/__init__.py b/tests/optimize/__init__.py index ad14125b5..4e1192a13 100644 --- a/tests/optimize/__init__.py +++ b/tests/optimize/__init__.py @@ -15,7 +15,7 @@ class BTrade(NamedTuple): """ Minimalistic Trade result used for functional backtesting """ - sell_reason: ExitType + exit_reason: ExitType open_tick: int close_tick: int enter_tag: Optional[str] = None diff --git a/tests/optimize/test_backtest_detail.py b/tests/optimize/test_backtest_detail.py index f8de780b9..43b15fc81 100644 --- a/tests/optimize/test_backtest_detail.py +++ b/tests/optimize/test_backtest_detail.py @@ -23,7 +23,7 @@ tc0 = BTContainer(data=[ [4, 5010, 5011, 4977, 4995, 6172, 0, 0], [5, 4995, 4995, 4950, 4950, 6172, 0, 0]], stop_loss=-0.01, roi={"0": 1}, profit_perc=0.002, use_sell_signal=True, - trades=[BTrade(sell_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=4)] + trades=[BTrade(exit_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=4)] ) # Test 1: Stop-Loss Triggered 1% loss @@ -37,7 +37,7 @@ tc1 = BTContainer(data=[ [4, 4977, 4995, 4977, 4995, 6172, 0, 0], [5, 4995, 4995, 4950, 4950, 6172, 0, 0]], stop_loss=-0.01, roi={"0": 1}, profit_perc=-0.01, - trades=[BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=2)] + trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=2)] ) @@ -52,7 +52,7 @@ tc2 = BTContainer(data=[ [4, 4962, 4987, 4937, 4950, 6172, 0, 0], [5, 4950, 4975, 4925, 4950, 6172, 0, 0]], stop_loss=-0.03, roi={"0": 1}, profit_perc=-0.03, - trades=[BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=3)] + trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=3)] ) @@ -72,8 +72,8 @@ tc3 = BTContainer(data=[ [5, 4962, 4987, 4000, 4000, 6172, 0, 0], # exit with stoploss hit [6, 4950, 4975, 4950, 4950, 6172, 0, 0]], stop_loss=-0.02, roi={"0": 1}, profit_perc=-0.04, - trades=[BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=2), - BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=4, close_tick=5)] + trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=2), + BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=4, close_tick=5)] ) # Test 4: Minus 3% / recovery +15% @@ -89,7 +89,7 @@ tc4 = BTContainer(data=[ [4, 4962, 4987, 4937, 4950, 6172, 0, 0], [5, 4950, 4975, 4925, 4950, 6172, 0, 0]], stop_loss=-0.02, roi={"0": 0.06}, profit_perc=-0.02, - trades=[BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=2)] + trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=2)] ) # Test 5: Drops 0.5% Closes +20%, ROI triggers 3% Gain @@ -103,7 +103,7 @@ tc5 = BTContainer(data=[ [4, 4962, 4987, 4962, 4972, 6172, 0, 0], [5, 4950, 4975, 4925, 4950, 6172, 0, 0]], stop_loss=-0.01, roi={"0": 0.03}, profit_perc=0.03, - trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=3)] + trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)] ) # Test 6: Drops 3% / Recovers 6% Positive / Closes 1% positve, Stop-Loss triggers 2% Loss @@ -117,7 +117,7 @@ tc6 = BTContainer(data=[ [4, 4962, 4987, 4950, 4950, 6172, 0, 0], [5, 4950, 4975, 4925, 4950, 6172, 0, 0]], stop_loss=-0.02, roi={"0": 0.05}, profit_perc=-0.02, - trades=[BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=2)] + trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=2)] ) # Test 7: 6% Positive / 1% Negative / Close 1% Positve, ROI Triggers 3% Gain @@ -131,7 +131,7 @@ tc7 = BTContainer(data=[ [4, 4962, 4987, 4950, 4950, 6172, 0, 0], [5, 4950, 4975, 4925, 4950, 6172, 0, 0]], stop_loss=-0.02, roi={"0": 0.03}, profit_perc=0.03, - trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=2)] + trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=2)] ) @@ -145,7 +145,7 @@ tc8 = BTContainer(data=[ [3, 4850, 5050, 4650, 4750, 6172, 0, 0], [4, 4750, 4950, 4350, 4750, 6172, 0, 0]], stop_loss=-0.10, roi={"0": 0.10}, profit_perc=-0.055, trailing_stop=True, - trades=[BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)] + trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)] ) @@ -159,7 +159,7 @@ tc9 = BTContainer(data=[ [3, 5000, 5200, 4550, 4850, 6172, 0, 0], [4, 4750, 4950, 4350, 4750, 6172, 0, 0]], stop_loss=-0.10, roi={"0": 0.10}, profit_perc=-0.064, trailing_stop=True, - trades=[BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)] + trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)] ) # Test 10: trailing_stop should raise so candle 3 causes a stoploss @@ -175,7 +175,7 @@ tc10 = BTContainer(data=[ stop_loss=-0.10, roi={"0": 0.10}, profit_perc=-0.1, trailing_stop=True, trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.10, trailing_stop_positive=0.03, - trades=[BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=4)] + trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=4)] ) # Test 11: trailing_stop should raise so candle 3 causes a stoploss @@ -191,7 +191,7 @@ tc11 = BTContainer(data=[ stop_loss=-0.10, roi={"0": 0.10}, profit_perc=0.019, trailing_stop=True, trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.05, trailing_stop_positive=0.03, - trades=[BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)] + trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)] ) # Test 12: trailing_stop should raise in candle 2 and cause a stoploss in the same candle @@ -207,7 +207,7 @@ tc12 = BTContainer(data=[ stop_loss=-0.10, roi={"0": 0.10}, profit_perc=0.019, trailing_stop=True, trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.05, trailing_stop_positive=0.03, - trades=[BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=2)] + trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=2)] ) # Test 13: Buy and sell ROI on same candle @@ -220,7 +220,7 @@ tc13 = BTContainer(data=[ [3, 4850, 5050, 4750, 4750, 6172, 0, 0], [4, 4750, 4950, 4750, 4750, 6172, 0, 0]], stop_loss=-0.10, roi={"0": 0.01}, profit_perc=0.01, - trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=1)] + trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=1)] ) # Test 14 - Buy and Stoploss on same candle @@ -233,7 +233,7 @@ tc14 = BTContainer(data=[ [3, 4850, 5050, 4750, 4750, 6172, 0, 0], [4, 4750, 4950, 4350, 4750, 6172, 0, 0]], stop_loss=-0.05, roi={"0": 0.10}, profit_perc=-0.05, - trades=[BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1)] + trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1)] ) @@ -247,8 +247,8 @@ tc15 = BTContainer(data=[ [3, 4850, 5050, 4750, 4750, 6172, 0, 0], [4, 4750, 4950, 4350, 4750, 6172, 0, 0]], stop_loss=-0.05, roi={"0": 0.01}, profit_perc=-0.04, - trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=1), - BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=2, close_tick=2)] + trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=1), + BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=2, close_tick=2)] ) # Test 16: Buy, hold for 65 min, then forcesell using roi=-1 @@ -263,7 +263,7 @@ tc16 = BTContainer(data=[ [4, 4962, 4987, 4950, 4950, 6172, 0, 0], [5, 4950, 4975, 4925, 4950, 6172, 0, 0]], stop_loss=-0.10, roi={"0": 0.10, "65": -1}, profit_perc=-0.012, - trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=3)] + trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)] ) # Test 17: Buy, hold for 120 mins, then forcesell using roi=-1 @@ -279,7 +279,7 @@ tc17 = BTContainer(data=[ [4, 4962, 4987, 4950, 4950, 6172, 0, 0], [5, 4950, 4975, 4925, 4950, 6172, 0, 0]], stop_loss=-0.10, roi={"0": 0.10, "120": -1}, profit_perc=-0.004, - trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=3)] + trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)] ) @@ -295,7 +295,7 @@ tc18 = BTContainer(data=[ [4, 4962, 4987, 4950, 4950, 6172, 0, 0], [5, 4950, 4975, 4925, 4950, 6172, 0, 0]], stop_loss=-0.10, roi={"0": 0.10, "120": 0.01}, profit_perc=0.04, - trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=3)] + trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)] ) # Test 19: Buy, hold for 119 mins, then drop ROI to 1%, causing a sell in candle 3. @@ -310,7 +310,7 @@ tc19 = BTContainer(data=[ [4, 4962, 4987, 4950, 4950, 6172, 0, 0], [5, 4550, 4975, 4550, 4950, 6172, 0, 0]], stop_loss=-0.10, roi={"0": 0.10, "120": 0.01}, profit_perc=0.01, - trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=3)] + trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)] ) # Test 20: Buy, hold for 119 mins, then drop ROI to 1%, causing a sell in candle 3. @@ -325,7 +325,7 @@ tc20 = BTContainer(data=[ [4, 4962, 4987, 4950, 4950, 6172, 0, 0], [5, 4925, 4975, 4925, 4950, 6172, 0, 0]], stop_loss=-0.10, roi={"0": 0.10, "119": 0.01}, profit_perc=0.01, - trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=3)] + trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)] ) # Test 21: trailing_stop ROI collision. @@ -342,7 +342,7 @@ tc21 = BTContainer(data=[ stop_loss=-0.10, roi={"0": 0.04}, profit_perc=0.04, trailing_stop=True, trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.05, trailing_stop_positive=0.03, - trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=2)] + trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=2)] ) # Test 22: trailing_stop Raises in candle 2 - but ROI applies at the same time. @@ -358,7 +358,7 @@ tc22 = BTContainer(data=[ stop_loss=-0.10, roi={"0": 0.04}, profit_perc=0.04, trailing_stop=True, trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.05, trailing_stop_positive=0.03, - trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=2)] + trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=2)] ) @@ -375,7 +375,7 @@ tc23 = BTContainer(data=[ stop_loss=-0.10, roi={"0": 0.04}, profit_perc=0.04, trailing_stop=True, trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.05, trailing_stop_positive=0.03, - trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=2, is_short=True)] + trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=2, is_short=True)] ) # Test 24: trailing_stop Raises in candle 2 (does not trigger) @@ -394,7 +394,7 @@ tc24 = BTContainer(data=[ stop_loss=-0.10, roi={"0": 0.1, "119": 0.03}, profit_perc=0.03, trailing_stop=True, trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.05, trailing_stop_positive=0.03, - trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=3)] + trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)] ) # Test 25: Sell with signal sell in candle 3 (stoploss also triggers on this candle) @@ -409,7 +409,7 @@ tc25 = BTContainer(data=[ [4, 5010, 5010, 4977, 4995, 6172, 0, 0], [5, 4995, 4995, 4950, 4950, 6172, 0, 0]], stop_loss=-0.01, roi={"0": 1}, profit_perc=-0.01, use_sell_signal=True, - trades=[BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=3)] + trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=3)] ) # Test 26: Sell with signal sell in candle 3 (stoploss also triggers on this candle) @@ -424,7 +424,7 @@ tc26 = BTContainer(data=[ [4, 5010, 5010, 4855, 4995, 6172, 0, 0], # Triggers stoploss + sellsignal acted on [5, 4995, 4995, 4950, 4950, 6172, 0, 0]], stop_loss=-0.01, roi={"0": 1}, profit_perc=0.002, use_sell_signal=True, - trades=[BTrade(sell_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=4)] + trades=[BTrade(exit_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=4)] ) # Test 27: (copy of test26 with leverage) @@ -441,7 +441,7 @@ tc27 = BTContainer(data=[ [5, 4995, 4995, 4950, 4950, 6172, 0, 0]], stop_loss=-0.05, roi={"0": 1}, profit_perc=0.002 * 5.0, use_sell_signal=True, leverage=5.0, - trades=[BTrade(sell_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=4)] + trades=[BTrade(exit_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=4)] ) # Test 28: (copy of test26 with leverage and as short) @@ -458,7 +458,7 @@ tc28 = BTContainer(data=[ [5, 4995, 4995, 4950, 4950, 6172, 0, 0, 0, 0]], stop_loss=-0.05, roi={"0": 1}, profit_perc=0.002 * 5.0, use_sell_signal=True, leverage=5.0, - trades=[BTrade(sell_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=4, is_short=True)] + trades=[BTrade(exit_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=4, is_short=True)] ) # Test 29: Sell with signal sell in candle 3 (ROI at signal candle) # Stoploss at 10% (irrelevant), ROI at 5% (will trigger) @@ -472,7 +472,7 @@ tc29 = BTContainer(data=[ [4, 5010, 5010, 4855, 4995, 6172, 0, 0], [5, 4995, 4995, 4950, 4950, 6172, 0, 0]], stop_loss=-0.10, roi={"0": 0.05}, profit_perc=0.05, use_sell_signal=True, - trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=3)] + trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)] ) # Test 30: Sell with signal sell in candle 3 (ROI at signal candle) @@ -486,7 +486,7 @@ tc30 = BTContainer(data=[ [4, 5010, 5251, 4855, 4995, 6172, 0, 0], # Triggers ROI, sell-signal acted on [5, 4995, 4995, 4950, 4950, 6172, 0, 0]], stop_loss=-0.10, roi={"0": 0.05}, profit_perc=0.002, use_sell_signal=True, - trades=[BTrade(sell_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=4)] + trades=[BTrade(exit_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=4)] ) # Test 31: trailing_stop should raise so candle 3 causes a stoploss @@ -503,7 +503,7 @@ tc31 = BTContainer(data=[ stop_loss=-0.10, roi={"0": 0.10}, profit_perc=-0.03, trailing_stop=True, trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.05, trailing_stop_positive=0.03, - trades=[BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)] + trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)] ) # Test 32: (Short of test 31) trailing_stop should raise so candle 3 causes a stoploss @@ -521,7 +521,7 @@ tc32 = BTContainer(data=[ trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.05, trailing_stop_positive=0.03, trades=[ - BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3, is_short=True) + BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3, is_short=True) ] ) @@ -537,7 +537,7 @@ tc33 = BTContainer(data=[ [4, 4750, 4950, 4350, 4750, 6172, 0, 0]], stop_loss=-0.10, roi={"0": 0.10}, profit_perc=-0.02, trailing_stop=True, trailing_stop_positive=0.03, - trades=[BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=2)] + trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=2)] ) # Test 34: trailing_stop should be triggered immediately on trade open candle. @@ -551,7 +551,7 @@ tc34 = BTContainer(data=[ [4, 4750, 4950, 4350, 4750, 6172, 0, 0]], stop_loss=-0.10, roi={"0": 0.10}, profit_perc=-0.01, trailing_stop=True, trailing_stop_positive=0.01, - trades=[BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)] + trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)] ) # Test 35: trailing_stop should be triggered immediately on trade open candle. @@ -566,7 +566,7 @@ tc35 = BTContainer(data=[ stop_loss=-0.10, 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, - trades=[BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)] + trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)] ) # Test 36: trailing_stop should be triggered immediately on trade open candle. @@ -581,7 +581,7 @@ tc36 = BTContainer(data=[ 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=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)] + trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)] ) # Test 37: trailing_stop should be triggered immediately on trade open candle. @@ -597,7 +597,7 @@ tc37 = BTContainer(data=[ 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=ExitType.TRAILING_STOP_LOSS, + exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1, enter_tag='buy_signal_01' @@ -617,7 +617,7 @@ tc38 = BTContainer(data=[ 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=ExitType.TRAILING_STOP_LOSS, + exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1, enter_tag='short_signal_01', @@ -647,7 +647,7 @@ tc40 = BTContainer(data=[ [4, 4750, 4950, 4350, 4750, 6172, 0, 0]], stop_loss=-0.01, roi={"0": 0.10}, profit_perc=-0.01, custom_entry_price=7200, trades=[ - BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1) + BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1) ]) # Test 41: Custom-entry-price above all candles should have rate adjusted to "entry candle high" @@ -661,7 +661,7 @@ tc41 = BTContainer(data=[ stop_loss=-0.01, roi={"0": 0.10}, profit_perc=-0.01, custom_entry_price=4000, trades=[ - BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1, is_short=True) + BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1, is_short=True) ] ) @@ -678,7 +678,7 @@ tc42 = BTContainer(data=[ [4, 4750, 4950, 4350, 4750, 6172, 0, 0]], stop_loss=-0.10, roi={"0": 0.01}, profit_perc=0.01, custom_entry_price=4952, - trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=2)] + trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=2)] ) # Test 43: Custom-entry-price around candle low @@ -693,7 +693,7 @@ tc43 = BTContainer(data=[ [4, 4750, 4950, 4350, 4750, 6172, 0, 0]], stop_loss=-0.10, roi={"0": 0.01}, profit_perc=0.01, custom_entry_price=4952, - trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=1)] + trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=1)] ) # Test 44: Custom exit price below all candles @@ -708,7 +708,7 @@ tc44 = BTContainer(data=[ stop_loss=-0.10, roi={"0": 0.10}, profit_perc=-0.01, use_sell_signal=True, custom_exit_price=4552, - trades=[BTrade(sell_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=3)] + trades=[BTrade(exit_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=3)] ) # Test 45: Custom exit price above all candles @@ -723,7 +723,7 @@ tc45 = BTContainer(data=[ stop_loss=-0.10, roi={"0": 0.10}, profit_perc=0.0, use_sell_signal=True, custom_exit_price=6052, - trades=[BTrade(sell_reason=ExitType.FORCE_SELL, open_tick=1, close_tick=4)] + trades=[BTrade(exit_reason=ExitType.FORCE_SELL, open_tick=1, close_tick=4)] ) # Test 46: (Short of tc45) Custom short exit price above below candles @@ -738,7 +738,7 @@ tc46 = BTContainer(data=[ stop_loss=-0.10, roi={"0": 0.10}, profit_perc=0.0, use_sell_signal=True, custom_exit_price=4700, - trades=[BTrade(sell_reason=ExitType.FORCE_SELL, open_tick=1, close_tick=4, is_short=True)] + trades=[BTrade(exit_reason=ExitType.FORCE_SELL, open_tick=1, close_tick=4, is_short=True)] ) # Test 47: Colliding long and short signal @@ -861,7 +861,7 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None: for c, trade in enumerate(data.trades): res: BTrade = results.iloc[c] - assert res.sell_reason == trade.sell_reason.value + assert res.exit_reason == trade.exit_reason.value assert res.enter_tag == trade.enter_tag assert res.open_date == _get_frame_time_from_offset(trade.open_tick) assert res.close_date == _get_frame_time_from_offset(trade.close_tick) diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index cc5cf9e43..2c468ca55 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -713,7 +713,7 @@ def test_backtest__get_sell_trade_entry(default_conf, fee, mocker) -> None: # No data available. res = backtesting._get_sell_trade_entry(trade, row_sell) assert res is not None - assert res.sell_reason == ExitType.ROI.value + assert res.exit_reason == ExitType.ROI.value assert res.close_date_utc == datetime(2020, 1, 1, 5, 0, tzinfo=timezone.utc) # Enter new trade @@ -732,7 +732,7 @@ def test_backtest__get_sell_trade_entry(default_conf, fee, mocker) -> None: res = backtesting._get_sell_trade_entry(trade, row_sell) assert res is not None - assert res.sell_reason == ExitType.ROI.value + assert res.exit_reason == ExitType.ROI.value # Sell at minute 3 (not available above!) assert res.close_date_utc == datetime(2020, 1, 1, 5, 3, tzinfo=timezone.utc) sell_order = res.select_order('sell', True) @@ -781,7 +781,7 @@ def test_backtest_one(default_conf, fee, mocker, testdatadir) -> None: 'trade_duration': [235, 40], 'profit_ratio': [0.0, 0.0], 'profit_abs': [0.0, 0.0], - 'sell_reason': [ExitType.ROI.value, ExitType.ROI.value], + 'exit_reason': [ExitType.ROI.value, ExitType.ROI.value], 'initial_stop_loss_abs': [0.0940005, 0.09272236], 'initial_stop_loss_ratio': [-0.1, -0.1], 'stop_loss_abs': [0.0940005, 0.09272236], @@ -1178,7 +1178,7 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir): text_table_bt_results=text_table_mock, text_table_strategy=strattable_mock, generate_pair_metrics=MagicMock(), - generate_sell_reason_stats=sell_reason_mock, + generate_exit_reason_stats=sell_reason_mock, generate_strategy_comparison=strat_summary, generate_daily_stats=MagicMock(), ) @@ -1249,7 +1249,7 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat 'close_rate': [0.104969, 0.103541], "is_short": [False, False], - 'sell_reason': [ExitType.ROI, ExitType.ROI] + 'exit_reason': [ExitType.ROI, ExitType.ROI] }) result2 = pd.DataFrame({'pair': ['XRP/BTC', 'LTC/BTC', 'ETH/BTC'], 'profit_ratio': [0.03, 0.01, 0.1], @@ -1267,7 +1267,7 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat 'open_rate': [0.104445, 0.10302485, 0.122541], 'close_rate': [0.104969, 0.103541, 0.123541], "is_short": [False, False, False], - 'sell_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS] + 'exit_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS] }) backtestmock = MagicMock(side_effect=[ { @@ -1367,7 +1367,7 @@ def test_backtest_start_nomock_futures(default_conf_usdt, mocker, 'stake_amount': [0.01, 0.01], 'open_rate': [0.104445, 0.10302485], 'close_rate': [0.104969, 0.103541], - 'sell_reason': [ExitType.ROI, ExitType.ROI] + 'exit_reason': [ExitType.ROI, ExitType.ROI] }) result2 = pd.DataFrame({'pair': ['XRP/USDT', 'XRP/USDT', 'XRP/USDT'], 'profit_ratio': [0.03, 0.01, 0.1], @@ -1385,7 +1385,7 @@ def test_backtest_start_nomock_futures(default_conf_usdt, mocker, 'stake_amount': [0.01, 0.01, 0.01], 'open_rate': [0.104445, 0.10302485, 0.122541], 'close_rate': [0.104969, 0.103541, 0.123541], - 'sell_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS] + 'exit_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS] }) backtestmock = MagicMock(side_effect=[ { @@ -1470,7 +1470,7 @@ def test_backtest_start_multi_strat_nomock_detail(default_conf, mocker, 'stake_amount': [0.01, 0.01], 'open_rate': [0.104445, 0.10302485], 'close_rate': [0.104969, 0.103541], - 'sell_reason': [ExitType.ROI, ExitType.ROI] + 'exit_reason': [ExitType.ROI, ExitType.ROI] }) result2 = pd.DataFrame({'pair': ['XRP/BTC', 'LTC/BTC', 'ETH/BTC'], 'profit_ratio': [0.03, 0.01, 0.1], @@ -1488,7 +1488,7 @@ def test_backtest_start_multi_strat_nomock_detail(default_conf, mocker, 'stake_amount': [0.01, 0.01, 0.01], 'open_rate': [0.104445, 0.10302485, 0.122541], 'close_rate': [0.104969, 0.103541, 0.123541], - 'sell_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS] + 'exit_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS] }) backtestmock = MagicMock(side_effect=[ { diff --git a/tests/optimize/test_backtesting_adjust_position.py b/tests/optimize/test_backtesting_adjust_position.py index 95847c660..4f902bf42 100644 --- a/tests/optimize/test_backtesting_adjust_position.py +++ b/tests/optimize/test_backtesting_adjust_position.py @@ -60,7 +60,7 @@ def test_backtest_position_adjustment(default_conf, fee, mocker, testdatadir) -> 'trade_duration': [200, 40], 'profit_ratio': [0.0, 0.0], 'profit_abs': [0.0, 0.0], - 'sell_reason': [ExitType.ROI.value, ExitType.ROI.value], + 'exit_reason': [ExitType.ROI.value, ExitType.ROI.value], 'initial_stop_loss_abs': [0.0940005, 0.09272236], 'initial_stop_loss_ratio': [-0.1, -0.1], 'stop_loss_abs': [0.0940005, 0.09272236], diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index 3a6fe9293..e25649d80 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -357,7 +357,7 @@ def test_hyperopt_format_results(hyperopt): "is_open": [False, False, False, True], "is_short": [False, False, False, False], "stake_amount": [0.01, 0.01, 0.01, 0.01], - "sell_reason": [ExitType.ROI, ExitType.STOP_LOSS, + "exit_reason": [ExitType.ROI, ExitType.STOP_LOSS, ExitType.ROI, ExitType.FORCE_SELL] }), 'config': hyperopt.config, @@ -428,7 +428,7 @@ def test_generate_optimizer(mocker, hyperopt_conf) -> None: "is_open": [False, False, False, True], "is_short": [False, False, False, False], "stake_amount": [0.01, 0.01, 0.01, 0.01], - "sell_reason": [ExitType.ROI, ExitType.STOP_LOSS, + "exit_reason": [ExitType.ROI, ExitType.STOP_LOSS, ExitType.ROI, ExitType.FORCE_SELL] }), 'config': hyperopt_conf, diff --git a/tests/optimize/test_optimize_reports.py b/tests/optimize/test_optimize_reports.py index 3ff8d5870..c4ed64304 100644 --- a/tests/optimize/test_optimize_reports.py +++ b/tests/optimize/test_optimize_reports.py @@ -15,9 +15,8 @@ from freqtrade.edge import PairInfo from freqtrade.enums import ExitType from freqtrade.optimize.optimize_reports import (_get_resample_from_period, generate_backtest_stats, generate_daily_stats, generate_edge_table, - generate_pair_metrics, + generate_exit_reason_stats, generate_pair_metrics, generate_periodic_breakdown_stats, - generate_sell_reason_stats, generate_strategy_comparison, generate_trading_stats, show_sorted_pairlist, store_backtest_stats, text_table_bt_results, @@ -77,7 +76,7 @@ def test_generate_backtest_stats(default_conf, testdatadir, tmpdir): "is_open": [False, False, False, True], "is_short": [False, False, False, False], "stake_amount": [0.01, 0.01, 0.01, 0.01], - "sell_reason": [ExitType.ROI, ExitType.STOP_LOSS, + "exit_reason": [ExitType.ROI, ExitType.STOP_LOSS, ExitType.ROI, ExitType.FORCE_SELL] }), 'config': default_conf, @@ -129,7 +128,7 @@ def test_generate_backtest_stats(default_conf, testdatadir, tmpdir): "is_open": [False, False, False, True], "is_short": [False, False, False, False], "stake_amount": [0.01, 0.01, 0.01, 0.01], - "sell_reason": [ExitType.ROI, ExitType.ROI, + "exit_reason": [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS, ExitType.FORCE_SELL] }), 'config': default_conf, @@ -265,7 +264,7 @@ def test_generate_trading_stats(testdatadir): assert res['losses'] == 0 -def test_text_table_sell_reason(): +def test_text_table_exit_reason(): results = pd.DataFrame( { @@ -276,7 +275,7 @@ def test_text_table_sell_reason(): 'wins': [2, 0, 0], 'draws': [0, 0, 0], 'losses': [0, 0, 1], - 'sell_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS] + 'exit_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS] } ) @@ -291,9 +290,9 @@ def test_text_table_sell_reason(): ' -0.2 | -5 |' ) - sell_reason_stats = generate_sell_reason_stats(max_open_trades=2, + exit_reason_stats = generate_exit_reason_stats(max_open_trades=2, results=results) - assert text_table_exit_reason(sell_reason_stats=sell_reason_stats, + assert text_table_exit_reason(exit_reason_stats=exit_reason_stats, stake_currency='BTC') == result_str @@ -308,23 +307,23 @@ def test_generate_sell_reason_stats(): 'wins': [2, 0, 0], 'draws': [0, 0, 0], 'losses': [0, 0, 1], - 'sell_reason': [ExitType.ROI.value, ExitType.ROI.value, ExitType.STOP_LOSS.value] + 'exit_reason': [ExitType.ROI.value, ExitType.ROI.value, ExitType.STOP_LOSS.value] } ) - sell_reason_stats = generate_sell_reason_stats(max_open_trades=2, + exit_reason_stats = generate_exit_reason_stats(max_open_trades=2, results=results) - roi_result = sell_reason_stats[0] - assert roi_result['sell_reason'] == 'roi' + roi_result = exit_reason_stats[0] + assert roi_result['exit_reason'] == 'roi' assert roi_result['trades'] == 2 assert pytest.approx(roi_result['profit_mean']) == 0.15 assert roi_result['profit_mean_pct'] == round(roi_result['profit_mean'] * 100, 2) assert pytest.approx(roi_result['profit_mean']) == 0.15 assert roi_result['profit_mean_pct'] == round(roi_result['profit_mean'] * 100, 2) - stop_result = sell_reason_stats[1] + stop_result = exit_reason_stats[1] - assert stop_result['sell_reason'] == 'stop_loss' + assert stop_result['exit_reason'] == 'stop_loss' assert stop_result['trades'] == 1 assert pytest.approx(stop_result['profit_mean']) == -0.1 assert stop_result['profit_mean_pct'] == round(stop_result['profit_mean'] * 100, 2) diff --git a/tests/plugins/test_protections.py b/tests/plugins/test_protections.py index 69c42c93d..023f46ef7 100644 --- a/tests/plugins/test_protections.py +++ b/tests/plugins/test_protections.py @@ -32,7 +32,7 @@ def generate_mock_trade(pair: str, fee: float, is_open: bool, trade.recalc_open_trade_value() if not is_open: trade.close(open_rate * profit_rate) - trade.sell_reason = sell_reason + trade.exit_reason = sell_reason return trade diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index 580ee5c84..8574abca8 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -66,6 +66,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None: 'open_trade_value': 0.0010025, 'close_rate_requested': ANY, 'sell_reason': ANY, + 'exit_reason': ANY, 'sell_order_status': ANY, 'min_rate': ANY, 'max_rate': ANY, @@ -148,6 +149,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None: 'open_trade_value': ANY, 'close_rate_requested': ANY, 'sell_reason': ANY, + 'exit_reason': ANY, 'sell_order_status': ANY, 'min_rate': ANY, 'max_rate': ANY, @@ -1044,7 +1046,7 @@ def test_sell_reason_performance_handle(default_conf, ticker, limit_buy_order, f assert res[0]['count'] == 1 assert prec_satoshi(res[0]['profit_pct'], 6.2) - trade.sell_reason = "TEST1" + trade.exit_reason = "TEST1" res = rpc._rpc_sell_reason_performance(None) assert len(res) == 1 @@ -1119,7 +1121,7 @@ def test_mix_tag_performance_handle(default_conf, ticker, limit_buy_order, fee, assert prec_satoshi(res[0]['profit_pct'], 6.2) trade.enter_tag = "TESTBUY" - trade.sell_reason = "TESTSELL" + trade.exit_reason = "TESTSELL" res = rpc._rpc_mix_tag_performance(None) assert len(res) == 1 diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 167f644c6..2bba122f6 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -822,14 +822,14 @@ def test_api_stats(botclient, mocker, ticker, fee, markets, is_short): rc = client_get(client, f"{BASE_URI}/stats") assert_response(rc, 200) assert 'durations' in rc.json() - assert 'sell_reasons' in rc.json() + assert 'exit_reasons' in rc.json() create_mock_trades(fee, is_short=is_short) rc = client_get(client, f"{BASE_URI}/stats") assert_response(rc, 200) assert 'durations' in rc.json() - assert 'sell_reasons' in rc.json() + assert 'exit_reasons' in rc.json() assert 'wins' in rc.json()['durations'] assert 'losses' in rc.json()['durations'] @@ -962,6 +962,7 @@ def test_api_status(botclient, mocker, ticker, fee, markets, is_short, 'open_rate_requested': ANY, 'open_trade_value': open_trade_value, 'sell_reason': None, + 'exit_reason': None, 'sell_order_status': None, 'strategy': CURRENT_TEST_STRATEGY, 'buy_tag': None, @@ -1162,6 +1163,7 @@ def test_api_forceentry(botclient, mocker, fee, endpoint): 'open_rate_requested': None, 'open_trade_value': 0.24605460, 'sell_reason': None, + 'exit_reason': None, 'sell_order_status': None, 'strategy': CURRENT_TEST_STRATEGY, 'buy_tag': None, diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index db93a6ec4..6dc146a99 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -837,7 +837,7 @@ def test_telegram_stats(default_conf, update, ticker, ticker_sell_up, fee, telegram._stats(update=update, context=MagicMock()) assert msg_mock.call_count == 1 - assert 'Sell Reason' in msg_mock.call_args_list[-1][0][0] + assert 'Exit Reason' in msg_mock.call_args_list[-1][0][0] assert 'ROI' in msg_mock.call_args_list[-1][0][0] assert 'Avg. Duration' in msg_mock.call_args_list[-1][0][0] msg_mock.reset_mock() @@ -1060,6 +1060,7 @@ def test_telegram_forcesell_handle(default_conf, update, ticker, fee, 'buy_tag': ANY, 'enter_tag': ANY, 'sell_reason': ExitType.FORCE_SELL.value, + 'exit_reason': ExitType.FORCE_SELL.value, 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, @@ -1128,6 +1129,7 @@ def test_telegram_forcesell_down_handle(default_conf, update, ticker, fee, 'buy_tag': ANY, 'enter_tag': ANY, 'sell_reason': ExitType.FORCE_SELL.value, + 'exit_reason': ExitType.FORCE_SELL.value, 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, @@ -1186,6 +1188,7 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None 'buy_tag': ANY, 'enter_tag': ANY, 'sell_reason': ExitType.FORCE_SELL.value, + 'exit_reason': ExitType.FORCE_SELL.value, 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, @@ -1393,7 +1396,7 @@ def test_telegram_sell_reason_performance_handle(default_conf, update, ticker, f freqtradebot.enter_positions() trade = Trade.query.first() assert trade - trade.sell_reason = 'TESTSELL' + trade.exit_reason = 'TESTSELL' # Simulate fulfilled LIMIT_BUY order for trade oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') trade.update_trade(oobj) @@ -1439,7 +1442,7 @@ def test_telegram_mix_tag_performance_handle(default_conf, update, ticker, fee, assert trade trade.enter_tag = "TESTBUY" - trade.sell_reason = "TESTSELL" + trade.exit_reason = "TESTSELL" # Simulate fulfilled LIMIT_BUY order for trade oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') @@ -1932,7 +1935,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None: 'stake_currency': 'ETH', 'fiat_currency': 'USD', 'enter_tag': 'buy_signal1', - 'sell_reason': ExitType.STOP_LOSS.value, + 'exit_reason': ExitType.STOP_LOSS.value, 'open_date': arrow.utcnow().shift(hours=-1), 'close_date': arrow.utcnow(), }) @@ -1966,7 +1969,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None: 'profit_ratio': -0.57405275, 'stake_currency': 'ETH', 'enter_tag': 'buy_signal1', - 'sell_reason': ExitType.STOP_LOSS.value, + 'exit_reason': ExitType.STOP_LOSS.value, 'open_date': arrow.utcnow().shift(days=-1, hours=-2, minutes=-30), 'close_date': arrow.utcnow(), }) @@ -2045,7 +2048,7 @@ def test_send_msg_sell_fill_notification(default_conf, mocker, direction, 'profit_ratio': -0.57405275, 'stake_currency': 'ETH', 'enter_tag': enter_signal, - 'sell_reason': ExitType.STOP_LOSS.value, + 'exit_reason': ExitType.STOP_LOSS.value, 'open_date': arrow.utcnow().shift(days=-1, hours=-2, minutes=-30), 'close_date': arrow.utcnow(), }) @@ -2169,7 +2172,7 @@ def test_send_msg_sell_notification_no_fiat( 'stake_currency': 'ETH', 'fiat_currency': 'USD', 'enter_tag': enter_signal, - 'sell_reason': ExitType.STOP_LOSS.value, + 'exit_reason': ExitType.STOP_LOSS.value, 'open_date': arrow.utcnow().shift(hours=-2, minutes=-35, seconds=-3), 'close_date': arrow.utcnow(), }) @@ -2191,13 +2194,13 @@ def test_send_msg_sell_notification_no_fiat( @pytest.mark.parametrize('msg,expected', [ - ({'profit_percent': 20.1, 'sell_reason': 'roi'}, "\N{ROCKET}"), - ({'profit_percent': 5.1, 'sell_reason': 'roi'}, "\N{ROCKET}"), - ({'profit_percent': 2.56, 'sell_reason': 'roi'}, "\N{EIGHT SPOKED ASTERISK}"), - ({'profit_percent': 1.0, 'sell_reason': 'roi'}, "\N{EIGHT SPOKED ASTERISK}"), - ({'profit_percent': 0.0, 'sell_reason': 'roi'}, "\N{EIGHT SPOKED ASTERISK}"), - ({'profit_percent': -5.0, 'sell_reason': 'stop_loss'}, "\N{WARNING SIGN}"), - ({'profit_percent': -2.0, 'sell_reason': 'sell_signal'}, "\N{CROSS MARK}"), + ({'profit_percent': 20.1, 'exit_reason': 'roi'}, "\N{ROCKET}"), + ({'profit_percent': 5.1, 'exit_reason': 'roi'}, "\N{ROCKET}"), + ({'profit_percent': 2.56, 'exit_reason': 'roi'}, "\N{EIGHT SPOKED ASTERISK}"), + ({'profit_percent': 1.0, 'exit_reason': 'roi'}, "\N{EIGHT SPOKED ASTERISK}"), + ({'profit_percent': 0.0, 'exit_reason': 'roi'}, "\N{EIGHT SPOKED ASTERISK}"), + ({'profit_percent': -5.0, 'exit_reason': 'stop_loss'}, "\N{WARNING SIGN}"), + ({'profit_percent': -2.0, 'exit_reason': 'sell_signal'}, "\N{CROSS MARK}"), ]) def test__sell_emoji(default_conf, mocker, msg, expected): del default_conf['fiat_display_currency'] diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 8de94d249..111286324 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -236,7 +236,7 @@ def test_edge_overrides_stoploss(limit_order, fee, caplog, mocker, assert freqtrade.handle_trade(trade) is not ignore_strat_sl if not ignore_strat_sl: assert log_has_re('Exit for NEO/BTC detected. Reason: stop_loss.*', caplog) - assert trade.sell_reason == ExitType.STOP_LOSS.value + assert trade.exit_reason == ExitType.STOP_LOSS.value def test_total_open_trades_stakes(mocker, default_conf_usdt, ticker_usdt, fee) -> None: @@ -1208,7 +1208,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_ assert freqtrade.handle_stoploss_on_exchange(trade) is False assert trade.stoploss_order_id is None assert trade.is_open is False - assert trade.sell_reason == str(ExitType.EMERGENCY_SELL) + assert trade.exit_reason == str(ExitType.EMERGENCY_SELL) @pytest.mark.parametrize("is_short", [False, True]) @@ -1291,7 +1291,7 @@ def test_create_stoploss_order_invalid_order( caplog.clear() freqtrade.create_stoploss_order(trade, 200) assert trade.stoploss_order_id is None - assert trade.sell_reason == ExitType.EMERGENCY_SELL.value + assert trade.exit_reason == ExitType.EMERGENCY_SELL.value assert log_has("Unable to place a stoploss order on exchange. ", caplog) assert log_has("Exiting the trade forcefully", caplog) @@ -2150,7 +2150,7 @@ def test_handle_trade( assert trade.close_profit == close_profit assert trade.calc_profit() == 5.685 assert trade.close_date is not None - assert trade.sell_reason == 'sell_signal1' + assert trade.exit_reason == 'sell_signal1' @pytest.mark.parametrize("is_short", [False, True]) @@ -2995,7 +2995,7 @@ def test_handle_cancel_exit_limit(mocker, default_conf_usdt, fee) -> None: assert cancel_order_mock.call_count == 1 assert send_msg_mock.call_count == 1 assert trade.close_rate is None - assert trade.sell_reason is None + assert trade.exit_reason is None send_msg_mock.reset_mock() @@ -3107,6 +3107,7 @@ def test_execute_trade_exit_up(default_conf_usdt, ticker_usdt, fee, ticker_usdt_ 'stake_currency': 'USDT', 'fiat_currency': 'USD', 'sell_reason': ExitType.ROI.value, + 'exit_reason': ExitType.ROI.value, 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, @@ -3166,6 +3167,7 @@ def test_execute_trade_exit_down(default_conf_usdt, ticker_usdt, fee, ticker_usd 'stake_currency': 'USDT', 'fiat_currency': 'USD', 'sell_reason': ExitType.STOP_LOSS.value, + 'exit_reason': ExitType.STOP_LOSS.value, 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, @@ -3246,6 +3248,7 @@ def test_execute_trade_exit_custom_exit_price( 'stake_currency': 'USDT', 'fiat_currency': 'USD', 'sell_reason': ExitType.SELL_SIGNAL.value, + 'exit_reason': ExitType.SELL_SIGNAL.value, 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, @@ -3313,6 +3316,7 @@ def test_execute_trade_exit_down_stoploss_on_exchange_dry_run( 'stake_currency': 'USDT', 'fiat_currency': 'USD', 'sell_reason': ExitType.STOP_LOSS.value, + 'exit_reason': ExitType.STOP_LOSS.value, 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, @@ -3479,7 +3483,7 @@ def test_may_execute_trade_exit_after_stoploss_on_exchange_hit( freqtrade.exit_positions(trades) assert trade.stoploss_order_id is None assert trade.is_open is False - assert trade.sell_reason == ExitType.STOPLOSS_ON_EXCHANGE.value + assert trade.exit_reason == ExitType.STOPLOSS_ON_EXCHANGE.value assert rpc_mock.call_count == 3 if is_short: assert rpc_mock.call_args_list[0][0][0]['type'] == RPCMessageType.SHORT @@ -3576,6 +3580,7 @@ def test_execute_trade_exit_market_order( 'stake_currency': 'USDT', 'fiat_currency': 'USD', 'sell_reason': ExitType.ROI.value, + 'exit_reason': ExitType.ROI.value, 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, @@ -3843,7 +3848,7 @@ def test_ignore_roi_if_buy_signal(default_conf_usdt, limit_order, limit_order_op else: patch_get_signal(freqtrade, enter_long=False, exit_long=False) assert freqtrade.handle_trade(trade) is True - assert trade.sell_reason == ExitType.ROI.value + assert trade.exit_reason == ExitType.ROI.value @pytest.mark.parametrize("is_short,val1,val2", [ @@ -3905,7 +3910,7 @@ def test_trailing_stop_loss(default_conf_usdt, limit_order_open, f"stoploss is {(2.0 * val1 * stop_multi):6f}, " f"initial stoploss was at {(2.0 * stop_multi):6f}, trade opened at 2.000000", caplog) - assert trade.sell_reason == ExitType.TRAILING_STOP_LOSS.value + assert trade.exit_reason == ExitType.TRAILING_STOP_LOSS.value @pytest.mark.parametrize('offset,trail_if_reached,second_sl,is_short', [ @@ -4011,7 +4016,7 @@ def test_trailing_stop_loss_positive( f"initial stoploss was at {'2.42' if is_short else '1.80'}0000, " f"trade opened at {2.2 if is_short else 2.0}00000", caplog) - assert trade.sell_reason == ExitType.TRAILING_STOP_LOSS.value + assert trade.exit_reason == ExitType.TRAILING_STOP_LOSS.value @pytest.mark.parametrize("is_short", [False, True]) @@ -4057,7 +4062,7 @@ def test_disable_ignore_roi_if_buy_signal(default_conf_usdt, limit_order, limit_ # Test if entry-signal is absent patch_get_signal(freqtrade) assert freqtrade.handle_trade(trade) is True - assert trade.sell_reason == ExitType.ROI.value + assert trade.exit_reason == ExitType.ROI.value def test_get_real_amount_quote(default_conf_usdt, trades_for_order, buy_order_fee, fee, caplog, diff --git a/tests/test_integration.py b/tests/test_integration.py index d1fac3d71..9b689f2eb 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -115,15 +115,15 @@ def test_may_execute_exit_stoploss_on_exchange_multi(default_conf, ticker, fee, assert wallets_mock.call_count == 4 trade = trades[0] - assert trade.sell_reason == ExitType.STOPLOSS_ON_EXCHANGE.value + assert trade.exit_reason == ExitType.STOPLOSS_ON_EXCHANGE.value assert not trade.is_open trade = trades[1] - assert not trade.sell_reason + assert not trade.exit_reason assert trade.is_open trade = trades[2] - assert trade.sell_reason == ExitType.SELL_SIGNAL.value + assert trade.exit_reason == ExitType.SELL_SIGNAL.value assert not trade.is_open diff --git a/tests/test_persistence.py b/tests/test_persistence.py index 61aaf0fb7..1c1daf75b 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -1255,7 +1255,7 @@ def test_migrate_new(mocker, default_conf, fee, caplog): assert trade.min_rate is None assert trade.stop_loss == 0.0 assert trade.initial_stop_loss == 0.0 - assert trade.sell_reason is None + assert trade.exit_reason is None assert trade.strategy is None assert trade.timeframe == '5m' assert trade.stoploss_order_id == 'stop_order_id222' @@ -1590,6 +1590,7 @@ def test_to_json(fee): 'profit_pct': None, 'profit_abs': None, 'sell_reason': None, + 'exit_reason': None, 'sell_order_status': None, 'stop_loss_abs': None, 'stop_loss_ratio': None, @@ -1676,6 +1677,7 @@ def test_to_json(fee): 'open_rate_requested': None, 'open_trade_value': 12.33075, 'sell_reason': None, + 'exit_reason': None, 'sell_order_status': None, 'strategy': None, 'buy_tag': 'buys_signal_001',