Update SellType to ExitType

This commit is contained in:
Matthias 2022-03-25 06:55:37 +01:00
parent c07883b1f9
commit dcfa3e8648
24 changed files with 226 additions and 226 deletions

View File

@ -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.enums.candletype import CandleType
from freqtrade.exceptions import OperationalException
from freqtrade.exchange.exchange import timeframe_to_seconds
@ -461,7 +461,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
@ -471,7 +471,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,

View File

@ -2,11 +2,11 @@
from freqtrade.enums.backteststate import BacktestState
from freqtrade.enums.candletype import CandleType
from freqtrade.enums.exitchecktuple import ExitCheckTuple
from freqtrade.enums.exittype import ExitType
from freqtrade.enums.marginmode import MarginMode
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.signaltype import SignalDirection, SignalTagType, SignalType
from freqtrade.enums.state import State
from freqtrade.enums.tradingmode import TradingMode

View File

@ -1,17 +1,17 @@
from freqtrade.enums.selltype import SellType
from freqtrade.enums.exittype import ExitType
class ExitCheckTuple:
"""
NamedTuple for Exit type + reason
"""
exit_type: SellType
exit_type: ExitType
exit_reason: str = ''
def __init__(self, exit_type: SellType, exit_reason: str = ''):
def __init__(self, exit_type: ExitType, exit_reason: str = ''):
self.exit_type = exit_type
self.exit_reason = exit_reason or exit_type.value
@property
def exit_flag(self):
return self.exit_type != SellType.NONE
return self.exit_type != ExitType.NONE

View File

@ -1,7 +1,7 @@
from enum import Enum
class SellType(Enum):
class ExitType(Enum):
"""
Enum to distinguish between sell reasons
"""

View File

@ -16,7 +16,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 (ExitCheckTuple, RPCMessageType, RunMode, SellType, SignalDirection,
from freqtrade.enums import (ExitCheckTuple, RPCMessageType, RunMode, ExitType, SignalDirection,
State, TradingMode)
from freqtrade.exceptions import (DependencyException, ExchangeError, InsufficientFundsError,
InvalidOrderException, PricingError)
@ -978,7 +978,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_check=ExitCheckTuple(
exit_type=SellType.EMERGENCY_SELL))
exit_type=ExitType.EMERGENCY_SELL))
except ExchangeError:
trade.stoploss_order_id = None
@ -1009,7 +1009,7 @@ class FreqtradeBot(LoggingMixin):
# We check if stoploss order is fulfilled
if stoploss_order and stoploss_order['status'] in ('closed', 'triggered'):
trade.sell_reason = SellType.STOPLOSS_ON_EXCHANGE.value
trade.sell_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
@ -1159,7 +1159,7 @@ class FreqtradeBot(LoggingMixin):
try:
self.execute_trade_exit(
trade, order.get('price'),
exit_check=ExitCheckTuple(exit_type=SellType.EMERGENCY_SELL))
exit_check=ExitCheckTuple(exit_type=ExitType.EMERGENCY_SELL))
except DependencyException as exception:
logger.warning(
f'Unable to emergency sell trade {trade.pair}: {exception}')
@ -1353,7 +1353,7 @@ class FreqtradeBot(LoggingMixin):
open_date=trade.open_date,
)
exit_type = 'exit'
if exit_check.exit_type in (SellType.STOP_LOSS, SellType.TRAILING_STOP_LOSS):
if exit_check.exit_type in (ExitType.STOP_LOSS, ExitType.TRAILING_STOP_LOSS):
exit_type = 'stoploss'
# if stoploss is on exchange and we are on dry_run mode,
@ -1377,7 +1377,7 @@ class FreqtradeBot(LoggingMixin):
trade = self.cancel_stoploss_on_exchange(trade)
order_type = ordertype or self.strategy.order_types[exit_type]
if exit_check.exit_type == SellType.EMERGENCY_SELL:
if exit_check.exit_type == ExitType.EMERGENCY_SELL:
# Emergency sells (default to market!)
order_type = self.strategy.order_types.get("emergencyexit", "market")

View File

