diff --git a/freqtrade/edge/edge_positioning.py b/freqtrade/edge/edge_positioning.py index b2f4534f1..ab72f9da3 100644 --- a/freqtrade/edge/edge_positioning.py +++ b/freqtrade/edge/edge_positioning.py @@ -13,7 +13,7 @@ from pandas import DataFrame from freqtrade.configuration import TimeRange from freqtrade.constants import DATETIME_PRINT_FORMAT, UNLIMITED_STAKE_AMOUNT from freqtrade.data.history import get_timerange, load_data, refresh_data -from freqtrade.enums import RunMode, SellType +from freqtrade.enums import RunMode, ExitType from freqtrade.exceptions import OperationalException from freqtrade.exchange.exchange import timeframe_to_seconds from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist @@ -454,7 +454,7 @@ class Edge: if stop_index <= sell_index: exit_index = open_trade_index + stop_index - exit_type = SellType.STOP_LOSS + exit_type = ExitType.STOP_LOSS exit_price = stop_price elif stop_index > sell_index: # If exit is SELL then we exit at the next candle @@ -464,7 +464,7 @@ class Edge: if len(ohlc_columns) - 1 < exit_index: break - exit_type = SellType.SELL_SIGNAL + exit_type = ExitType.SELL_SIGNAL exit_price = ohlc_columns[exit_index, 0] trade = {'pair': pair, diff --git a/freqtrade/enums/__init__.py b/freqtrade/enums/__init__.py index 4eb0ce307..885bcfa7f 100644 --- a/freqtrade/enums/__init__.py +++ b/freqtrade/enums/__init__.py @@ -5,7 +5,7 @@ from freqtrade.enums.collateral import Collateral from freqtrade.enums.ordertypevalue import OrderTypeValues from freqtrade.enums.rpcmessagetype import RPCMessageType from freqtrade.enums.runmode import NON_UTIL_MODES, OPTIMIZE_MODES, TRADING_MODES, RunMode -from freqtrade.enums.selltype import SellType +from freqtrade.enums.exittype import ExitType from freqtrade.enums.signaltype import SignalDirection, SignalTagType, SignalType from freqtrade.enums.state import State from freqtrade.enums.tradingmode import TradingMode diff --git a/freqtrade/enums/selltype.py b/freqtrade/enums/exittype.py similarity index 95% rename from freqtrade/enums/selltype.py rename to freqtrade/enums/exittype.py index 015c30186..36d2a4f9e 100644 --- a/freqtrade/enums/selltype.py +++ b/freqtrade/enums/exittype.py @@ -1,7 +1,7 @@ from enum import Enum -class SellType(Enum): +class ExitType(Enum): """ Enum to distinguish between sell reasons """ diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index e8380fae6..06e556246 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -17,7 +17,7 @@ from freqtrade.configuration import validate_config_consistency from freqtrade.data.converter import order_book_to_dataframe from freqtrade.data.dataprovider import DataProvider from freqtrade.edge import Edge -from freqtrade.enums import (Collateral, RPCMessageType, SellType, SignalDirection, State, +from freqtrade.enums import (Collateral, RPCMessageType, ExitType, SignalDirection, State, TradingMode) from freqtrade.exceptions import (DependencyException, ExchangeError, InsufficientFundsError, InvalidOrderException, PricingError) @@ -915,7 +915,7 @@ class FreqtradeBot(LoggingMixin): logger.error(f'Unable to place a stoploss order on exchange. {e}') logger.warning('Exiting the trade forcefully') self.execute_trade_exit(trade, trade.stop_loss, exit_reason=SellCheckTuple( - sell_type=SellType.EMERGENCY_SELL)) + sell_type=ExitType.EMERGENCY_SELL)) except ExchangeError: trade.stoploss_order_id = None @@ -947,7 +947,7 @@ class FreqtradeBot(LoggingMixin): # We check if stoploss order is fulfilled if stoploss_order and stoploss_order['status'] in ('closed', 'triggered'): # TODO-lev: Update to exit reason - trade.exit_reason = SellType.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 @@ -1102,7 +1102,7 @@ class FreqtradeBot(LoggingMixin): try: self.execute_trade_exit( trade, order.get('price'), - exit_reason=SellCheckTuple(sell_type=SellType.EMERGENCY_SELL)) + exit_reason=SellCheckTuple(sell_type=ExitType.EMERGENCY_SELL)) except DependencyException as exception: logger.warning( f'Unable to emergency sell trade {trade.pair}: {exception}') @@ -1284,7 +1284,7 @@ class FreqtradeBot(LoggingMixin): trade.open_date ) exit_type = 'sell' # TODO-lev: Update to exit - if exit_reason.sell_type in (SellType.STOP_LOSS, SellType.TRAILING_STOP_LOSS): + if exit_reason.sell_type in (ExitType.STOP_LOSS, ExitType.TRAILING_STOP_LOSS): exit_type = 'stoploss' # if stoploss is on exchange and we are on dry_run mode, @@ -1314,7 +1314,7 @@ class FreqtradeBot(LoggingMixin): logger.exception(f"Could not cancel stoploss order {trade.stoploss_order_id}") order_type = ordertype or self.strategy.order_types[exit_type] - if exit_reason.sell_type == SellType.EMERGENCY_SELL: + if exit_reason.sell_type == ExitType.EMERGENCY_SELL: # Emergency sells (default to market!) order_type = self.strategy.order_types.get("emergencysell", "market") diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index dc2b94e1a..53fba9a82 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -17,7 +17,7 @@ from freqtrade.data import history from freqtrade.data.btanalysis import trade_list_to_dataframe from freqtrade.data.converter import trim_dataframe, trim_dataframes from freqtrade.data.dataprovider import DataProvider -from freqtrade.enums import BacktestState, CandleType, SellType, TradingMode +from freqtrade.enums import BacktestState, CandleType, ExitType, TradingMode from freqtrade.exceptions import DependencyException, OperationalException from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds from freqtrade.mixins import LoggingMixin @@ -314,7 +314,7 @@ class Backtesting: Get close rate for backtesting result """ # Special handling if high or low hit STOP_LOSS or ROI - if sell.sell_type in (SellType.STOP_LOSS, SellType.TRAILING_STOP_LOSS): + if sell.sell_type in (ExitType.STOP_LOSS, ExitType.TRAILING_STOP_LOSS): if trade.stop_loss > sell_row[HIGH_IDX]: # our stoploss was already higher than candle high, # possibly due to a cancelled trade exit. @@ -324,7 +324,7 @@ class Backtesting: # Special case: trailing triggers within same candle as trade opened. Assume most # pessimistic price movement, which is moving just enough to arm stoploss and # immediately going down to stop price. - if sell.sell_type == SellType.TRAILING_STOP_LOSS and trade_dur == 0: + if sell.sell_type == ExitType.TRAILING_STOP_LOSS and trade_dur == 0: if ( not self.strategy.use_custom_stoploss and self.strategy.trailing_stop and self.strategy.trailing_only_offset_is_reached @@ -345,7 +345,7 @@ class Backtesting: # Set close_rate to stoploss return trade.stop_loss - elif sell.sell_type == (SellType.ROI): + elif sell.sell_type == (ExitType.ROI): roi_entry, roi = self.strategy.min_roi_reached_entry(trade_dur) if roi is not None and roi_entry is not None: if roi == -1 and roi_entry % self.timeframe_min == 0: @@ -395,7 +395,7 @@ class Backtesting: closerate = self._get_close_rate(sell_row, trade, sell, trade_dur) # call the custom exit price,with default value as previous closerate current_profit = trade.calc_profit_ratio(closerate) - if sell.sell_type in (SellType.SELL_SIGNAL, SellType.CUSTOM_SELL): + if sell.sell_type in (ExitType.SELL_SIGNAL, ExitType.CUSTOM_SELL): # Custom exit pricing only for sell-signals closerate = strategy_safe_wrapper(self.strategy.custom_exit_price, default_retval=closerate)( @@ -542,7 +542,7 @@ class Backtesting: sell_row = data[pair][-1] trade.close_date = sell_row[DATE_IDX].to_pydatetime() - trade.exit_reason = SellType.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/persistence/models.py b/freqtrade/persistence/models.py index d070e068f..a1a9199fb 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -14,7 +14,7 @@ from sqlalchemy.pool import StaticPool from sqlalchemy.sql.schema import UniqueConstraint from freqtrade.constants import DATETIME_PRINT_FORMAT, NON_OPEN_EXCHANGE_STATES -from freqtrade.enums import SellType, TradingMode +from freqtrade.enums import ExitType, TradingMode from freqtrade.exceptions import DependencyException, OperationalException from freqtrade.leverage import interest from freqtrade.misc import safe_value_fallback @@ -575,7 +575,7 @@ class LocalTrade(): elif order_type in ('stop_loss_limit', 'stop-loss', 'stop-loss-limit', 'stop'): self.stoploss_order_id = None self.close_rate_requested = self.stop_loss - self.exit_reason = SellType.STOPLOSS_ON_EXCHANGE.value + self.exit_reason = ExitType.STOPLOSS_ON_EXCHANGE.value if self.is_open: logger.info(f'{order_type.upper()} is hit for {self}.') self.close(safe_value_fallback(order, 'average', 'price')) diff --git a/freqtrade/plugins/protections/stoploss_guard.py b/freqtrade/plugins/protections/stoploss_guard.py index 567fd9fcc..eba4d50fe 100644 --- a/freqtrade/plugins/protections/stoploss_guard.py +++ b/freqtrade/plugins/protections/stoploss_guard.py @@ -3,7 +3,7 @@ import logging from datetime import datetime, timedelta from typing import Any, Dict -from freqtrade.enums import SellType +from freqtrade.enums import ExitType from freqtrade.persistence import Trade from freqtrade.plugins.protections import IProtection, ProtectionReturn @@ -44,8 +44,8 @@ class StoplossGuard(IProtection): # filters = [ # Trade.is_open.is_(False), # Trade.close_date > look_back_until, - # or_(Trade.exit_reason == SellType.STOP_LOSS.value, - # and_(Trade.exit_reason == SellType.TRAILING_STOP_LOSS.value, + # or_(Trade.exit_reason == ExitType.STOP_LOSS.value, + # and_(Trade.exit_reason == ExitType.TRAILING_STOP_LOSS.value, # Trade.close_profit < 0)) # ] # if pair: @@ -55,8 +55,8 @@ class StoplossGuard(IProtection): trades1 = Trade.get_trades_proxy(pair=pair, is_open=False, close_date=look_back_until) trades = [trade for trade in trades1 if (str(trade.exit_reason) in ( - SellType.TRAILING_STOP_LOSS.value, SellType.STOP_LOSS.value, - SellType.STOPLOSS_ON_EXCHANGE.value) + ExitType.TRAILING_STOP_LOSS.value, ExitType.STOP_LOSS.value, + ExitType.STOPLOSS_ON_EXCHANGE.value) and trade.close_profit and trade.close_profit < 0)] if len(trades) < self._trade_limit: diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 0b2ea3bbc..0d99b19b3 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -17,7 +17,7 @@ from freqtrade import __version__ from freqtrade.configuration.timerange import TimeRange from freqtrade.constants import CANCEL_REASON, DATETIME_PRINT_FORMAT from freqtrade.data.history import load_data -from freqtrade.enums import SellType, State +from freqtrade.enums import ExitType, State from freqtrade.exceptions import ExchangeError, PricingError from freqtrade.exchange import timeframe_to_minutes, timeframe_to_msecs from freqtrade.loggers import bufferHandler @@ -672,7 +672,7 @@ class RPC: closing_side = "buy" if trade.is_short else "sell" current_rate = self._freqtrade.exchange.get_rate( trade.pair, refresh=False, side=closing_side) - exit_reason = SellCheckTuple(sell_type=SellType.FORCE_SELL) + exit_reason = SellCheckTuple(sell_type=ExitType.FORCE_SELL) order_type = ordertype or self._freqtrade.strategy.order_types.get( "forcesell", self._freqtrade.strategy.order_types["sell"]) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 5eaf69840..ba3e95b77 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -13,7 +13,7 @@ from pandas import DataFrame from freqtrade.constants import ListPairsWithTimeframes from freqtrade.data.dataprovider import DataProvider -from freqtrade.enums import CandleType, SellType, SignalDirection, SignalTagType, SignalType +from freqtrade.enums import CandleType, ExitType, SignalDirection, SignalTagType, SignalType from freqtrade.exceptions import OperationalException, StrategyError from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds from freqtrade.exchange.exchange import timeframe_to_next_date @@ -34,16 +34,16 @@ class SellCheckTuple: """ NamedTuple for Sell type + reason """ - sell_type: SellType + sell_type: ExitType exit_reason: str = '' - def __init__(self, sell_type: SellType, exit_reason: str = ''): + def __init__(self, sell_type: ExitType, exit_reason: str = ''): self.sell_type = sell_type self.exit_reason = exit_reason or sell_type.value @property def sell_flag(self): - return self.sell_type != SellType.NONE + return self.sell_type != ExitType.NONE class IStrategy(ABC, HyperStrategyMixin): @@ -784,7 +784,7 @@ class IStrategy(ABC, HyperStrategyMixin): and self.min_roi_reached(trade=trade, current_profit=current_profit, current_time=date)) - sell_signal = SellType.NONE + sell_signal = ExitType.NONE custom_reason = '' # use provided rate in backtesting, not high/low. current_rate = rate @@ -795,14 +795,14 @@ class IStrategy(ABC, HyperStrategyMixin): pass elif self.use_exit_signal and not enter: if exit_: - sell_signal = SellType.SELL_SIGNAL + sell_signal = ExitType.SELL_SIGNAL else: trade_type = "exit_short" if trade.is_short else "sell" custom_reason = strategy_safe_wrapper(self.custom_sell, default_retval=False)( pair=trade.pair, trade=trade, current_time=date, current_rate=current_rate, current_profit=current_profit) if custom_reason: - sell_signal = SellType.CUSTOM_SELL + sell_signal = ExitType.CUSTOM_SELL if isinstance(custom_reason, str): if len(custom_reason) > CUSTOM_SELL_MAX_LENGTH: logger.warning(f'Custom {trade_type} reason returned from ' @@ -811,9 +811,9 @@ class IStrategy(ABC, HyperStrategyMixin): custom_reason = custom_reason[:CUSTOM_SELL_MAX_LENGTH] else: custom_reason = None - if sell_signal in (SellType.CUSTOM_SELL, SellType.SELL_SIGNAL): + if sell_signal in (ExitType.CUSTOM_SELL, ExitType.SELL_SIGNAL): logger.debug(f"{trade.pair} - Sell signal received. " - f"sell_type=SellType.{sell_signal.name}" + + f"sell_type=ExitType.{sell_signal.name}" + (f", custom_reason={custom_reason}" if custom_reason else "")) return SellCheckTuple(sell_type=sell_signal, exit_reason=custom_reason) @@ -821,9 +821,9 @@ class IStrategy(ABC, HyperStrategyMixin): # Exit-signal # ROI (if not stoploss) # Stoploss - if roi_reached and stoplossflag.sell_type != SellType.STOP_LOSS: - logger.debug(f"{trade.pair} - Required profit reached. sell_type=SellType.ROI") - return SellCheckTuple(sell_type=SellType.ROI) + if roi_reached and stoplossflag.sell_type != ExitType.STOP_LOSS: + logger.debug(f"{trade.pair} - Required profit reached. sell_type=ExitType.ROI") + return SellCheckTuple(sell_type=ExitType.ROI) if stoplossflag.sell_flag: @@ -832,7 +832,7 @@ class IStrategy(ABC, HyperStrategyMixin): # This one is noisy, commented out... # logger.debug(f"{trade.pair} - No exit signal.") - return SellCheckTuple(sell_type=SellType.NONE) + return SellCheckTuple(sell_type=ExitType.NONE) def stop_loss_reached(self, current_rate: float, trade: Trade, current_time: datetime, current_profit: float, @@ -896,11 +896,11 @@ class IStrategy(ABC, HyperStrategyMixin): if ((sl_higher_short or sl_lower_long) and (not self.order_types.get('stoploss_on_exchange') or self.config['dry_run'])): - sell_type = SellType.STOP_LOSS + sell_type = ExitType.STOP_LOSS # If initial stoploss is not the same as current one then it is trailing. if trade.initial_stop_loss != trade.stop_loss: - sell_type = SellType.TRAILING_STOP_LOSS + sell_type = ExitType.TRAILING_STOP_LOSS logger.debug( f"{trade.pair} - HIT STOP: current price at " f"{((high if trade.is_short else low) or current_rate):.6f}, " @@ -917,7 +917,7 @@ class IStrategy(ABC, HyperStrategyMixin): return SellCheckTuple(sell_type=sell_type) - return SellCheckTuple(sell_type=SellType.NONE) + return SellCheckTuple(sell_type=ExitType.NONE) def min_roi_reached_entry(self, trade_dur: int) -> Tuple[Optional[int], Optional[float]]: """ diff --git a/tests/edge/test_edge.py b/tests/edge/test_edge.py index 5c6d1d3ad..76005c734 100644 --- a/tests/edge/test_edge.py +++ b/tests/edge/test_edge.py @@ -12,7 +12,7 @@ from pandas import DataFrame, to_datetime from freqtrade.data.converter import ohlcv_to_dataframe from freqtrade.edge import Edge, PairInfo -from freqtrade.enums import SellType +from freqtrade.enums import ExitType from freqtrade.exceptions import OperationalException from tests.conftest import get_patched_freqtradebot, log_has from tests.optimize import (BTContainer, BTrade, _build_backtest_dataframe, @@ -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(exit_reason=SellType.SELL_SIGNAL, open_tick=1, close_tick=2), - BTrade(exit_reason=SellType.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(exit_reason=SellType.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(exit_reason=SellType.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(exit_reason=SellType.STOP_LOSS, open_tick=1, close_tick=1)] + trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1)] ) TESTS = [ diff --git a/tests/optimize/__init__.py b/tests/optimize/__init__.py index 4b62eabfd..369c9b135 100644 --- a/tests/optimize/__init__.py +++ b/tests/optimize/__init__.py @@ -3,7 +3,7 @@ from typing import Dict, List, NamedTuple, Optional import arrow from pandas import DataFrame -from freqtrade.enums import SellType +from freqtrade.enums import ExitType from freqtrade.exchange import timeframe_to_minutes @@ -15,7 +15,7 @@ class BTrade(NamedTuple): """ Minimalistic Trade result used for functional backtesting """ - exit_reason: SellType + exit_reason: ExitType open_tick: int close_tick: int enter_tag: Optional[str] = None diff --git a/tests/optimize/conftest.py b/tests/optimize/conftest.py index 6609335d0..46bfddcc2 100644 --- a/tests/optimize/conftest.py +++ b/tests/optimize/conftest.py @@ -5,7 +5,7 @@ from pathlib import Path import pandas as pd import pytest -from freqtrade.enums import RunMode, SellType +from freqtrade.enums import RunMode, ExitType from freqtrade.optimize.hyperopt import Hyperopt from tests.conftest import patch_exchange @@ -44,7 +44,7 @@ def hyperopt_results(): 'profit_abs': [-0.2, 0.4, -0.2, 0.6], 'trade_duration': [10, 30, 10, 10], 'amount': [0.1, 0.1, 0.1, 0.1], - 'exit_reason': [SellType.STOP_LOSS, SellType.ROI, SellType.STOP_LOSS, SellType.ROI], + 'exit_reason': [ExitType.STOP_LOSS, ExitType.ROI, ExitType.STOP_LOSS, ExitType.ROI], 'open_date': [ datetime(2019, 1, 1, 9, 15, 0), diff --git a/tests/optimize/test_backtest_detail.py b/tests/optimize/test_backtest_detail.py index 7bf08217e..a942a4f73 100644 --- a/tests/optimize/test_backtest_detail.py +++ b/tests/optimize/test_backtest_detail.py @@ -4,7 +4,7 @@ import logging import pytest from freqtrade.data.history import get_timerange -from freqtrade.enums import SellType +from freqtrade.enums import ExitType from freqtrade.optimize.backtesting import Backtesting from tests.conftest import patch_exchange from tests.optimize import (BTContainer, BTrade, _build_backtest_dataframe, @@ -22,7 +22,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_exit_signal=True, - trades=[BTrade(exit_reason=SellType.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 @@ -36,7 +36,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(exit_reason=SellType.STOP_LOSS, open_tick=1, close_tick=2)] + trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=2)] ) @@ -51,7 +51,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(exit_reason=SellType.STOP_LOSS, open_tick=1, close_tick=3)] + trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=3)] ) @@ -71,8 +71,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(exit_reason=SellType.STOP_LOSS, open_tick=1, close_tick=2), - BTrade(exit_reason=SellType.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% @@ -88,7 +88,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(exit_reason=SellType.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 @@ -102,7 +102,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(exit_reason=SellType.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 @@ -116,7 +116,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(exit_reason=SellType.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 @@ -130,7 +130,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(exit_reason=SellType.ROI, open_tick=1, close_tick=2)] + trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=2)] ) @@ -144,7 +144,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(exit_reason=SellType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)] + trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)] ) @@ -158,7 +158,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(exit_reason=SellType.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 @@ -174,7 +174,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(exit_reason=SellType.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 @@ -190,7 +190,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(exit_reason=SellType.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 @@ -206,7 +206,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(exit_reason=SellType.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 @@ -219,7 +219,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(exit_reason=SellType.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 @@ -232,7 +232,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(exit_reason=SellType.STOP_LOSS, open_tick=1, close_tick=1)] + trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1)] ) @@ -246,8 +246,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(exit_reason=SellType.ROI, open_tick=1, close_tick=1), - BTrade(exit_reason=SellType.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 @@ -262,7 +262,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(exit_reason=SellType.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 @@ -278,7 +278,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(exit_reason=SellType.ROI, open_tick=1, close_tick=3)] + trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)] ) @@ -294,7 +294,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(exit_reason=SellType.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. @@ -309,7 +309,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(exit_reason=SellType.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. @@ -324,7 +324,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(exit_reason=SellType.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. @@ -341,7 +341,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(exit_reason=SellType.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. @@ -357,7 +357,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(exit_reason=SellType.ROI, open_tick=1, close_tick=2)] + trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=2)] ) # Test 23: trailing_stop Raises in candle 2 (does not trigger) @@ -376,7 +376,7 @@ tc23 = 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(exit_reason=SellType.ROI, open_tick=1, close_tick=3)] + trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)] ) # Test 24: Sell with signal sell in candle 3 (stoploss also triggers on this candle) @@ -391,7 +391,7 @@ tc24 = 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_exit_signal=True, - trades=[BTrade(exit_reason=SellType.STOP_LOSS, open_tick=1, close_tick=3)] + trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=3)] ) # Test 25: Sell with signal sell in candle 3 (stoploss also triggers on this candle) @@ -406,7 +406,7 @@ tc25 = 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_exit_signal=True, - trades=[BTrade(exit_reason=SellType.SELL_SIGNAL, open_tick=1, close_tick=4)] + trades=[BTrade(exit_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=4)] ) # Test 26: Sell with signal sell in candle 3 (ROI at signal candle) @@ -421,7 +421,7 @@ tc26 = 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_exit_signal=True, - trades=[BTrade(exit_reason=SellType.ROI, open_tick=1, close_tick=3)] + trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)] ) # Test 27: Sell with signal sell in candle 3 (ROI at signal candle) @@ -435,7 +435,7 @@ tc27 = 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_exit_signal=True, - trades=[BTrade(exit_reason=SellType.SELL_SIGNAL, open_tick=1, close_tick=4)] + trades=[BTrade(exit_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=4)] ) # Test 28: trailing_stop should raise so candle 3 causes a stoploss @@ -452,7 +452,7 @@ tc28 = 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(exit_reason=SellType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)] + trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)] ) # Test 29: trailing_stop should be triggered by low of next candle, without adjusting stoploss using @@ -467,7 +467,7 @@ tc29 = 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(exit_reason=SellType.TRAILING_STOP_LOSS, open_tick=1, close_tick=2)] + trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=2)] ) # Test 30: trailing_stop should be triggered immediately on trade open candle. @@ -481,7 +481,7 @@ tc30 = 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(exit_reason=SellType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)] + trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)] ) # Test 31: trailing_stop should be triggered immediately on trade open candle. @@ -496,7 +496,7 @@ tc31 = 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(exit_reason=SellType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)] + trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)] ) # Test 32: trailing_stop should be triggered immediately on trade open candle. @@ -511,7 +511,7 @@ tc32 = 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(exit_reason=SellType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)] + trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)] ) # Test 33: trailing_stop should be triggered immediately on trade open candle. @@ -527,7 +527,7 @@ tc33 = 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( - exit_reason=SellType.TRAILING_STOP_LOSS, + exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1, enter_tag='buy_signal_01' @@ -548,7 +548,7 @@ tc34 = BTContainer(data=[ [5, 4995, 4995, 4950, 4950, 6172, 0, 0]], stop_loss=-0.01, roi={"0": 1}, profit_perc=0.002 * 5.0, use_exit_signal=True, leverage=5.0, - trades=[BTrade(exit_reason=SellType.SELL_SIGNAL, open_tick=1, close_tick=4)] + trades=[BTrade(exit_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=4)] ) TESTS = [ diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index 781c2b126..4629f0ec6 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -18,7 +18,7 @@ from freqtrade.data.btanalysis import BT_DATA_COLUMNS, evaluate_result_multi from freqtrade.data.converter import clean_ohlcv_dataframe from freqtrade.data.dataprovider import DataProvider from freqtrade.data.history import get_timerange -from freqtrade.enums import RunMode, SellType +from freqtrade.enums import RunMode, ExitType from freqtrade.exceptions import DependencyException, OperationalException from freqtrade.optimize.backtesting import Backtesting from freqtrade.persistence import LocalTrade @@ -628,7 +628,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.exit_reason == SellType.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 @@ -647,7 +647,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.exit_reason == SellType.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) assert round(res.close_rate, 3) == round(209.0225, 3) @@ -693,7 +693,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], - 'exit_reason': [SellType.ROI.value, SellType.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], @@ -1081,7 +1081,7 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat 'close_rate': [0.104969, 0.103541], "is_short": [False, False], - 'exit_reason': [SellType.ROI, SellType.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], @@ -1099,7 +1099,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], - 'exit_reason': [SellType.ROI, SellType.ROI, SellType.STOP_LOSS] + 'exit_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS] }) backtestmock = MagicMock(side_effect=[ { @@ -1192,7 +1192,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], - 'exit_reason': [SellType.ROI, SellType.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], @@ -1210,7 +1210,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], - 'exit_reason': [SellType.ROI, SellType.ROI, SellType.STOP_LOSS] + 'exit_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS] }) backtestmock = MagicMock(side_effect=[ { diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index 98582eb82..b93f5a0e9 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -10,7 +10,7 @@ from filelock import Timeout from freqtrade.commands.optimize_commands import setup_optimize_configuration, start_hyperopt from freqtrade.data.history import load_data -from freqtrade.enums import RunMode, SellType +from freqtrade.enums import RunMode, ExitType from freqtrade.exceptions import OperationalException from freqtrade.optimize.hyperopt import Hyperopt from freqtrade.optimize.hyperopt_auto import HyperOptAuto @@ -359,8 +359,8 @@ 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], - "exit_reason": [SellType.ROI, SellType.STOP_LOSS, - SellType.ROI, SellType.FORCE_SELL] + "exit_reason": [ExitType.ROI, ExitType.STOP_LOSS, + ExitType.ROI, ExitType.FORCE_SELL] }), 'config': hyperopt.config, 'locks': [], @@ -428,8 +428,8 @@ 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], - "exit_reason": [SellType.ROI, SellType.STOP_LOSS, - SellType.ROI, SellType.FORCE_SELL] + "exit_reason": [ExitType.ROI, ExitType.STOP_LOSS, + ExitType.ROI, ExitType.FORCE_SELL] }), 'config': hyperopt_conf, 'locks': [], diff --git a/tests/optimize/test_optimize_reports.py b/tests/optimize/test_optimize_reports.py index 740193561..5cd3df3c6 100644 --- a/tests/optimize/test_optimize_reports.py +++ b/tests/optimize/test_optimize_reports.py @@ -13,7 +13,7 @@ from freqtrade.data import history from freqtrade.data.btanalysis import (get_latest_backtest_filename, load_backtest_data, load_backtest_stats) from freqtrade.edge import PairInfo -from freqtrade.enums import SellType +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, @@ -78,8 +78,8 @@ 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], - "exit_reason": [SellType.ROI, SellType.STOP_LOSS, - SellType.ROI, SellType.FORCE_SELL] + "exit_reason": [ExitType.ROI, ExitType.STOP_LOSS, + ExitType.ROI, ExitType.FORCE_SELL] }), 'config': default_conf, 'locks': [], @@ -127,8 +127,8 @@ 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], - "exit_reason": [SellType.ROI, SellType.ROI, - SellType.STOP_LOSS, SellType.FORCE_SELL] + "exit_reason": [ExitType.ROI, ExitType.ROI, + ExitType.STOP_LOSS, ExitType.FORCE_SELL] }), 'config': default_conf, 'locks': [], @@ -271,7 +271,7 @@ def test_text_table_exit_reason(): 'wins': [2, 0, 0], 'draws': [0, 0, 0], 'losses': [0, 0, 1], - 'exit_reason': [SellType.ROI, SellType.ROI, SellType.STOP_LOSS] + 'exit_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS] } ) @@ -303,7 +303,7 @@ def test_generate_exit_reason_stats(): 'wins': [2, 0, 0], 'draws': [0, 0, 0], 'losses': [0, 0, 1], - 'exit_reason': [SellType.ROI.value, SellType.ROI.value, SellType.STOP_LOSS.value] + 'exit_reason': [ExitType.ROI.value, ExitType.ROI.value, ExitType.STOP_LOSS.value] } ) @@ -343,7 +343,7 @@ def test_text_table_strategy(default_conf): 'wins': [2, 0, 0], 'draws': [0, 0, 0], 'losses': [0, 0, 1], - 'exit_reason': [SellType.ROI, SellType.ROI, SellType.STOP_LOSS] + 'exit_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS] } ), 'config': default_conf} results['TestStrategy2'] = {'results': pd.DataFrame( @@ -356,7 +356,7 @@ def test_text_table_strategy(default_conf): 'wins': [4, 1, 0], 'draws': [0, 0, 0], 'losses': [0, 0, 1], - 'exit_reason': [SellType.ROI, SellType.ROI, SellType.STOP_LOSS] + 'exit_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS] } ), 'config': default_conf} diff --git a/tests/plugins/test_protections.py b/tests/plugins/test_protections.py index 2e097726d..370810c32 100644 --- a/tests/plugins/test_protections.py +++ b/tests/plugins/test_protections.py @@ -4,14 +4,14 @@ from datetime import datetime, timedelta import pytest from freqtrade import constants -from freqtrade.enums import SellType +from freqtrade.enums import ExitType from freqtrade.persistence import PairLocks, Trade from freqtrade.plugins.protectionmanager import ProtectionManager from tests.conftest import get_patched_freqtradebot, log_has_re def generate_mock_trade(pair: str, fee: float, is_open: bool, - exit_reason: str = SellType.SELL_SIGNAL, + exit_reason: str = ExitType.SELL_SIGNAL, min_ago_open: int = None, min_ago_close: int = None, profit_rate: float = 0.9 ): @@ -91,7 +91,7 @@ def test_stoploss_guard(mocker, default_conf, fee, caplog): caplog.clear() Trade.query.session.add(generate_mock_trade( - 'XRP/BTC', fee.return_value, False, exit_reason=SellType.STOP_LOSS.value, + 'XRP/BTC', fee.return_value, False, exit_reason=ExitType.STOP_LOSS.value, min_ago_open=200, min_ago_close=30, )) @@ -100,12 +100,12 @@ def test_stoploss_guard(mocker, default_conf, fee, caplog): caplog.clear() # This trade does not count, as it's closed too long ago Trade.query.session.add(generate_mock_trade( - 'BCH/BTC', fee.return_value, False, exit_reason=SellType.STOP_LOSS.value, + 'BCH/BTC', fee.return_value, False, exit_reason=ExitType.STOP_LOSS.value, min_ago_open=250, min_ago_close=100, )) Trade.query.session.add(generate_mock_trade( - 'ETH/BTC', fee.return_value, False, exit_reason=SellType.STOP_LOSS.value, + 'ETH/BTC', fee.return_value, False, exit_reason=ExitType.STOP_LOSS.value, min_ago_open=240, min_ago_close=30, )) # 3 Trades closed - but the 2nd has been closed too long ago. @@ -114,7 +114,7 @@ def test_stoploss_guard(mocker, default_conf, fee, caplog): caplog.clear() Trade.query.session.add(generate_mock_trade( - 'LTC/BTC', fee.return_value, False, exit_reason=SellType.STOP_LOSS.value, + 'LTC/BTC', fee.return_value, False, exit_reason=ExitType.STOP_LOSS.value, min_ago_open=180, min_ago_close=30, )) @@ -148,7 +148,7 @@ def test_stoploss_guard_perpair(mocker, default_conf, fee, caplog, only_per_pair caplog.clear() Trade.query.session.add(generate_mock_trade( - pair, fee.return_value, False, exit_reason=SellType.STOP_LOSS.value, + pair, fee.return_value, False, exit_reason=ExitType.STOP_LOSS.value, min_ago_open=200, min_ago_close=30, profit_rate=0.9, )) @@ -158,12 +158,12 @@ def test_stoploss_guard_perpair(mocker, default_conf, fee, caplog, only_per_pair caplog.clear() # This trade does not count, as it's closed too long ago Trade.query.session.add(generate_mock_trade( - pair, fee.return_value, False, exit_reason=SellType.STOP_LOSS.value, + pair, fee.return_value, False, exit_reason=ExitType.STOP_LOSS.value, min_ago_open=250, min_ago_close=100, profit_rate=0.9, )) # Trade does not count for per pair stop as it's the wrong pair. Trade.query.session.add(generate_mock_trade( - 'ETH/BTC', fee.return_value, False, exit_reason=SellType.STOP_LOSS.value, + 'ETH/BTC', fee.return_value, False, exit_reason=ExitType.STOP_LOSS.value, min_ago_open=240, min_ago_close=30, profit_rate=0.9, )) # 3 Trades closed - but the 2nd has been closed too long ago. @@ -178,7 +178,7 @@ def test_stoploss_guard_perpair(mocker, default_conf, fee, caplog, only_per_pair # 2nd Trade that counts with correct pair Trade.query.session.add(generate_mock_trade( - pair, fee.return_value, False, exit_reason=SellType.STOP_LOSS.value, + pair, fee.return_value, False, exit_reason=ExitType.STOP_LOSS.value, min_ago_open=180, min_ago_close=30, profit_rate=0.9, )) @@ -203,7 +203,7 @@ def test_CooldownPeriod(mocker, default_conf, fee, caplog): caplog.clear() Trade.query.session.add(generate_mock_trade( - 'XRP/BTC', fee.return_value, False, exit_reason=SellType.STOP_LOSS.value, + 'XRP/BTC', fee.return_value, False, exit_reason=ExitType.STOP_LOSS.value, min_ago_open=200, min_ago_close=30, )) @@ -213,7 +213,7 @@ def test_CooldownPeriod(mocker, default_conf, fee, caplog): assert not PairLocks.is_global_lock() Trade.query.session.add(generate_mock_trade( - 'ETH/BTC', fee.return_value, False, exit_reason=SellType.ROI.value, + 'ETH/BTC', fee.return_value, False, exit_reason=ExitType.ROI.value, min_ago_open=205, min_ago_close=35, )) @@ -242,7 +242,7 @@ def test_LowProfitPairs(mocker, default_conf, fee, caplog): caplog.clear() Trade.query.session.add(generate_mock_trade( - 'XRP/BTC', fee.return_value, False, exit_reason=SellType.STOP_LOSS.value, + 'XRP/BTC', fee.return_value, False, exit_reason=ExitType.STOP_LOSS.value, min_ago_open=800, min_ago_close=450, profit_rate=0.9, )) @@ -253,7 +253,7 @@ def test_LowProfitPairs(mocker, default_conf, fee, caplog): assert not PairLocks.is_global_lock() Trade.query.session.add(generate_mock_trade( - 'XRP/BTC', fee.return_value, False, exit_reason=SellType.STOP_LOSS.value, + 'XRP/BTC', fee.return_value, False, exit_reason=ExitType.STOP_LOSS.value, min_ago_open=200, min_ago_close=120, profit_rate=0.9, )) @@ -265,14 +265,14 @@ def test_LowProfitPairs(mocker, default_conf, fee, caplog): # Add positive trade Trade.query.session.add(generate_mock_trade( - 'XRP/BTC', fee.return_value, False, exit_reason=SellType.ROI.value, + 'XRP/BTC', fee.return_value, False, exit_reason=ExitType.ROI.value, min_ago_open=20, min_ago_close=10, profit_rate=1.15, )) assert not freqtrade.protections.stop_per_pair('XRP/BTC') assert not PairLocks.is_pair_locked('XRP/BTC') Trade.query.session.add(generate_mock_trade( - 'XRP/BTC', fee.return_value, False, exit_reason=SellType.STOP_LOSS.value, + 'XRP/BTC', fee.return_value, False, exit_reason=ExitType.STOP_LOSS.value, min_ago_open=110, min_ago_close=20, profit_rate=0.8, )) @@ -300,15 +300,15 @@ def test_MaxDrawdown(mocker, default_conf, fee, caplog): caplog.clear() Trade.query.session.add(generate_mock_trade( - 'XRP/BTC', fee.return_value, False, exit_reason=SellType.STOP_LOSS.value, + 'XRP/BTC', fee.return_value, False, exit_reason=ExitType.STOP_LOSS.value, min_ago_open=1000, min_ago_close=900, profit_rate=1.1, )) Trade.query.session.add(generate_mock_trade( - 'ETH/BTC', fee.return_value, False, exit_reason=SellType.STOP_LOSS.value, + 'ETH/BTC', fee.return_value, False, exit_reason=ExitType.STOP_LOSS.value, min_ago_open=1000, min_ago_close=900, profit_rate=1.1, )) Trade.query.session.add(generate_mock_trade( - 'NEO/BTC', fee.return_value, False, exit_reason=SellType.STOP_LOSS.value, + 'NEO/BTC', fee.return_value, False, exit_reason=ExitType.STOP_LOSS.value, min_ago_open=1000, min_ago_close=900, profit_rate=1.1, )) # No losing trade yet ... so max_drawdown will raise exception @@ -316,7 +316,7 @@ def test_MaxDrawdown(mocker, default_conf, fee, caplog): assert not freqtrade.protections.stop_per_pair('XRP/BTC') Trade.query.session.add(generate_mock_trade( - 'XRP/BTC', fee.return_value, False, exit_reason=SellType.STOP_LOSS.value, + 'XRP/BTC', fee.return_value, False, exit_reason=ExitType.STOP_LOSS.value, min_ago_open=500, min_ago_close=400, profit_rate=0.9, )) # Not locked with one trade @@ -326,7 +326,7 @@ def test_MaxDrawdown(mocker, default_conf, fee, caplog): assert not PairLocks.is_global_lock() Trade.query.session.add(generate_mock_trade( - 'XRP/BTC', fee.return_value, False, exit_reason=SellType.STOP_LOSS.value, + 'XRP/BTC', fee.return_value, False, exit_reason=ExitType.STOP_LOSS.value, min_ago_open=1200, min_ago_close=1100, profit_rate=0.5, )) @@ -339,7 +339,7 @@ def test_MaxDrawdown(mocker, default_conf, fee, caplog): # Winning trade ... (should not lock, does not change drawdown!) Trade.query.session.add(generate_mock_trade( - 'XRP/BTC', fee.return_value, False, exit_reason=SellType.ROI.value, + 'XRP/BTC', fee.return_value, False, exit_reason=ExitType.ROI.value, min_ago_open=320, min_ago_close=410, profit_rate=1.5, )) assert not freqtrade.protections.global_stop() @@ -349,7 +349,7 @@ def test_MaxDrawdown(mocker, default_conf, fee, caplog): # Add additional negative trade, causing a loss of > 15% Trade.query.session.add(generate_mock_trade( - 'XRP/BTC', fee.return_value, False, exit_reason=SellType.ROI.value, + 'XRP/BTC', fee.return_value, False, exit_reason=ExitType.ROI.value, min_ago_open=20, min_ago_close=10, profit_rate=0.8, )) assert not freqtrade.protections.stop_per_pair('XRP/BTC') diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 3915886d7..9dc7eccf4 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -18,7 +18,7 @@ from telegram.error import BadRequest, NetworkError, TelegramError from freqtrade import __version__ from freqtrade.constants import CANCEL_REASON from freqtrade.edge import PairInfo -from freqtrade.enums import RPCMessageType, RunMode, SellType, State +from freqtrade.enums import RPCMessageType, RunMode, ExitType, State from freqtrade.exceptions import OperationalException from freqtrade.freqtradebot import FreqtradeBot from freqtrade.loggers import setup_logging @@ -962,7 +962,7 @@ def test_telegram_forcesell_handle(default_conf, update, ticker, fee, 'fiat_currency': 'USD', 'buy_tag': ANY, 'enter_tag': ANY, - 'exit_reason': SellType.FORCE_SELL.value, + 'exit_reason': ExitType.FORCE_SELL.value, 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, @@ -1030,7 +1030,7 @@ def test_telegram_forcesell_down_handle(default_conf, update, ticker, fee, 'fiat_currency': 'USD', 'buy_tag': ANY, 'enter_tag': ANY, - 'exit_reason': SellType.FORCE_SELL.value, + 'exit_reason': ExitType.FORCE_SELL.value, 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, @@ -1088,7 +1088,7 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None 'fiat_currency': 'USD', 'buy_tag': ANY, 'enter_tag': ANY, - 'exit_reason': SellType.FORCE_SELL.value, + 'exit_reason': ExitType.FORCE_SELL.value, 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, @@ -1826,7 +1826,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None: 'stake_currency': 'ETH', 'fiat_currency': 'USD', 'enter_tag': 'buy_signal1', - 'exit_reason': SellType.STOP_LOSS.value, + 'exit_reason': ExitType.STOP_LOSS.value, 'open_date': arrow.utcnow().shift(hours=-1), 'close_date': arrow.utcnow(), }) @@ -1860,7 +1860,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None: 'profit_ratio': -0.57405275, 'stake_currency': 'ETH', 'enter_tag': 'buy_signal1', - 'exit_reason': SellType.STOP_LOSS.value, + 'exit_reason': ExitType.STOP_LOSS.value, 'open_date': arrow.utcnow().shift(days=-1, hours=-2, minutes=-30), 'close_date': arrow.utcnow(), }) @@ -1939,7 +1939,7 @@ def test_send_msg_sell_fill_notification(default_conf, mocker, direction, 'profit_ratio': -0.57405275, 'stake_currency': 'ETH', 'enter_tag': enter_signal, - 'exit_reason': SellType.STOP_LOSS.value, + 'exit_reason': ExitType.STOP_LOSS.value, 'open_date': arrow.utcnow().shift(days=-1, hours=-2, minutes=-30), 'close_date': arrow.utcnow(), }) @@ -2063,7 +2063,7 @@ def test_send_msg_sell_notification_no_fiat( 'stake_currency': 'ETH', 'fiat_currency': 'USD', 'enter_tag': enter_signal, - 'exit_reason': SellType.STOP_LOSS.value, + 'exit_reason': ExitType.STOP_LOSS.value, 'open_date': arrow.utcnow().shift(hours=-2, minutes=-35, seconds=-3), 'close_date': arrow.utcnow(), }) diff --git a/tests/rpc/test_rpc_webhook.py b/tests/rpc/test_rpc_webhook.py index 706df455b..f556358f2 100644 --- a/tests/rpc/test_rpc_webhook.py +++ b/tests/rpc/test_rpc_webhook.py @@ -5,7 +5,7 @@ from unittest.mock import MagicMock import pytest from requests import RequestException -from freqtrade.enums import RPCMessageType, SellType +from freqtrade.enums import RPCMessageType, ExitType from freqtrade.rpc import RPC from freqtrade.rpc.webhook import Webhook from tests.conftest import get_patched_freqtradebot, log_has @@ -244,7 +244,7 @@ def test_send_msg_webhook(default_conf, mocker): 'profit_amount': 0.001, 'profit_ratio': 0.20, 'stake_currency': 'BTC', - 'exit_reason': SellType.STOP_LOSS.value + 'exit_reason': ExitType.STOP_LOSS.value } webhook.send_msg(msg=msg) assert msg_mock.call_count == 1 @@ -269,7 +269,7 @@ def test_send_msg_webhook(default_conf, mocker): 'profit_amount': 0.001, 'profit_ratio': 0.20, 'stake_currency': 'BTC', - 'exit_reason': SellType.STOP_LOSS.value + 'exit_reason': ExitType.STOP_LOSS.value } webhook.send_msg(msg=msg) assert msg_mock.call_count == 1 @@ -294,7 +294,7 @@ def test_send_msg_webhook(default_conf, mocker): 'profit_amount': 0.001, 'profit_ratio': 0.20, 'stake_currency': 'BTC', - 'exit_reason': SellType.STOP_LOSS.value + 'exit_reason': ExitType.STOP_LOSS.value } webhook.send_msg(msg=msg) assert msg_mock.call_count == 1 diff --git a/tests/strategy/test_interface.py b/tests/strategy/test_interface.py index 6217c6b79..9e3085e83 100644 --- a/tests/strategy/test_interface.py +++ b/tests/strategy/test_interface.py @@ -11,7 +11,7 @@ from pandas import DataFrame from freqtrade.configuration import TimeRange from freqtrade.data.dataprovider import DataProvider from freqtrade.data.history import load_data -from freqtrade.enums import SellType, SignalDirection +from freqtrade.enums import ExitType, SignalDirection from freqtrade.exceptions import OperationalException, StrategyError from freqtrade.optimize.space import SKDecimal from freqtrade.persistence import PairLocks, Trade @@ -395,22 +395,22 @@ def test_min_roi_reached3(default_conf, fee) -> None: 'profit,adjusted,expected,trailing,custom,profit2,adjusted2,expected2,custom_stop', [ # Profit, adjusted stoploss(absolute), profit for 2nd call, enable trailing, # enable custom stoploss, expected after 1st call, expected after 2nd call - (0.2, 0.9, SellType.NONE, False, False, 0.3, 0.9, SellType.NONE, None), - (0.2, 0.9, SellType.NONE, False, False, -0.2, 0.9, SellType.STOP_LOSS, None), - (0.2, 1.14, SellType.NONE, True, False, 0.05, 1.14, SellType.TRAILING_STOP_LOSS, None), - (0.01, 0.96, SellType.NONE, True, False, 0.05, 1, SellType.NONE, None), - (0.05, 1, SellType.NONE, True, False, -0.01, 1, SellType.TRAILING_STOP_LOSS, None), + (0.2, 0.9, ExitType.NONE, False, False, 0.3, 0.9, ExitType.NONE, None), + (0.2, 0.9, ExitType.NONE, False, False, -0.2, 0.9, ExitType.STOP_LOSS, None), + (0.2, 1.14, ExitType.NONE, True, False, 0.05, 1.14, ExitType.TRAILING_STOP_LOSS, None), + (0.01, 0.96, ExitType.NONE, True, False, 0.05, 1, ExitType.NONE, None), + (0.05, 1, ExitType.NONE, True, False, -0.01, 1, ExitType.TRAILING_STOP_LOSS, None), # Default custom case - trails with 10% - (0.05, 0.95, SellType.NONE, False, True, -0.02, 0.95, SellType.NONE, None), - (0.05, 0.95, SellType.NONE, False, True, -0.06, 0.95, SellType.TRAILING_STOP_LOSS, None), - (0.05, 1, SellType.NONE, False, True, -0.06, 1, SellType.TRAILING_STOP_LOSS, + (0.05, 0.95, ExitType.NONE, False, True, -0.02, 0.95, ExitType.NONE, None), + (0.05, 0.95, ExitType.NONE, False, True, -0.06, 0.95, ExitType.TRAILING_STOP_LOSS, None), + (0.05, 1, ExitType.NONE, False, True, -0.06, 1, ExitType.TRAILING_STOP_LOSS, lambda **kwargs: -0.05), - (0.05, 1, SellType.NONE, False, True, 0.09, 1.04, SellType.NONE, + (0.05, 1, ExitType.NONE, False, True, 0.09, 1.04, ExitType.NONE, lambda **kwargs: -0.05), - (0.05, 0.95, SellType.NONE, False, True, 0.09, 0.98, SellType.NONE, + (0.05, 0.95, ExitType.NONE, False, True, 0.09, 0.98, ExitType.NONE, lambda current_profit, **kwargs: -0.1 if current_profit < 0.6 else -(current_profit * 2)), # Error case - static stoploss in place - (0.05, 0.9, SellType.NONE, False, True, 0.09, 0.9, SellType.NONE, + (0.05, 0.9, ExitType.NONE, False, True, 0.09, 0.9, ExitType.NONE, lambda **kwargs: None), ]) def test_stop_loss_reached(default_conf, fee, profit, adjusted, expected, trailing, custom, @@ -441,7 +441,7 @@ def test_stop_loss_reached(default_conf, fee, profit, adjusted, expected, traili force_stoploss=0, high=None) assert isinstance(sl_flag, SellCheckTuple) assert sl_flag.sell_type == expected - if expected == SellType.NONE: + if expected == ExitType.NONE: assert sl_flag.sell_flag is False else: assert sl_flag.sell_flag is True @@ -451,7 +451,7 @@ def test_stop_loss_reached(default_conf, fee, profit, adjusted, expected, traili current_time=now, current_profit=profit2, force_stoploss=0, high=None) assert sl_flag.sell_type == expected2 - if expected2 == SellType.NONE: + if expected2 == ExitType.NONE: assert sl_flag.sell_flag is False else: assert sl_flag.sell_flag is True @@ -480,14 +480,14 @@ def test_custom_sell(default_conf, fee, caplog) -> None: low=None, high=None) assert res.sell_flag is False - assert res.sell_type == SellType.NONE + assert res.sell_type == ExitType.NONE strategy.custom_sell = MagicMock(return_value=True) res = strategy.should_exit(trade, 1, now, enter=False, exit_=False, low=None, high=None) assert res.sell_flag is True - assert res.sell_type == SellType.CUSTOM_SELL + assert res.sell_type == ExitType.CUSTOM_SELL assert res.exit_reason == 'custom_sell' strategy.custom_sell = MagicMock(return_value='hello world') @@ -495,7 +495,7 @@ def test_custom_sell(default_conf, fee, caplog) -> None: res = strategy.should_exit(trade, 1, now, enter=False, exit_=False, low=None, high=None) - assert res.sell_type == SellType.CUSTOM_SELL + assert res.sell_type == ExitType.CUSTOM_SELL assert res.sell_flag is True assert res.exit_reason == 'hello world' @@ -504,7 +504,7 @@ def test_custom_sell(default_conf, fee, caplog) -> None: res = strategy.should_exit(trade, 1, now, enter=False, exit_=False, low=None, high=None) - assert res.sell_type == SellType.CUSTOM_SELL + assert res.sell_type == ExitType.CUSTOM_SELL assert res.sell_flag is True assert res.exit_reason == 'h' * 64 assert log_has_re('Custom sell reason returned from custom_sell is too long.*', caplog) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 0c8d58d81..673be3c3c 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -12,7 +12,7 @@ import pytest from pandas import DataFrame from freqtrade.constants import CANCEL_REASON, MATH_CLOSE_PREC, UNLIMITED_STAKE_AMOUNT -from freqtrade.enums import CandleType, RPCMessageType, RunMode, SellType, SignalDirection, State +from freqtrade.enums import CandleType, RPCMessageType, RunMode, ExitType, SignalDirection, State from freqtrade.exceptions import (DependencyException, ExchangeError, InsufficientFundsError, InvalidOrderException, OperationalException, PricingError, TemporaryError) @@ -234,7 +234,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.exit_reason == SellType.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: @@ -1164,7 +1164,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.exit_reason == SellType.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) @@ -1176,7 +1176,7 @@ def test_create_stoploss_order_invalid_order( # Rpc is sending first buy, then sell assert rpc_mock.call_count == 2 - assert rpc_mock.call_args_list[1][0][0]['exit_reason'] == SellType.EMERGENCY_SELL.value + assert rpc_mock.call_args_list[1][0][0]['exit_reason'] == ExitType.EMERGENCY_SELL.value assert rpc_mock.call_args_list[1][0][0]['order_type'] == 'market' @@ -2093,7 +2093,7 @@ def test_handle_trade_roi(default_conf_usdt, ticker_usdt, limit_order_open, fee, caplog.clear() patch_get_signal(freqtrade) assert freqtrade.handle_trade(trade) - assert log_has("ETH/USDT - Required profit reached. sell_type=SellType.ROI", + assert log_has("ETH/USDT - Required profit reached. sell_type=ExitType.ROI", caplog) @@ -2135,7 +2135,7 @@ def test_handle_trade_use_exit_signal( else: patch_get_signal(freqtrade, enter_long=False, exit_long=True) assert freqtrade.handle_trade(trade) - assert log_has("ETH/USDT - Sell signal received. sell_type=SellType.SELL_SIGNAL", + assert log_has("ETH/USDT - Sell signal received. sell_type=ExitType.SELL_SIGNAL", caplog) @@ -2855,7 +2855,7 @@ def test_execute_trade_exit_up(default_conf_usdt, ticker_usdt, fee, ticker_usdt_ freqtrade.execute_trade_exit( trade=trade, limit=(ticker_usdt_sell_down()['ask'] if is_short else ticker_usdt_sell_up()['bid']), - exit_reason=SellCheckTuple(sell_type=SellType.ROI) + exit_reason=SellCheckTuple(sell_type=ExitType.ROI) ) assert rpc_mock.call_count == 0 assert freqtrade.strategy.confirm_trade_exit.call_count == 1 @@ -2867,7 +2867,7 @@ def test_execute_trade_exit_up(default_conf_usdt, ticker_usdt, fee, ticker_usdt_ freqtrade.execute_trade_exit( trade=trade, limit=(ticker_usdt_sell_down()['ask'] if is_short else ticker_usdt_sell_up()['bid']), - exit_reason=SellCheckTuple(sell_type=SellType.ROI) + exit_reason=SellCheckTuple(sell_type=ExitType.ROI) ) assert freqtrade.strategy.confirm_trade_exit.call_count == 1 @@ -2892,7 +2892,7 @@ def test_execute_trade_exit_up(default_conf_usdt, ticker_usdt, fee, ticker_usdt_ 'profit_ratio': 0.00493809 if is_short else 0.09451372, 'stake_currency': 'USDT', 'fiat_currency': 'USD', - 'exit_reason': SellType.ROI.value, + 'exit_reason': ExitType.ROI.value, 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, @@ -2928,7 +2928,7 @@ def test_execute_trade_exit_down(default_conf_usdt, ticker_usdt, fee, ticker_usd ) freqtrade.execute_trade_exit( trade=trade, limit=(ticker_usdt_sell_up if is_short else ticker_usdt_sell_down)()['bid'], - exit_reason=SellCheckTuple(sell_type=SellType.STOP_LOSS)) + exit_reason=SellCheckTuple(sell_type=ExitType.STOP_LOSS)) assert rpc_mock.call_count == 2 last_msg = rpc_mock.call_args_list[-1][0][0] @@ -2951,7 +2951,7 @@ def test_execute_trade_exit_down(default_conf_usdt, ticker_usdt, fee, ticker_usd 'profit_ratio': -0.0945681 if is_short else -1.247e-05, 'stake_currency': 'USDT', 'fiat_currency': 'USD', - 'exit_reason': SellType.STOP_LOSS.value, + 'exit_reason': ExitType.STOP_LOSS.value, 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, @@ -3003,7 +3003,7 @@ def test_execute_trade_exit_custom_exit_price( freqtrade.execute_trade_exit( trade=trade, limit=ticker_usdt_sell_up()['ask' if is_short else 'bid'], - exit_reason=SellCheckTuple(sell_type=SellType.SELL_SIGNAL) + exit_reason=SellCheckTuple(sell_type=ExitType.SELL_SIGNAL) ) # Sell price must be different to default bid price @@ -3031,7 +3031,7 @@ def test_execute_trade_exit_custom_exit_price( 'profit_ratio': profit_ratio, 'stake_currency': 'USDT', 'fiat_currency': 'USD', - 'exit_reason': SellType.SELL_SIGNAL.value, + 'exit_reason': ExitType.SELL_SIGNAL.value, 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, @@ -3074,7 +3074,7 @@ def test_execute_trade_exit_down_stoploss_on_exchange_dry_run( trade.stop_loss = 2.0 * 1.01 if is_short else 2.0 * 0.99 freqtrade.execute_trade_exit( trade=trade, limit=(ticker_usdt_sell_up if is_short else ticker_usdt_sell_down())['bid'], - exit_reason=SellCheckTuple(sell_type=SellType.STOP_LOSS)) + exit_reason=SellCheckTuple(sell_type=ExitType.STOP_LOSS)) assert rpc_mock.call_count == 2 last_msg = rpc_mock.call_args_list[-1][0][0] @@ -3098,7 +3098,7 @@ def test_execute_trade_exit_down_stoploss_on_exchange_dry_run( 'profit_ratio': -0.00501253 if is_short else -0.01493766, 'stake_currency': 'USDT', 'fiat_currency': 'USD', - 'exit_reason': SellType.STOP_LOSS.value, + 'exit_reason': ExitType.STOP_LOSS.value, 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, @@ -3134,7 +3134,7 @@ def test_execute_trade_exit_sloe_cancel_exception( trade.stoploss_order_id = "abcd" freqtrade.execute_trade_exit(trade=trade, limit=1234, - exit_reason=SellCheckTuple(sell_type=SellType.STOP_LOSS)) + exit_reason=SellCheckTuple(sell_type=ExitType.STOP_LOSS)) assert create_order_mock.call_count == 2 assert log_has('Could not cancel stoploss order abcd', caplog) @@ -3189,7 +3189,7 @@ def test_execute_trade_exit_with_stoploss_on_exchange( freqtrade.execute_trade_exit( trade=trade, limit=ticker_usdt_sell_up()['ask' if is_short else 'bid'], - exit_reason=SellCheckTuple(sell_type=SellType.STOP_LOSS) + exit_reason=SellCheckTuple(sell_type=ExitType.STOP_LOSS) ) trade = Trade.query.first() @@ -3265,7 +3265,7 @@ def test_may_execute_trade_exit_after_stoploss_on_exchange_hit(default_conf_usdt freqtrade.exit_positions(trades) assert trade.stoploss_order_id is None assert trade.is_open is False - assert trade.exit_reason == SellType.STOPLOSS_ON_EXCHANGE.value + assert trade.exit_reason == ExitType.STOPLOSS_ON_EXCHANGE.value assert rpc_mock.call_count == 3 assert rpc_mock.call_args_list[0][0][0]['type'] == RPCMessageType.BUY assert rpc_mock.call_args_list[1][0][0]['type'] == RPCMessageType.BUY_FILL @@ -3328,7 +3328,7 @@ def test_execute_trade_exit_market_order( freqtrade.execute_trade_exit( trade=trade, limit=ticker_usdt_sell_up()['ask' if is_short else 'bid'], - exit_reason=SellCheckTuple(sell_type=SellType.ROI) + exit_reason=SellCheckTuple(sell_type=ExitType.ROI) ) assert not trade.is_open @@ -3355,7 +3355,7 @@ def test_execute_trade_exit_market_order( 'profit_ratio': profit_ratio, 'stake_currency': 'USDT', 'fiat_currency': 'USD', - 'exit_reason': SellType.ROI.value, + 'exit_reason': ExitType.ROI.value, 'open_date': ANY, 'close_date': ANY, 'close_rate': ANY, @@ -3392,7 +3392,7 @@ def test_execute_trade_exit_insufficient_funds_error(default_conf_usdt, ticker_u fetch_ticker=ticker_usdt_sell_up ) - exit_reason = SellCheckTuple(sell_type=SellType.ROI) + exit_reason = SellCheckTuple(sell_type=ExitType.ROI) assert not freqtrade.execute_trade_exit( trade=trade, limit=ticker_usdt_sell_up()['ask' if is_short else 'bid'], @@ -3403,18 +3403,18 @@ def test_execute_trade_exit_insufficient_funds_error(default_conf_usdt, ticker_u @pytest.mark.parametrize('profit_only,bid,ask,handle_first,handle_second,sell_type,is_short', [ # Enable profit - (True, 2.18, 2.2, False, True, SellType.SELL_SIGNAL.value, False), - (True, 2.18, 2.2, False, True, SellType.SELL_SIGNAL.value, True), + (True, 2.18, 2.2, False, True, ExitType.SELL_SIGNAL.value, False), + (True, 2.18, 2.2, False, True, ExitType.SELL_SIGNAL.value, True), # # Disable profit - (False, 3.19, 3.2, True, False, SellType.SELL_SIGNAL.value, False), - (False, 3.19, 3.2, True, False, SellType.SELL_SIGNAL.value, True), + (False, 3.19, 3.2, True, False, ExitType.SELL_SIGNAL.value, False), + (False, 3.19, 3.2, True, False, ExitType.SELL_SIGNAL.value, True), # # Enable loss - # # * Shouldn't this be SellType.STOP_LOSS.value + # # * Shouldn't this be ExitType.STOP_LOSS.value (True, 0.21, 0.22, False, False, None, False), (True, 2.41, 2.42, False, False, None, True), # Disable loss - (False, 0.10, 0.22, True, False, SellType.SELL_SIGNAL.value, False), - (False, 0.10, 0.22, True, False, SellType.SELL_SIGNAL.value, True), + (False, 0.10, 0.22, True, False, ExitType.SELL_SIGNAL.value, False), + (False, 0.10, 0.22, True, False, ExitType.SELL_SIGNAL.value, True), ]) def test_sell_profit_only( default_conf_usdt, limit_order, limit_order_open, is_short, @@ -3441,11 +3441,11 @@ def test_sell_profit_only( }) freqtrade = FreqtradeBot(default_conf_usdt) patch_get_signal(freqtrade, enter_short=is_short, enter_long=not is_short) - if sell_type == SellType.SELL_SIGNAL.value: + if sell_type == ExitType.SELL_SIGNAL.value: freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) else: freqtrade.strategy.stop_loss_reached = MagicMock(return_value=SellCheckTuple( - sell_type=SellType.NONE)) + sell_type=ExitType.NONE)) freqtrade.enter_positions() trade = Trade.query.first() @@ -3561,7 +3561,7 @@ def test_locked_pairs(default_conf_usdt, ticker_usdt, fee, freqtrade.execute_trade_exit( trade=trade, limit=ticker_usdt_sell_down()['ask' if is_short else 'bid'], - exit_reason=SellCheckTuple(sell_type=SellType.STOP_LOSS) + exit_reason=SellCheckTuple(sell_type=ExitType.STOP_LOSS) ) trade.close(ticker_usdt_sell_down()['bid']) assert freqtrade.strategy.is_pair_locked(trade.pair) @@ -3616,7 +3616,7 @@ def test_ignore_roi_if_enter_signal(default_conf_usdt, limit_order, limit_order_ else: patch_get_signal(freqtrade, enter_long=False, exit_long=False) assert freqtrade.handle_trade(trade) is True - assert trade.exit_reason == SellType.ROI.value + assert trade.exit_reason == ExitType.ROI.value @pytest.mark.parametrize("is_short,val1,val2", [ @@ -3678,7 +3678,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.exit_reason == SellType.TRAILING_STOP_LOSS.value + assert trade.exit_reason == ExitType.TRAILING_STOP_LOSS.value @pytest.mark.parametrize('offset,trail_if_reached,second_sl,is_short', [ @@ -3782,7 +3782,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.exit_reason == SellType.TRAILING_STOP_LOSS.value + assert trade.exit_reason == ExitType.TRAILING_STOP_LOSS.value @pytest.mark.parametrize("is_short", [False, True]) @@ -3824,7 +3824,7 @@ def test_disable_ignore_roi_if_enter_signal(default_conf_usdt, limit_order, limi # Test if buy-signal is absent patch_get_signal(freqtrade) assert freqtrade.handle_trade(trade) is True - assert trade.exit_reason == SellType.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, @@ -4920,7 +4920,7 @@ def test_update_funding_fees( trade=trade, # The values of the next 2 params are irrelevant for this test limit=ticker_usdt_sell_up()['bid'], - exit_reason=SellCheckTuple(sell_type=SellType.ROI) + exit_reason=SellCheckTuple(sell_type=ExitType.ROI) ) assert trade.funding_fees == pytest.approx(sum( trade.amount * diff --git a/tests/test_integration.py b/tests/test_integration.py index 00f3a527a..1bc5a03e5 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -2,7 +2,7 @@ from unittest.mock import MagicMock import pytest -from freqtrade.enums import SellType +from freqtrade.enums import ExitType from freqtrade.persistence import Trade from freqtrade.rpc.rpc import RPC from freqtrade.strategy.interface import SellCheckTuple @@ -52,8 +52,8 @@ def test_may_execute_exit_stoploss_on_exchange_multi(default_conf, ticker, fee, side_effect=[stoploss_order_closed, stoploss_order_open, stoploss_order_open]) # Sell 3rd trade (not called for the first trade) should_sell_mock = MagicMock(side_effect=[ - SellCheckTuple(sell_type=SellType.NONE), - SellCheckTuple(sell_type=SellType.SELL_SIGNAL)] + SellCheckTuple(sell_type=ExitType.NONE), + SellCheckTuple(sell_type=ExitType.SELL_SIGNAL)] ) cancel_order_mock = MagicMock() mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss) @@ -111,7 +111,7 @@ def test_may_execute_exit_stoploss_on_exchange_multi(default_conf, ticker, fee, assert wallets_mock.call_count == 4 trade = trades[0] - assert trade.exit_reason == SellType.STOPLOSS_ON_EXCHANGE.value + assert trade.exit_reason == ExitType.STOPLOSS_ON_EXCHANGE.value assert not trade.is_open trade = trades[1] @@ -119,7 +119,7 @@ def test_may_execute_exit_stoploss_on_exchange_multi(default_conf, ticker, fee, assert trade.is_open trade = trades[2] - assert trade.exit_reason == SellType.SELL_SIGNAL.value + assert trade.exit_reason == ExitType.SELL_SIGNAL.value assert not trade.is_open @@ -157,11 +157,11 @@ def test_forcebuy_last_unlimited(default_conf, ticker, fee, limit_buy_order, moc _notify_exit=MagicMock(), ) should_sell_mock = MagicMock(side_effect=[ - SellCheckTuple(sell_type=SellType.NONE), - SellCheckTuple(sell_type=SellType.SELL_SIGNAL), - SellCheckTuple(sell_type=SellType.NONE), - SellCheckTuple(sell_type=SellType.NONE), - SellCheckTuple(sell_type=SellType.NONE)] + SellCheckTuple(sell_type=ExitType.NONE), + SellCheckTuple(sell_type=ExitType.SELL_SIGNAL), + SellCheckTuple(sell_type=ExitType.NONE), + SellCheckTuple(sell_type=ExitType.NONE), + SellCheckTuple(sell_type=ExitType.NONE)] ) mocker.patch("freqtrade.strategy.interface.IStrategy.should_exit", should_sell_mock)