@ -19,7 +19,7 @@ from freqtrade.data import history
from freqtrade.data.btanalysis import find_existing_backtest_stats, 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, ExitCheckTuple, MarginMode, SellType,
from freqtrade.enums import (BacktestState, CandleType, ExitCheckTuple, MarginMode, ExitType,
TradingMode)
from freqtrade.exceptions import DependencyException, OperationalException
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds
@ -359,9 +359,9 @@ class Backtesting:
Get close rate for backtesting result
"""
# Special handling if high or low hit STOP_LOSS or ROI
if sell.exit_type in (SellType.STOP_LOSS, SellType.TRAILING_STOP_LOSS):
if sell.exit_type in (ExitType.STOP_LOSS, ExitType.TRAILING_STOP_LOSS):
return self._get_close_rate_for_stoploss(sell_row, trade, sell, trade_dur)
elif sell.exit_type == (SellType.ROI):
elif sell.exit_type == (ExitType.ROI):
return self._get_close_rate_for_roi(sell_row, trade, sell, trade_dur)
else:
return sell_row[OPEN_IDX]
@ -384,7 +384,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.exit_type == SellType.TRAILING_STOP_LOSS and trade_dur == 0:
if sell.exit_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
@ -533,7 +533,7 @@ class Backtesting:
# call the custom exit price,with default value as previous closerate
current_profit = trade.calc_profit_ratio(closerate)
order_type = self.strategy.order_types['exit']
if sell.exit_type in (SellType.SELL_SIGNAL, SellType.CUSTOM_SELL):
if sell.exit_type in (ExitType.SELL_SIGNAL, ExitType.CUSTOM_SELL):
# Custom exit pricing only for sell-signals
if order_type == 'limit':
closerate = strategy_safe_wrapper(self.strategy.custom_exit_price,
@ -814,7 +814,7 @@ class Backtesting:
sell_row = data[pair][-1]
trade.close_date = sell_row[DATE_IDX].to_pydatetime()
trade.sell_reason = SellType.FORCE_SELL.value
trade.sell_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

View File

@ -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.persistence.migrations import check_migrate
@ -625,7 +625,7 @@ class LocalTrade():
elif order.ft_order_side == 'stoploss':
self.stoploss_order_id = None
self.close_rate_requested = self.stop_loss
self.sell_reason = SellType.STOPLOSS_ON_EXCHANGE.value
self.sell_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)

View File

@ -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.sell_reason == SellType.STOP_LOSS.value,
# and_(Trade.sell_reason == SellType.TRAILING_STOP_LOSS.value,
# or_(Trade.sell_reason == ExitType.STOP_LOSS.value,
# and_(Trade.sell_reason == ExitType.TRAILING_STOP_LOSS.value,
# Trade.close_profit < 0))
# ]
# if pair:
@ -54,8 +54,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.sell_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:

View File

@ -18,7 +18,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, SignalDirection, State, TradingMode
from freqtrade.enums import ExitType, SignalDirection, State, TradingMode
from freqtrade.exceptions import ExchangeError, PricingError
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_msecs
from freqtrade.loggers import bufferHandler
@ -707,7 +707,7 @@ class RPC:
# Get current rate and execute sell
current_rate = self._freqtrade.exchange.get_rate(
trade.pair, refresh=False, side=trade.exit_side)
exit_check = ExitCheckTuple(exit_type=SellType.FORCE_SELL)
exit_check = ExitCheckTuple(exit_type=ExitType.FORCE_SELL)
order_type = ordertype or self._freqtrade.strategy.order_types.get(
"forceexit", self._freqtrade.strategy.order_types["exit"])

View File

@ -13,7 +13,7 @@ from pandas import DataFrame
from freqtrade.constants import ListPairsWithTimeframes
from freqtrade.data.dataprovider import DataProvider
from freqtrade.enums import (CandleType, ExitCheckTuple, SellType, SignalDirection, SignalTagType,
from freqtrade.enums import (CandleType, ExitCheckTuple, ExitType, SignalDirection, SignalTagType,
SignalType, TradingMode)
from freqtrade.exceptions import OperationalException, StrategyError
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds
@ -861,7 +861,7 @@ class IStrategy(ABC, HyperStrategyMixin):
and self.min_roi_reached(trade=trade, current_profit=current_profit,
current_time=current_time))
sell_signal = SellType.NONE
sell_signal = ExitType.NONE
custom_reason = ''
# use provided rate in backtesting, not high/low.
current_rate = rate
@ -872,14 +872,14 @@ class IStrategy(ABC, HyperStrategyMixin):
pass
elif self.use_sell_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_exit, default_retval=False)(
pair=trade.pair, trade=trade, current_time=current_time,
current_rate=current_rate, current_profit=current_profit)
if custom_reason:
sell_signal = SellType.CUSTOM_SELL
sell_signal = ExitType.CUSTOM_SELL
if isinstance(custom_reason, str):
if len(custom_reason) > CUSTOM_EXIT_MAX_LENGTH:
logger.warning(f'Custom {trade_type} reason returned from '
@ -888,9 +888,9 @@ class IStrategy(ABC, HyperStrategyMixin):
custom_reason = custom_reason[:CUSTOM_EXIT_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 ExitCheckTuple(exit_type=sell_signal, exit_reason=custom_reason)
@ -898,9 +898,9 @@ class IStrategy(ABC, HyperStrategyMixin):
# Exit-signal
# ROI (if not stoploss)
# Stoploss
if roi_reached and stoplossflag.exit_type != SellType.STOP_LOSS:
logger.debug(f"{trade.pair} - Required profit reached. sell_type=SellType.ROI")
return ExitCheckTuple(exit_type=SellType.ROI)
if roi_reached and stoplossflag.exit_type != ExitType.STOP_LOSS:
logger.debug(f"{trade.pair} - Required profit reached. sell_type=ExitType.ROI")
return ExitCheckTuple(exit_type=ExitType.ROI)
if stoplossflag.exit_flag:
@ -909,7 +909,7 @@ class IStrategy(ABC, HyperStrategyMixin):
# This one is noisy, commented out...
# logger.debug(f"{trade.pair} - No exit signal.")
return ExitCheckTuple(exit_type=SellType.NONE)
return ExitCheckTuple(exit_type=ExitType.NONE)
def stop_loss_reached(self, current_rate: float, trade: Trade,
current_time: datetime, current_profit: float,
@ -973,11 +973,11 @@ class IStrategy(ABC, HyperStrategyMixin):
if ((sl_higher_long or sl_lower_short) 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}, "
@ -994,7 +994,7 @@ class IStrategy(ABC, HyperStrategyMixin):
return ExitCheckTuple(exit_type=sell_type)
return ExitCheckTuple(exit_type=SellType.NONE)
return ExitCheckTuple(exit_type=ExitType.NONE)
def min_roi_reached_entry(self, trade_dur: int) -> Tuple[Optional[int], Optional[float]]:
"""

View File

@ -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(sell_reason=SellType.SELL_SIGNAL, open_tick=1, close_tick=2),
BTrade(sell_reason=SellType.SELL_SIGNAL, open_tick=4, close_tick=6)]
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)]
)
# 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=SellType.STOP_LOSS, open_tick=1, close_tick=1)]
trades=[BTrade(sell_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=SellType.STOP_LOSS, open_tick=1, close_tick=1)]
trades=[BTrade(sell_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=SellType.STOP_LOSS, open_tick=1, close_tick=1)]
trades=[BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1)]
)
TESTS = [

View File

@ -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
"""
sell_reason: SellType
sell_reason: ExitType
open_tick: int
close_tick: int
enter_tag: Optional[str] = None

View File

@ -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],
'sell_reason': [SellType.STOP_LOSS, SellType.ROI, SellType.STOP_LOSS, SellType.ROI],
'sell_reason': [ExitType.STOP_LOSS, ExitType.ROI, ExitType.STOP_LOSS, ExitType.ROI],
'open_date':
[
datetime(2019, 1, 1, 9, 15, 0),

View File

@ -5,7 +5,7 @@ from unittest.mock import MagicMock
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,
@ -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=SellType.SELL_SIGNAL, open_tick=1, close_tick=4)]
trades=[BTrade(sell_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=SellType.STOP_LOSS, open_tick=1, close_tick=2)]
trades=[BTrade(sell_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=SellType.STOP_LOSS, open_tick=1, close_tick=3)]
trades=[BTrade(sell_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=SellType.STOP_LOSS, open_tick=1, close_tick=2),
BTrade(sell_reason=SellType.STOP_LOSS, open_tick=4, close_tick=5)]
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)]
)
# 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=SellType.STOP_LOSS, open_tick=1, close_tick=2)]
trades=[BTrade(sell_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=SellType.ROI, open_tick=1, close_tick=3)]
trades=[BTrade(sell_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=SellType.STOP_LOSS, open_tick=1, close_tick=2)]
trades=[BTrade(sell_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=SellType.ROI, open_tick=1, close_tick=2)]
trades=[BTrade(sell_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=SellType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)]
trades=[BTrade(sell_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=SellType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)]
trades=[BTrade(sell_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=SellType.STOP_LOSS, open_tick=1, close_tick=4)]
trades=[BTrade(sell_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=SellType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)]
trades=[BTrade(sell_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=SellType.TRAILING_STOP_LOSS, open_tick=1, close_tick=2)]
trades=[BTrade(sell_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=SellType.ROI, open_tick=1, close_tick=1)]
trades=[BTrade(sell_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=SellType.STOP_LOSS, open_tick=1, close_tick=1)]
trades=[BTrade(sell_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=SellType.ROI, open_tick=1, close_tick=1),
BTrade(sell_reason=SellType.STOP_LOSS, open_tick=2, close_tick=2)]
trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=1),
BTrade(sell_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=SellType.ROI, open_tick=1, close_tick=3)]
trades=[BTrade(sell_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=SellType.ROI, open_tick=1, close_tick=3)]
trades=[BTrade(sell_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=SellType.ROI, open_tick=1, close_tick=3)]
trades=[BTrade(sell_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=SellType.ROI, open_tick=1, close_tick=3)]
trades=[BTrade(sell_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=SellType.ROI, open_tick=1, close_tick=3)]
trades=[BTrade(sell_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=SellType.ROI, open_tick=1, close_tick=2)]
trades=[BTrade(sell_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=SellType.ROI, open_tick=1, close_tick=2)]
trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=2)]
)
@ -375,7 +375,7 @@ tc22s = 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=SellType.ROI, open_tick=1, close_tick=2, is_short=True)]
trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=2, is_short=True)]
)
# Test 23: trailing_stop Raises in candle 2 (does not trigger)
@ -394,7 +394,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(sell_reason=SellType.ROI, open_tick=1, close_tick=3)]
trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=3)]
)
# Test 24: Sell with signal sell in candle 3 (stoploss also triggers on this candle)
@ -409,7 +409,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_sell_signal=True,
trades=[BTrade(sell_reason=SellType.STOP_LOSS, open_tick=1, close_tick=3)]
trades=[BTrade(sell_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)
@ -424,7 +424,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_sell_signal=True,
trades=[BTrade(sell_reason=SellType.SELL_SIGNAL, open_tick=1, close_tick=4)]
trades=[BTrade(sell_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=4)]
)
# Test 25l: (copy of test25 with leverage)
@ -441,7 +441,7 @@ tc25l = 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=SellType.SELL_SIGNAL, open_tick=1, close_tick=4)]
trades=[BTrade(sell_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=4)]
)
# Test 25s: (copy of test25 with leverage and as short)
@ -458,7 +458,7 @@ tc25s = 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=SellType.SELL_SIGNAL, open_tick=1, close_tick=4, is_short=True)]
trades=[BTrade(sell_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=4, is_short=True)]
)
# Test 26: Sell with signal sell in candle 3 (ROI at signal candle)
# Stoploss at 10% (irrelevant), ROI at 5% (will trigger)
@ -472,7 +472,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_sell_signal=True,
trades=[BTrade(sell_reason=SellType.ROI, open_tick=1, close_tick=3)]
trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=3)]
)
# Test 27: Sell with signal sell in candle 3 (ROI at signal candle)
@ -486,7 +486,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_sell_signal=True,
trades=[BTrade(sell_reason=SellType.SELL_SIGNAL, open_tick=1, close_tick=4)]
trades=[BTrade(sell_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=4)]
)
# Test 28: trailing_stop should raise so candle 3 causes a stoploss
@ -503,7 +503,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(sell_reason=SellType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)]
trades=[BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)]
)
# Test 28s: trailing_stop should raise so candle 3 causes a stoploss
@ -521,7 +521,7 @@ tc28s = BTContainer(data=[
trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.05,
trailing_stop_positive=0.03,
trades=[
BTrade(sell_reason=SellType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3, is_short=True)
BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3, is_short=True)
]
)
@ -537,7 +537,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(sell_reason=SellType.TRAILING_STOP_LOSS, open_tick=1, close_tick=2)]
trades=[BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=2)]
)
# Test 30: trailing_stop should be triggered immediately on trade open candle.
@ -551,7 +551,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(sell_reason=SellType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)]
trades=[BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)]
)
# Test 31: trailing_stop should be triggered immediately on trade open candle.
@ -566,7 +566,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(sell_reason=SellType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)]
trades=[BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)]
)
# Test 32: trailing_stop should be triggered immediately on trade open candle.
@ -581,7 +581,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(sell_reason=SellType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)]
trades=[BTrade(sell_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)]
)
# Test 33: trailing_stop should be triggered immediately on trade open candle.
@ -597,7 +597,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(
sell_reason=SellType.TRAILING_STOP_LOSS,
sell_reason=ExitType.TRAILING_STOP_LOSS,
open_tick=1,
close_tick=1,
enter_tag='buy_signal_01'
@ -617,7 +617,7 @@ tc33s = 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=SellType.TRAILING_STOP_LOSS,
sell_reason=ExitType.TRAILING_STOP_LOSS,
open_tick=1,
close_tick=1,
enter_tag='short_signal_01',
@ -647,7 +647,7 @@ tc35 = 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=SellType.STOP_LOSS, open_tick=1, close_tick=1)
BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1)
])
# Test 35s: Custom-entry-price above all candles should have rate adjusted to "entry candle high"
@ -661,7 +661,7 @@ tc35s = BTContainer(data=[
stop_loss=-0.01, roi={"0": 0.10}, profit_perc=-0.01,
custom_entry_price=4000,
trades=[
BTrade(sell_reason=SellType.STOP_LOSS, open_tick=1, close_tick=1, is_short=True)
BTrade(sell_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1, is_short=True)
]
)
@ -678,7 +678,7 @@ tc36 = 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=SellType.ROI, open_tick=1, close_tick=2)]
trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=2)]
)
# Test 37: Custom-entry-price around candle low
@ -693,7 +693,7 @@ tc37 = 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=SellType.ROI, open_tick=1, close_tick=1)]
trades=[BTrade(sell_reason=ExitType.ROI, open_tick=1, close_tick=1)]
)
# Test 38: Custom exit price below all candles
@ -708,7 +708,7 @@ tc38 = 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=SellType.SELL_SIGNAL, open_tick=1, close_tick=3)]
trades=[BTrade(sell_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=3)]
)
# Test 39: Custom exit price above all candles
@ -723,7 +723,7 @@ tc39 = 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=SellType.FORCE_SELL, open_tick=1, close_tick=4)]
trades=[BTrade(sell_reason=ExitType.FORCE_SELL, open_tick=1, close_tick=4)]
)
# Test 39: Custom short exit price above below candles
@ -738,7 +738,7 @@ tc39a = 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=SellType.FORCE_SELL, open_tick=1, close_tick=4, is_short=True)]
trades=[BTrade(sell_reason=ExitType.FORCE_SELL, open_tick=1, close_tick=4, is_short=True)]
)
# Test 40: Colliding long and short signal

View File

@ -19,7 +19,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.exchange.exchange import timeframe_to_next_date
from freqtrade.misc import get_strategy_run_id
@ -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 == SellType.ROI.value
assert res.sell_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 == SellType.ROI.value
assert res.sell_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': [SellType.ROI.value, SellType.ROI.value],
'sell_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],
@ -1219,7 +1219,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': [SellType.ROI, SellType.ROI]
'sell_reason': [ExitType.ROI, ExitType.ROI]
})
result2 = pd.DataFrame({'pair': ['XRP/BTC', 'LTC/BTC', 'ETH/BTC'],
'profit_ratio': [0.03, 0.01, 0.1],
@ -1237,7 +1237,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': [SellType.ROI, SellType.ROI, SellType.STOP_LOSS]
'sell_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS]
})
backtestmock = MagicMock(side_effect=[
{
@ -1337,7 +1337,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': [SellType.ROI, SellType.ROI]
'sell_reason': [ExitType.ROI, ExitType.ROI]
})
result2 = pd.DataFrame({'pair': ['XRP/USDT', 'XRP/USDT', 'XRP/USDT'],
'profit_ratio': [0.03, 0.01, 0.1],
@ -1355,7 +1355,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': [SellType.ROI, SellType.ROI, SellType.STOP_LOSS]
'sell_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS]
})
backtestmock = MagicMock(side_effect=[
{
@ -1440,7 +1440,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': [SellType.ROI, SellType.ROI]
'sell_reason': [ExitType.ROI, ExitType.ROI]
})
result2 = pd.DataFrame({'pair': ['XRP/BTC', 'LTC/BTC', 'ETH/BTC'],
'profit_ratio': [0.03, 0.01, 0.1],
@ -1458,7 +1458,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': [SellType.ROI, SellType.ROI, SellType.STOP_LOSS]
'sell_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS]
})
backtestmock = MagicMock(side_effect=[
{

View File

@ -8,7 +8,7 @@ from arrow import Arrow
from freqtrade.configuration import TimeRange
from freqtrade.data import history
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
@ -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': [SellType.ROI.value, SellType.ROI.value],
'sell_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],

View File

@ -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
@ -357,8 +357,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],
"sell_reason": [SellType.ROI, SellType.STOP_LOSS,
SellType.ROI, SellType.FORCE_SELL]
"sell_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],
"sell_reason": [SellType.ROI, SellType.STOP_LOSS,
SellType.ROI, SellType.FORCE_SELL]
"sell_reason": [ExitType.ROI, ExitType.STOP_LOSS,
ExitType.ROI, ExitType.FORCE_SELL]
}),
'config': hyperopt_conf,
'locks': [],

View File

@ -12,7 +12,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,
@ -77,8 +77,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],
"sell_reason": [SellType.ROI, SellType.STOP_LOSS,
SellType.ROI, SellType.FORCE_SELL]
"sell_reason": [ExitType.ROI, ExitType.STOP_LOSS,
ExitType.ROI, ExitType.FORCE_SELL]
}),
'config': default_conf,
'locks': [],
@ -129,8 +129,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],
"sell_reason": [SellType.ROI, SellType.ROI,
SellType.STOP_LOSS, SellType.FORCE_SELL]
"sell_reason": [ExitType.ROI, ExitType.ROI,
ExitType.STOP_LOSS, ExitType.FORCE_SELL]
}),
'config': default_conf,
'locks': [],
@ -276,7 +276,7 @@ def test_text_table_sell_reason():
'wins': [2, 0, 0],
'draws': [0, 0, 0],
'losses': [0, 0, 1],
'sell_reason': [SellType.ROI, SellType.ROI, SellType.STOP_LOSS]
'sell_reason': [ExitType.ROI, ExitType.ROI, ExitType.STOP_LOSS]
}
)
@ -308,7 +308,7 @@ def test_generate_sell_reason_stats():
'wins': [2, 0, 0],
'draws': [0, 0, 0],
'losses': [0, 0, 1],
'sell_reason': [SellType.ROI.value, SellType.ROI.value, SellType.STOP_LOSS.value]
'sell_reason': [ExitType.ROI.value, ExitType.ROI.value, ExitType.STOP_LOSS.value]
}
)

View File

@ -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,
sell_reason: str = SellType.SELL_SIGNAL,
sell_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, sell_reason=SellType.STOP_LOSS.value,
'XRP/BTC', fee.return_value, False, sell_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, sell_reason=SellType.STOP_LOSS.value,
'BCH/BTC', fee.return_value, False, sell_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, sell_reason=SellType.STOP_LOSS.value,
'ETH/BTC', fee.return_value, False, sell_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, sell_reason=SellType.STOP_LOSS.value,
'LTC/BTC', fee.return_value, False, sell_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, sell_reason=SellType.STOP_LOSS.value,
pair, fee.return_value, False, sell_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, sell_reason=SellType.STOP_LOSS.value,
pair, fee.return_value, False, sell_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, sell_reason=SellType.STOP_LOSS.value,
'ETH/BTC', fee.return_value, False, sell_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, sell_reason=SellType.STOP_LOSS.value,
pair, fee.return_value, False, sell_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, sell_reason=SellType.STOP_LOSS.value,
'XRP/BTC', fee.return_value, False, sell_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, sell_reason=SellType.ROI.value,
'ETH/BTC', fee.return_value, False, sell_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, sell_reason=SellType.STOP_LOSS.value,
'XRP/BTC', fee.return_value, False, sell_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, sell_reason=SellType.STOP_LOSS.value,
'XRP/BTC', fee.return_value, False, sell_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, sell_reason=SellType.ROI.value,
'XRP/BTC', fee.return_value, False, sell_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, sell_reason=SellType.STOP_LOSS.value,
'XRP/BTC', fee.return_value, False, sell_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, sell_reason=SellType.STOP_LOSS.value,
'XRP/BTC', fee.return_value, False, sell_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, sell_reason=SellType.STOP_LOSS.value,
'ETH/BTC', fee.return_value, False, sell_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, sell_reason=SellType.STOP_LOSS.value,
'NEO/BTC', fee.return_value, False, sell_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, sell_reason=SellType.STOP_LOSS.value,
'XRP/BTC', fee.return_value, False, sell_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, sell_reason=SellType.STOP_LOSS.value,
'XRP/BTC', fee.return_value, False, sell_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, sell_reason=SellType.ROI.value,
'XRP/BTC', fee.return_value, False, sell_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, sell_reason=SellType.ROI.value,
'XRP/BTC', fee.return_value, False, sell_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')

View File

@ -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, SignalDirection, State
from freqtrade.enums import RPCMessageType, RunMode, ExitType, SignalDirection, State
from freqtrade.exceptions import OperationalException
from freqtrade.freqtradebot import FreqtradeBot
from freqtrade.loggers import setup_logging
@ -1059,7 +1059,7 @@ def test_telegram_forcesell_handle(default_conf, update, ticker, fee,
'fiat_currency': 'USD',
'buy_tag': ANY,
'enter_tag': ANY,
'sell_reason': SellType.FORCE_SELL.value,
'sell_reason': ExitType.FORCE_SELL.value,
'open_date': ANY,
'close_date': ANY,
'close_rate': ANY,
@ -1127,7 +1127,7 @@ def test_telegram_forcesell_down_handle(default_conf, update, ticker, fee,
'fiat_currency': 'USD',
'buy_tag': ANY,
'enter_tag': ANY,
'sell_reason': SellType.FORCE_SELL.value,
'sell_reason': ExitType.FORCE_SELL.value,
'open_date': ANY,
'close_date': ANY,
'close_rate': ANY,
@ -1185,7 +1185,7 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None
'fiat_currency': 'USD',
'buy_tag': ANY,
'enter_tag': ANY,
'sell_reason': SellType.FORCE_SELL.value,
'sell_reason': ExitType.FORCE_SELL.value,
'open_date': ANY,
'close_date': ANY,
'close_rate': ANY,
@ -1932,7 +1932,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None:
'stake_currency': 'ETH',
'fiat_currency': 'USD',
'enter_tag': 'buy_signal1',
'sell_reason': SellType.STOP_LOSS.value,
'sell_reason': ExitType.STOP_LOSS.value,
'open_date': arrow.utcnow().shift(hours=-1),
'close_date': arrow.utcnow(),
})
@ -1966,7 +1966,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None:
'profit_ratio': -0.57405275,
'stake_currency': 'ETH',
'enter_tag': 'buy_signal1',
'sell_reason': SellType.STOP_LOSS.value,
'sell_reason': ExitType.STOP_LOSS.value,
'open_date': arrow.utcnow().shift(days=-1, hours=-2, minutes=-30),
'close_date': arrow.utcnow(),
})
@ -2045,7 +2045,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': SellType.STOP_LOSS.value,
'sell_reason': ExitType.STOP_LOSS.value,
'open_date': arrow.utcnow().shift(days=-1, hours=-2, minutes=-30),
'close_date': arrow.utcnow(),
})
@ -2169,7 +2169,7 @@ def test_send_msg_sell_notification_no_fiat(
'stake_currency': 'ETH',
'fiat_currency': 'USD',
'enter_tag': enter_signal,
'sell_reason': SellType.STOP_LOSS.value,
'sell_reason': ExitType.STOP_LOSS.value,
'open_date': arrow.utcnow().shift(hours=-2, minutes=-35, seconds=-3),
'close_date': arrow.utcnow(),
})

View File

@ -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',
'sell_reason': SellType.STOP_LOSS.value
'sell_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',
'sell_reason': SellType.STOP_LOSS.value
'sell_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',
'sell_reason': SellType.STOP_LOSS.value
'sell_reason': ExitType.STOP_LOSS.value
}
webhook.send_msg(msg=msg)
assert msg_mock.call_count == 1

View File

@ -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 ExitCheckTuple, SellType, SignalDirection
from freqtrade.enums import ExitCheckTuple, ExitType, SignalDirection
from freqtrade.exceptions import OperationalException, StrategyError
from freqtrade.optimize.space import SKDecimal
from freqtrade.persistence import PairLocks, Trade
@ -409,22 +409,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,
@ -456,7 +456,7 @@ def test_stop_loss_reached(default_conf, fee, profit, adjusted, expected, traili
force_stoploss=0, high=None)
assert isinstance(sl_flag, ExitCheckTuple)
assert sl_flag.exit_type == expected
if expected == SellType.NONE:
if expected == ExitType.NONE:
assert sl_flag.exit_flag is False
else:
assert sl_flag.exit_flag is True
@ -467,7 +467,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.exit_type == expected2
if expected2 == SellType.NONE:
if expected2 == ExitType.NONE:
assert sl_flag.exit_flag is False
else:
assert sl_flag.exit_flag is True
@ -496,14 +496,14 @@ def test_custom_exit(default_conf, fee, caplog) -> None:
low=None, high=None)
assert res.exit_flag is False
assert res.exit_type == SellType.NONE
assert res.exit_type == ExitType.NONE
strategy.custom_exit = MagicMock(return_value=True)
res = strategy.should_exit(trade, 1, now,
enter=False, exit_=False,
low=None, high=None)
assert res.exit_flag is True
assert res.exit_type == SellType.CUSTOM_SELL
assert res.exit_type == ExitType.CUSTOM_SELL
assert res.exit_reason == 'custom_sell'
strategy.custom_exit = MagicMock(return_value='hello world')
@ -511,7 +511,7 @@ def test_custom_exit(default_conf, fee, caplog) -> None:
res = strategy.should_exit(trade, 1, now,
enter=False, exit_=False,
low=None, high=None)
assert res.exit_type == SellType.CUSTOM_SELL
assert res.exit_type == ExitType.CUSTOM_SELL
assert res.exit_flag is True
assert res.exit_reason == 'hello world'
@ -520,7 +520,7 @@ def test_custom_exit(default_conf, fee, caplog) -> None:
res = strategy.should_exit(trade, 1, now,
enter=False, exit_=False,
low=None, high=None)
assert res.exit_type == SellType.CUSTOM_SELL
assert res.exit_type == ExitType.CUSTOM_SELL
assert res.exit_flag is True
assert res.exit_reason == 'h' * 64
assert log_has_re('Custom sell reason returned from custom_exit is too long.*', caplog)

View File

@ -13,7 +13,7 @@ import pytest
from pandas import DataFrame
from freqtrade.constants import CANCEL_REASON, MATH_CLOSE_PREC, UNLIMITED_STAKE_AMOUNT
from freqtrade.enums import (CandleType, ExitCheckTuple, RPCMessageType, RunMode, SellType,
from freqtrade.enums import (CandleType, ExitCheckTuple, ExitType, RPCMessageType, RunMode,
SignalDirection, State)
from freqtrade.exceptions import (DependencyException, ExchangeError, InsufficientFundsError,
InvalidOrderException, OperationalException, PricingError,
@ -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 == SellType.STOP_LOSS.value
assert trade.sell_reason == ExitType.STOP_LOSS.value
def test_total_open_trades_stakes(mocker, default_conf_usdt, ticker_usdt, fee) -> None:
@ -1209,7 +1209,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(SellType.EMERGENCY_SELL)
assert trade.sell_reason == str(ExitType.EMERGENCY_SELL)
@pytest.mark.parametrize("is_short", [False, True])
@ -1292,7 +1292,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 == SellType.EMERGENCY_SELL.value
assert trade.sell_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)
@ -1304,7 +1304,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]['sell_reason'] == SellType.EMERGENCY_SELL.value
assert rpc_mock.call_args_list[1][0][0]['sell_reason'] == ExitType.EMERGENCY_SELL.value
assert rpc_mock.call_args_list[1][0][0]['order_type'] == 'market'
@ -2274,7 +2274,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)
@ -2316,7 +2316,7 @@ def test_handle_trade_use_sell_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)
@ -3100,7 +3100,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_check=ExitCheckTuple(exit_type=SellType.ROI)
exit_check=ExitCheckTuple(exit_type=ExitType.ROI)
)
assert rpc_mock.call_count == 0
assert freqtrade.strategy.confirm_trade_exit.call_count == 1
@ -3112,7 +3112,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_check=ExitCheckTuple(exit_type=SellType.ROI)
exit_check=ExitCheckTuple(exit_type=ExitType.ROI)
)
assert freqtrade.strategy.confirm_trade_exit.call_count == 1
@ -3137,7 +3137,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',
'sell_reason': SellType.ROI.value,
'sell_reason': ExitType.ROI.value,
'open_date': ANY,
'close_date': ANY,
'close_rate': ANY,
@ -3173,7 +3173,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_check=ExitCheckTuple(exit_type=SellType.STOP_LOSS))
exit_check=ExitCheckTuple(exit_type=ExitType.STOP_LOSS))
assert rpc_mock.call_count == 2
last_msg = rpc_mock.call_args_list[-1][0][0]
@ -3196,7 +3196,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',
'sell_reason': SellType.STOP_LOSS.value,
'sell_reason': ExitType.STOP_LOSS.value,
'open_date': ANY,
'close_date': ANY,
'close_rate': ANY,
@ -3248,7 +3248,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_check=ExitCheckTuple(exit_type=SellType.SELL_SIGNAL)
exit_check=ExitCheckTuple(exit_type=ExitType.SELL_SIGNAL)
)
# Sell price must be different to default bid price
@ -3276,7 +3276,7 @@ def test_execute_trade_exit_custom_exit_price(
'profit_ratio': profit_ratio,
'stake_currency': 'USDT',
'fiat_currency': 'USD',
'sell_reason': SellType.SELL_SIGNAL.value,
'sell_reason': ExitType.SELL_SIGNAL.value,
'open_date': ANY,
'close_date': ANY,
'close_rate': ANY,
@ -3319,7 +3319,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_check=ExitCheckTuple(exit_type=SellType.STOP_LOSS))
exit_check=ExitCheckTuple(exit_type=ExitType.STOP_LOSS))
assert rpc_mock.call_count == 2
last_msg = rpc_mock.call_args_list[-1][0][0]
@ -3343,7 +3343,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',
'sell_reason': SellType.STOP_LOSS.value,
'sell_reason': ExitType.STOP_LOSS.value,
'open_date': ANY,
'close_date': ANY,
'close_rate': ANY,
@ -3379,7 +3379,7 @@ def test_execute_trade_exit_sloe_cancel_exception(
trade.stoploss_order_id = "abcd"
freqtrade.execute_trade_exit(trade=trade, limit=1234,
exit_check=ExitCheckTuple(exit_type=SellType.STOP_LOSS))
exit_check=ExitCheckTuple(exit_type=ExitType.STOP_LOSS))
assert create_order_mock.call_count == 2
assert log_has('Could not cancel stoploss order abcd', caplog)
@ -3434,7 +3434,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_check=ExitCheckTuple(exit_type=SellType.STOP_LOSS)
exit_check=ExitCheckTuple(exit_type=ExitType.STOP_LOSS)
)
trade = Trade.query.first()
@ -3510,7 +3510,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 == SellType.STOPLOSS_ON_EXCHANGE.value
assert trade.sell_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
@ -3579,7 +3579,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_check=ExitCheckTuple(exit_type=SellType.ROI)
exit_check=ExitCheckTuple(exit_type=ExitType.ROI)
)
assert not trade.is_open
@ -3606,7 +3606,7 @@ def test_execute_trade_exit_market_order(
'profit_ratio': profit_ratio,
'stake_currency': 'USDT',
'fiat_currency': 'USD',
'sell_reason': SellType.ROI.value,
'sell_reason': ExitType.ROI.value,
'open_date': ANY,
'close_date': ANY,
'close_rate': ANY,
@ -3643,7 +3643,7 @@ def test_execute_trade_exit_insufficient_funds_error(default_conf_usdt, ticker_u
fetch_ticker=ticker_usdt_sell_up
)
sell_reason = ExitCheckTuple(exit_type=SellType.ROI)
sell_reason = ExitCheckTuple(exit_type=ExitType.ROI)
assert not freqtrade.execute_trade_exit(
trade=trade,
limit=ticker_usdt_sell_up()['ask' if is_short else 'bid'],
@ -3654,18 +3654,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,
@ -3693,11 +3693,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=ExitCheckTuple(
exit_type=SellType.NONE))
exit_type=ExitType.NONE))
freqtrade.enter_positions()
trade = Trade.query.first()
@ -3816,7 +3816,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_check=ExitCheckTuple(exit_type=SellType.STOP_LOSS)
exit_check=ExitCheckTuple(exit_type=ExitType.STOP_LOSS)
)
trade.close(ticker_usdt_sell_down()['bid'])
assert freqtrade.strategy.is_pair_locked(trade.pair)
@ -3874,7 +3874,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 == SellType.ROI.value
assert trade.sell_reason == ExitType.ROI.value
@pytest.mark.parametrize("is_short,val1,val2", [
@ -3936,7 +3936,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 == SellType.TRAILING_STOP_LOSS.value
assert trade.sell_reason == ExitType.TRAILING_STOP_LOSS.value
@pytest.mark.parametrize('offset,trail_if_reached,second_sl,is_short', [
@ -4042,7 +4042,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 == SellType.TRAILING_STOP_LOSS.value
assert trade.sell_reason == ExitType.TRAILING_STOP_LOSS.value
@pytest.mark.parametrize("is_short", [False, True])
@ -4088,7 +4088,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 == SellType.ROI.value
assert trade.sell_reason == ExitType.ROI.value
def test_get_real_amount_quote(default_conf_usdt, trades_for_order, buy_order_fee, fee, caplog,
@ -5145,7 +5145,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_check=ExitCheckTuple(exit_type=SellType.ROI)
exit_check=ExitCheckTuple(exit_type=ExitType.ROI)
)
assert trade.funding_fees == pytest.approx(sum(
trade.amount *

View File

@ -2,7 +2,7 @@ from unittest.mock import MagicMock
import pytest
from freqtrade.enums import ExitCheckTuple, SellType
from freqtrade.enums import ExitCheckTuple, ExitType
from freqtrade.persistence import Trade
from freqtrade.persistence.models import Order
from freqtrade.rpc.rpc import RPC
@ -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=[
ExitCheckTuple(exit_type=SellType.NONE),
ExitCheckTuple(exit_type=SellType.SELL_SIGNAL)]
ExitCheckTuple(exit_type=ExitType.NONE),
ExitCheckTuple(exit_type=ExitType.SELL_SIGNAL)]
)
cancel_order_mock = MagicMock()
mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss)
@ -115,7 +115,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.sell_reason == SellType.STOPLOSS_ON_EXCHANGE.value
assert trade.sell_reason == ExitType.STOPLOSS_ON_EXCHANGE.value
assert not trade.is_open
trade = trades[1]
@ -123,7 +123,7 @@ def test_may_execute_exit_stoploss_on_exchange_multi(default_conf, ticker, fee,
assert trade.is_open
trade = trades[2]
assert trade.sell_reason == SellType.SELL_SIGNAL.value
assert trade.sell_reason == ExitType.SELL_SIGNAL.value
assert not trade.is_open
@ -160,11 +160,11 @@ def test_forcebuy_last_unlimited(default_conf, ticker, fee, mocker, balance_rati
_notify_exit=MagicMock(),
)
should_sell_mock = MagicMock(side_effect=[
ExitCheckTuple(exit_type=SellType.NONE),
ExitCheckTuple(exit_type=SellType.SELL_SIGNAL),
ExitCheckTuple(exit_type=SellType.NONE),
ExitCheckTuple(exit_type=SellType.NONE),
ExitCheckTuple(exit_type=SellType.NONE)]
ExitCheckTuple(exit_type=ExitType.NONE),
ExitCheckTuple(exit_type=ExitType.SELL_SIGNAL),
ExitCheckTuple(exit_type=ExitType.NONE),
ExitCheckTuple(exit_type=ExitType.NONE),
ExitCheckTuple(exit_type=ExitType.NONE)]
)
mocker.patch("freqtrade.strategy.interface.IStrategy.should_exit", should_sell_mock)