SellType -> ExitType
This commit is contained in:
parent
f5805543ed
commit
e9d3903827
@ -13,7 +13,7 @@ from pandas import DataFrame
|
|||||||
from freqtrade.configuration import TimeRange
|
from freqtrade.configuration import TimeRange
|
||||||
from freqtrade.constants import DATETIME_PRINT_FORMAT, UNLIMITED_STAKE_AMOUNT
|
from freqtrade.constants import DATETIME_PRINT_FORMAT, UNLIMITED_STAKE_AMOUNT
|
||||||
from freqtrade.data.history import get_timerange, load_data, refresh_data
|
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.exceptions import OperationalException
|
||||||
from freqtrade.exchange.exchange import timeframe_to_seconds
|
from freqtrade.exchange.exchange import timeframe_to_seconds
|
||||||
from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist
|
from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist
|
||||||
@ -454,7 +454,7 @@ class Edge:
|
|||||||
|
|
||||||
if stop_index <= sell_index:
|
if stop_index <= sell_index:
|
||||||
exit_index = open_trade_index + stop_index
|
exit_index = open_trade_index + stop_index
|
||||||
exit_type = SellType.STOP_LOSS
|
exit_type = ExitType.STOP_LOSS
|
||||||
exit_price = stop_price
|
exit_price = stop_price
|
||||||
elif stop_index > sell_index:
|
elif stop_index > sell_index:
|
||||||
# If exit is SELL then we exit at the next candle
|
# If exit is SELL then we exit at the next candle
|
||||||
@ -464,7 +464,7 @@ class Edge:
|
|||||||
if len(ohlc_columns) - 1 < exit_index:
|
if len(ohlc_columns) - 1 < exit_index:
|
||||||
break
|
break
|
||||||
|
|
||||||
exit_type = SellType.SELL_SIGNAL
|
exit_type = ExitType.SELL_SIGNAL
|
||||||
exit_price = ohlc_columns[exit_index, 0]
|
exit_price = ohlc_columns[exit_index, 0]
|
||||||
|
|
||||||
trade = {'pair': pair,
|
trade = {'pair': pair,
|
||||||
|
@ -5,7 +5,7 @@ from freqtrade.enums.collateral import Collateral
|
|||||||
from freqtrade.enums.ordertypevalue import OrderTypeValues
|
from freqtrade.enums.ordertypevalue import OrderTypeValues
|
||||||
from freqtrade.enums.rpcmessagetype import RPCMessageType
|
from freqtrade.enums.rpcmessagetype import RPCMessageType
|
||||||
from freqtrade.enums.runmode import NON_UTIL_MODES, OPTIMIZE_MODES, TRADING_MODES, RunMode
|
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.signaltype import SignalDirection, SignalTagType, SignalType
|
||||||
from freqtrade.enums.state import State
|
from freqtrade.enums.state import State
|
||||||
from freqtrade.enums.tradingmode import TradingMode
|
from freqtrade.enums.tradingmode import TradingMode
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
class SellType(Enum):
|
class ExitType(Enum):
|
||||||
"""
|
"""
|
||||||
Enum to distinguish between sell reasons
|
Enum to distinguish between sell reasons
|
||||||
"""
|
"""
|
@ -17,7 +17,7 @@ from freqtrade.configuration import validate_config_consistency
|
|||||||
from freqtrade.data.converter import order_book_to_dataframe
|
from freqtrade.data.converter import order_book_to_dataframe
|
||||||
from freqtrade.data.dataprovider import DataProvider
|
from freqtrade.data.dataprovider import DataProvider
|
||||||
from freqtrade.edge import Edge
|
from freqtrade.edge import Edge
|
||||||
from freqtrade.enums import (Collateral, RPCMessageType, SellType, SignalDirection, State,
|
from freqtrade.enums import (Collateral, RPCMessageType, ExitType, SignalDirection, State,
|
||||||
TradingMode)
|
TradingMode)
|
||||||
from freqtrade.exceptions import (DependencyException, ExchangeError, InsufficientFundsError,
|
from freqtrade.exceptions import (DependencyException, ExchangeError, InsufficientFundsError,
|
||||||
InvalidOrderException, PricingError)
|
InvalidOrderException, PricingError)
|
||||||
@ -915,7 +915,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
logger.error(f'Unable to place a stoploss order on exchange. {e}')
|
logger.error(f'Unable to place a stoploss order on exchange. {e}')
|
||||||
logger.warning('Exiting the trade forcefully')
|
logger.warning('Exiting the trade forcefully')
|
||||||
self.execute_trade_exit(trade, trade.stop_loss, exit_reason=SellCheckTuple(
|
self.execute_trade_exit(trade, trade.stop_loss, exit_reason=SellCheckTuple(
|
||||||
sell_type=SellType.EMERGENCY_SELL))
|
sell_type=ExitType.EMERGENCY_SELL))
|
||||||
|
|
||||||
except ExchangeError:
|
except ExchangeError:
|
||||||
trade.stoploss_order_id = None
|
trade.stoploss_order_id = None
|
||||||
@ -947,7 +947,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
# We check if stoploss order is fulfilled
|
# We check if stoploss order is fulfilled
|
||||||
if stoploss_order and stoploss_order['status'] in ('closed', 'triggered'):
|
if stoploss_order and stoploss_order['status'] in ('closed', 'triggered'):
|
||||||
# TODO-lev: Update to exit reason
|
# 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,
|
self.update_trade_state(trade, trade.stoploss_order_id, stoploss_order,
|
||||||
stoploss_order=True)
|
stoploss_order=True)
|
||||||
# Lock pair for one candle to prevent immediate rebuys
|
# Lock pair for one candle to prevent immediate rebuys
|
||||||
@ -1102,7 +1102,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
try:
|
try:
|
||||||
self.execute_trade_exit(
|
self.execute_trade_exit(
|
||||||
trade, order.get('price'),
|
trade, order.get('price'),
|
||||||
exit_reason=SellCheckTuple(sell_type=SellType.EMERGENCY_SELL))
|
exit_reason=SellCheckTuple(sell_type=ExitType.EMERGENCY_SELL))
|
||||||
except DependencyException as exception:
|
except DependencyException as exception:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f'Unable to emergency sell trade {trade.pair}: {exception}')
|
f'Unable to emergency sell trade {trade.pair}: {exception}')
|
||||||
@ -1284,7 +1284,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
trade.open_date
|
trade.open_date
|
||||||
)
|
)
|
||||||
exit_type = 'sell' # TODO-lev: Update to exit
|
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'
|
exit_type = 'stoploss'
|
||||||
|
|
||||||
# if stoploss is on exchange and we are on dry_run mode,
|
# 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}")
|
logger.exception(f"Could not cancel stoploss order {trade.stoploss_order_id}")
|
||||||
|
|
||||||
order_type = ordertype or self.strategy.order_types[exit_type]
|
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!)
|
# Emergency sells (default to market!)
|
||||||
order_type = self.strategy.order_types.get("emergencysell", "market")
|
order_type = self.strategy.order_types.get("emergencysell", "market")
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ from freqtrade.data import history
|
|||||||
from freqtrade.data.btanalysis import trade_list_to_dataframe
|
from freqtrade.data.btanalysis import trade_list_to_dataframe
|
||||||
from freqtrade.data.converter import trim_dataframe, trim_dataframes
|
from freqtrade.data.converter import trim_dataframe, trim_dataframes
|
||||||
from freqtrade.data.dataprovider import DataProvider
|
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.exceptions import DependencyException, OperationalException
|
||||||
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds
|
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds
|
||||||
from freqtrade.mixins import LoggingMixin
|
from freqtrade.mixins import LoggingMixin
|
||||||
@ -314,7 +314,7 @@ class Backtesting:
|
|||||||
Get close rate for backtesting result
|
Get close rate for backtesting result
|
||||||
"""
|
"""
|
||||||
# Special handling if high or low hit STOP_LOSS or ROI
|
# 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]:
|
if trade.stop_loss > sell_row[HIGH_IDX]:
|
||||||
# our stoploss was already higher than candle high,
|
# our stoploss was already higher than candle high,
|
||||||
# possibly due to a cancelled trade exit.
|
# 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
|
# Special case: trailing triggers within same candle as trade opened. Assume most
|
||||||
# pessimistic price movement, which is moving just enough to arm stoploss and
|
# pessimistic price movement, which is moving just enough to arm stoploss and
|
||||||
# immediately going down to stop price.
|
# 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 (
|
if (
|
||||||
not self.strategy.use_custom_stoploss and self.strategy.trailing_stop
|
not self.strategy.use_custom_stoploss and self.strategy.trailing_stop
|
||||||
and self.strategy.trailing_only_offset_is_reached
|
and self.strategy.trailing_only_offset_is_reached
|
||||||
@ -345,7 +345,7 @@ class Backtesting:
|
|||||||
|
|
||||||
# Set close_rate to stoploss
|
# Set close_rate to stoploss
|
||||||
return trade.stop_loss
|
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)
|
roi_entry, roi = self.strategy.min_roi_reached_entry(trade_dur)
|
||||||
if roi is not None and roi_entry is not None:
|
if roi is not None and roi_entry is not None:
|
||||||
if roi == -1 and roi_entry % self.timeframe_min == 0:
|
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)
|
closerate = self._get_close_rate(sell_row, trade, sell, trade_dur)
|
||||||
# call the custom exit price,with default value as previous closerate
|
# call the custom exit price,with default value as previous closerate
|
||||||
current_profit = trade.calc_profit_ratio(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
|
# Custom exit pricing only for sell-signals
|
||||||
closerate = strategy_safe_wrapper(self.strategy.custom_exit_price,
|
closerate = strategy_safe_wrapper(self.strategy.custom_exit_price,
|
||||||
default_retval=closerate)(
|
default_retval=closerate)(
|
||||||
@ -542,7 +542,7 @@ class Backtesting:
|
|||||||
sell_row = data[pair][-1]
|
sell_row = data[pair][-1]
|
||||||
|
|
||||||
trade.close_date = sell_row[DATE_IDX].to_pydatetime()
|
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)
|
trade.close(sell_row[OPEN_IDX], show_msg=False)
|
||||||
LocalTrade.close_bt_trade(trade)
|
LocalTrade.close_bt_trade(trade)
|
||||||
# Deepcopy object to have wallets update correctly
|
# Deepcopy object to have wallets update correctly
|
||||||
|
@ -14,7 +14,7 @@ from sqlalchemy.pool import StaticPool
|
|||||||
from sqlalchemy.sql.schema import UniqueConstraint
|
from sqlalchemy.sql.schema import UniqueConstraint
|
||||||
|
|
||||||
from freqtrade.constants import DATETIME_PRINT_FORMAT, NON_OPEN_EXCHANGE_STATES
|
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.exceptions import DependencyException, OperationalException
|
||||||
from freqtrade.leverage import interest
|
from freqtrade.leverage import interest
|
||||||
from freqtrade.misc import safe_value_fallback
|
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'):
|
elif order_type in ('stop_loss_limit', 'stop-loss', 'stop-loss-limit', 'stop'):
|
||||||
self.stoploss_order_id = None
|
self.stoploss_order_id = None
|
||||||
self.close_rate_requested = self.stop_loss
|
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:
|
if self.is_open:
|
||||||
logger.info(f'{order_type.upper()} is hit for {self}.')
|
logger.info(f'{order_type.upper()} is hit for {self}.')
|
||||||
self.close(safe_value_fallback(order, 'average', 'price'))
|
self.close(safe_value_fallback(order, 'average', 'price'))
|
||||||
|
@ -3,7 +3,7 @@ import logging
|
|||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from typing import Any, Dict
|
from typing import Any, Dict
|
||||||
|
|
||||||
from freqtrade.enums import SellType
|
from freqtrade.enums import ExitType
|
||||||
from freqtrade.persistence import Trade
|
from freqtrade.persistence import Trade
|
||||||
from freqtrade.plugins.protections import IProtection, ProtectionReturn
|
from freqtrade.plugins.protections import IProtection, ProtectionReturn
|
||||||
|
|
||||||
@ -44,8 +44,8 @@ class StoplossGuard(IProtection):
|
|||||||
# filters = [
|
# filters = [
|
||||||
# Trade.is_open.is_(False),
|
# Trade.is_open.is_(False),
|
||||||
# Trade.close_date > look_back_until,
|
# Trade.close_date > look_back_until,
|
||||||
# or_(Trade.exit_reason == SellType.STOP_LOSS.value,
|
# or_(Trade.exit_reason == ExitType.STOP_LOSS.value,
|
||||||
# and_(Trade.exit_reason == SellType.TRAILING_STOP_LOSS.value,
|
# and_(Trade.exit_reason == ExitType.TRAILING_STOP_LOSS.value,
|
||||||
# Trade.close_profit < 0))
|
# Trade.close_profit < 0))
|
||||||
# ]
|
# ]
|
||||||
# if pair:
|
# if pair:
|
||||||
@ -55,8 +55,8 @@ class StoplossGuard(IProtection):
|
|||||||
|
|
||||||
trades1 = Trade.get_trades_proxy(pair=pair, is_open=False, close_date=look_back_until)
|
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 (
|
trades = [trade for trade in trades1 if (str(trade.exit_reason) in (
|
||||||
SellType.TRAILING_STOP_LOSS.value, SellType.STOP_LOSS.value,
|
ExitType.TRAILING_STOP_LOSS.value, ExitType.STOP_LOSS.value,
|
||||||
SellType.STOPLOSS_ON_EXCHANGE.value)
|
ExitType.STOPLOSS_ON_EXCHANGE.value)
|
||||||
and trade.close_profit and trade.close_profit < 0)]
|
and trade.close_profit and trade.close_profit < 0)]
|
||||||
|
|
||||||
if len(trades) < self._trade_limit:
|
if len(trades) < self._trade_limit:
|
||||||
|
@ -17,7 +17,7 @@ from freqtrade import __version__
|
|||||||
from freqtrade.configuration.timerange import TimeRange
|
from freqtrade.configuration.timerange import TimeRange
|
||||||
from freqtrade.constants import CANCEL_REASON, DATETIME_PRINT_FORMAT
|
from freqtrade.constants import CANCEL_REASON, DATETIME_PRINT_FORMAT
|
||||||
from freqtrade.data.history import load_data
|
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.exceptions import ExchangeError, PricingError
|
||||||
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_msecs
|
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_msecs
|
||||||
from freqtrade.loggers import bufferHandler
|
from freqtrade.loggers import bufferHandler
|
||||||
@ -672,7 +672,7 @@ class RPC:
|
|||||||
closing_side = "buy" if trade.is_short else "sell"
|
closing_side = "buy" if trade.is_short else "sell"
|
||||||
current_rate = self._freqtrade.exchange.get_rate(
|
current_rate = self._freqtrade.exchange.get_rate(
|
||||||
trade.pair, refresh=False, side=closing_side)
|
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(
|
order_type = ordertype or self._freqtrade.strategy.order_types.get(
|
||||||
"forcesell", self._freqtrade.strategy.order_types["sell"])
|
"forcesell", self._freqtrade.strategy.order_types["sell"])
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ from pandas import DataFrame
|
|||||||
|
|
||||||
from freqtrade.constants import ListPairsWithTimeframes
|
from freqtrade.constants import ListPairsWithTimeframes
|
||||||
from freqtrade.data.dataprovider import DataProvider
|
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.exceptions import OperationalException, StrategyError
|
||||||
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds
|
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds
|
||||||
from freqtrade.exchange.exchange import timeframe_to_next_date
|
from freqtrade.exchange.exchange import timeframe_to_next_date
|
||||||
@ -34,16 +34,16 @@ class SellCheckTuple:
|
|||||||
"""
|
"""
|
||||||
NamedTuple for Sell type + reason
|
NamedTuple for Sell type + reason
|
||||||
"""
|
"""
|
||||||
sell_type: SellType
|
sell_type: ExitType
|
||||||
exit_reason: str = ''
|
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.sell_type = sell_type
|
||||||
self.exit_reason = exit_reason or sell_type.value
|
self.exit_reason = exit_reason or sell_type.value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def sell_flag(self):
|
def sell_flag(self):
|
||||||
return self.sell_type != SellType.NONE
|
return self.sell_type != ExitType.NONE
|
||||||
|
|
||||||
|
|
||||||
class IStrategy(ABC, HyperStrategyMixin):
|
class IStrategy(ABC, HyperStrategyMixin):
|
||||||
@ -784,7 +784,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
|||||||
and self.min_roi_reached(trade=trade, current_profit=current_profit,
|
and self.min_roi_reached(trade=trade, current_profit=current_profit,
|
||||||
current_time=date))
|
current_time=date))
|
||||||
|
|
||||||
sell_signal = SellType.NONE
|
sell_signal = ExitType.NONE
|
||||||
custom_reason = ''
|
custom_reason = ''
|
||||||
# use provided rate in backtesting, not high/low.
|
# use provided rate in backtesting, not high/low.
|
||||||
current_rate = rate
|
current_rate = rate
|
||||||
@ -795,14 +795,14 @@ class IStrategy(ABC, HyperStrategyMixin):
|
|||||||
pass
|
pass
|
||||||
elif self.use_exit_signal and not enter:
|
elif self.use_exit_signal and not enter:
|
||||||
if exit_:
|
if exit_:
|
||||||
sell_signal = SellType.SELL_SIGNAL
|
sell_signal = ExitType.SELL_SIGNAL
|
||||||
else:
|
else:
|
||||||
trade_type = "exit_short" if trade.is_short else "sell"
|
trade_type = "exit_short" if trade.is_short else "sell"
|
||||||
custom_reason = strategy_safe_wrapper(self.custom_sell, default_retval=False)(
|
custom_reason = strategy_safe_wrapper(self.custom_sell, default_retval=False)(
|
||||||
pair=trade.pair, trade=trade, current_time=date, current_rate=current_rate,
|
pair=trade.pair, trade=trade, current_time=date, current_rate=current_rate,
|
||||||
current_profit=current_profit)
|
current_profit=current_profit)
|
||||||
if custom_reason:
|
if custom_reason:
|
||||||
sell_signal = SellType.CUSTOM_SELL
|
sell_signal = ExitType.CUSTOM_SELL
|
||||||
if isinstance(custom_reason, str):
|
if isinstance(custom_reason, str):
|
||||||
if len(custom_reason) > CUSTOM_SELL_MAX_LENGTH:
|
if len(custom_reason) > CUSTOM_SELL_MAX_LENGTH:
|
||||||
logger.warning(f'Custom {trade_type} reason returned from '
|
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]
|
custom_reason = custom_reason[:CUSTOM_SELL_MAX_LENGTH]
|
||||||
else:
|
else:
|
||||||
custom_reason = None
|
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. "
|
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 ""))
|
(f", custom_reason={custom_reason}" if custom_reason else ""))
|
||||||
return SellCheckTuple(sell_type=sell_signal, exit_reason=custom_reason)
|
return SellCheckTuple(sell_type=sell_signal, exit_reason=custom_reason)
|
||||||
|
|
||||||
@ -821,9 +821,9 @@ class IStrategy(ABC, HyperStrategyMixin):
|
|||||||
# Exit-signal
|
# Exit-signal
|
||||||
# ROI (if not stoploss)
|
# ROI (if not stoploss)
|
||||||
# Stoploss
|
# Stoploss
|
||||||
if roi_reached and stoplossflag.sell_type != SellType.STOP_LOSS:
|
if roi_reached and stoplossflag.sell_type != ExitType.STOP_LOSS:
|
||||||
logger.debug(f"{trade.pair} - Required profit reached. sell_type=SellType.ROI")
|
logger.debug(f"{trade.pair} - Required profit reached. sell_type=ExitType.ROI")
|
||||||
return SellCheckTuple(sell_type=SellType.ROI)
|
return SellCheckTuple(sell_type=ExitType.ROI)
|
||||||
|
|
||||||
if stoplossflag.sell_flag:
|
if stoplossflag.sell_flag:
|
||||||
|
|
||||||
@ -832,7 +832,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
|||||||
|
|
||||||
# This one is noisy, commented out...
|
# This one is noisy, commented out...
|
||||||
# logger.debug(f"{trade.pair} - No exit signal.")
|
# 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,
|
def stop_loss_reached(self, current_rate: float, trade: Trade,
|
||||||
current_time: datetime, current_profit: float,
|
current_time: datetime, current_profit: float,
|
||||||
@ -896,11 +896,11 @@ class IStrategy(ABC, HyperStrategyMixin):
|
|||||||
if ((sl_higher_short or sl_lower_long) and
|
if ((sl_higher_short or sl_lower_long) and
|
||||||
(not self.order_types.get('stoploss_on_exchange') or self.config['dry_run'])):
|
(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 initial stoploss is not the same as current one then it is trailing.
|
||||||
if trade.initial_stop_loss != trade.stop_loss:
|
if trade.initial_stop_loss != trade.stop_loss:
|
||||||
sell_type = SellType.TRAILING_STOP_LOSS
|
sell_type = ExitType.TRAILING_STOP_LOSS
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"{trade.pair} - HIT STOP: current price at "
|
f"{trade.pair} - HIT STOP: current price at "
|
||||||
f"{((high if trade.is_short else low) or current_rate):.6f}, "
|
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=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]]:
|
def min_roi_reached_entry(self, trade_dur: int) -> Tuple[Optional[int], Optional[float]]:
|
||||||
"""
|
"""
|
||||||
|
@ -12,7 +12,7 @@ from pandas import DataFrame, to_datetime
|
|||||||
|
|
||||||
from freqtrade.data.converter import ohlcv_to_dataframe
|
from freqtrade.data.converter import ohlcv_to_dataframe
|
||||||
from freqtrade.edge import Edge, PairInfo
|
from freqtrade.edge import Edge, PairInfo
|
||||||
from freqtrade.enums import SellType
|
from freqtrade.enums import ExitType
|
||||||
from freqtrade.exceptions import OperationalException
|
from freqtrade.exceptions import OperationalException
|
||||||
from tests.conftest import get_patched_freqtradebot, log_has
|
from tests.conftest import get_patched_freqtradebot, log_has
|
||||||
from tests.optimize import (BTContainer, BTrade, _build_backtest_dataframe,
|
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
|
[6, 5000, 5025, 4975, 4987, 6172, 0, 0], # should sell
|
||||||
],
|
],
|
||||||
stop_loss=-0.99, roi={"0": float('inf')}, profit_perc=0.00,
|
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),
|
trades=[BTrade(exit_reason=ExitType.SELL_SIGNAL, open_tick=1, close_tick=2),
|
||||||
BTrade(exit_reason=SellType.SELL_SIGNAL, open_tick=4, close_tick=6)]
|
BTrade(exit_reason=ExitType.SELL_SIGNAL, open_tick=4, close_tick=6)]
|
||||||
)
|
)
|
||||||
|
|
||||||
# 3) Entered, sl 1%, candle drops 8% => Trade closed, 1% loss
|
# 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],
|
[2, 5000, 5025, 4975, 4987, 6172, 0, 0],
|
||||||
],
|
],
|
||||||
stop_loss=-0.01, roi={"0": float('inf')}, profit_perc=-0.01,
|
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
|
# 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],
|
[2, 5000, 5025, 4975, 4987, 6172, 0, 0],
|
||||||
],
|
],
|
||||||
stop_loss=-0.03, roi={"0": float('inf')}, profit_perc=-0.03,
|
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
|
# 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],
|
[2, 5000, 5025, 4975, 4987, 6172, 0, 0],
|
||||||
],
|
],
|
||||||
stop_loss=-0.03, roi={"0": float('inf')}, profit_perc=-0.03,
|
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 = [
|
TESTS = [
|
||||||
|
@ -3,7 +3,7 @@ from typing import Dict, List, NamedTuple, Optional
|
|||||||
import arrow
|
import arrow
|
||||||
from pandas import DataFrame
|
from pandas import DataFrame
|
||||||
|
|
||||||
from freqtrade.enums import SellType
|
from freqtrade.enums import ExitType
|
||||||
from freqtrade.exchange import timeframe_to_minutes
|
from freqtrade.exchange import timeframe_to_minutes
|
||||||
|
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ class BTrade(NamedTuple):
|
|||||||
"""
|
"""
|
||||||
Minimalistic Trade result used for functional backtesting
|
Minimalistic Trade result used for functional backtesting
|
||||||
"""
|
"""
|
||||||
exit_reason: SellType
|
exit_reason: ExitType
|
||||||
open_tick: int
|
open_tick: int
|
||||||
close_tick: int
|
close_tick: int
|
||||||
enter_tag: Optional[str] = None
|
enter_tag: Optional[str] = None
|
||||||
|
@ -5,7 +5,7 @@ from pathlib import Path
|
|||||||
import pandas as pd
|
import pandas as pd
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from freqtrade.enums import RunMode, SellType
|
from freqtrade.enums import RunMode, ExitType
|
||||||
from freqtrade.optimize.hyperopt import Hyperopt
|
from freqtrade.optimize.hyperopt import Hyperopt
|
||||||
from tests.conftest import patch_exchange
|
from tests.conftest import patch_exchange
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ def hyperopt_results():
|
|||||||
'profit_abs': [-0.2, 0.4, -0.2, 0.6],
|
'profit_abs': [-0.2, 0.4, -0.2, 0.6],
|
||||||
'trade_duration': [10, 30, 10, 10],
|
'trade_duration': [10, 30, 10, 10],
|
||||||
'amount': [0.1, 0.1, 0.1, 0.1],
|
'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':
|
'open_date':
|
||||||
[
|
[
|
||||||
datetime(2019, 1, 1, 9, 15, 0),
|
datetime(2019, 1, 1, 9, 15, 0),
|
||||||
|
@ -4,7 +4,7 @@ import logging
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from freqtrade.data.history import get_timerange
|
from freqtrade.data.history import get_timerange
|
||||||
from freqtrade.enums import SellType
|
from freqtrade.enums import ExitType
|
||||||
from freqtrade.optimize.backtesting import Backtesting
|
from freqtrade.optimize.backtesting import Backtesting
|
||||||
from tests.conftest import patch_exchange
|
from tests.conftest import patch_exchange
|
||||||
from tests.optimize import (BTContainer, BTrade, _build_backtest_dataframe,
|
from tests.optimize import (BTContainer, BTrade, _build_backtest_dataframe,
|
||||||
@ -22,7 +22,7 @@ tc0 = BTContainer(data=[
|
|||||||
[4, 5010, 5011, 4977, 4995, 6172, 0, 0],
|
[4, 5010, 5011, 4977, 4995, 6172, 0, 0],
|
||||||
[5, 4995, 4995, 4950, 4950, 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,
|
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
|
# Test 1: Stop-Loss Triggered 1% loss
|
||||||
@ -36,7 +36,7 @@ tc1 = BTContainer(data=[
|
|||||||
[4, 4977, 4995, 4977, 4995, 6172, 0, 0],
|
[4, 4977, 4995, 4977, 4995, 6172, 0, 0],
|
||||||
[5, 4995, 4995, 4950, 4950, 6172, 0, 0]],
|
[5, 4995, 4995, 4950, 4950, 6172, 0, 0]],
|
||||||
stop_loss=-0.01, roi={"0": 1}, profit_perc=-0.01,
|
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],
|
[4, 4962, 4987, 4937, 4950, 6172, 0, 0],
|
||||||
[5, 4950, 4975, 4925, 4950, 6172, 0, 0]],
|
[5, 4950, 4975, 4925, 4950, 6172, 0, 0]],
|
||||||
stop_loss=-0.03, roi={"0": 1}, profit_perc=-0.03,
|
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
|
[5, 4962, 4987, 4000, 4000, 6172, 0, 0], # exit with stoploss hit
|
||||||
[6, 4950, 4975, 4950, 4950, 6172, 0, 0]],
|
[6, 4950, 4975, 4950, 4950, 6172, 0, 0]],
|
||||||
stop_loss=-0.02, roi={"0": 1}, profit_perc=-0.04,
|
stop_loss=-0.02, roi={"0": 1}, profit_perc=-0.04,
|
||||||
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),
|
||||||
BTrade(exit_reason=SellType.STOP_LOSS, open_tick=4, close_tick=5)]
|
BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=4, close_tick=5)]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Test 4: Minus 3% / recovery +15%
|
# Test 4: Minus 3% / recovery +15%
|
||||||
@ -88,7 +88,7 @@ tc4 = BTContainer(data=[
|
|||||||
[4, 4962, 4987, 4937, 4950, 6172, 0, 0],
|
[4, 4962, 4987, 4937, 4950, 6172, 0, 0],
|
||||||
[5, 4950, 4975, 4925, 4950, 6172, 0, 0]],
|
[5, 4950, 4975, 4925, 4950, 6172, 0, 0]],
|
||||||
stop_loss=-0.02, roi={"0": 0.06}, profit_perc=-0.02,
|
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
|
# 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],
|
[4, 4962, 4987, 4962, 4972, 6172, 0, 0],
|
||||||
[5, 4950, 4975, 4925, 4950, 6172, 0, 0]],
|
[5, 4950, 4975, 4925, 4950, 6172, 0, 0]],
|
||||||
stop_loss=-0.01, roi={"0": 0.03}, profit_perc=0.03,
|
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
|
# 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],
|
[4, 4962, 4987, 4950, 4950, 6172, 0, 0],
|
||||||
[5, 4950, 4975, 4925, 4950, 6172, 0, 0]],
|
[5, 4950, 4975, 4925, 4950, 6172, 0, 0]],
|
||||||
stop_loss=-0.02, roi={"0": 0.05}, profit_perc=-0.02,
|
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
|
# 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],
|
[4, 4962, 4987, 4950, 4950, 6172, 0, 0],
|
||||||
[5, 4950, 4975, 4925, 4950, 6172, 0, 0]],
|
[5, 4950, 4975, 4925, 4950, 6172, 0, 0]],
|
||||||
stop_loss=-0.02, roi={"0": 0.03}, profit_perc=0.03,
|
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],
|
[3, 4850, 5050, 4650, 4750, 6172, 0, 0],
|
||||||
[4, 4750, 4950, 4350, 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,
|
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],
|
[3, 5000, 5200, 4550, 4850, 6172, 0, 0],
|
||||||
[4, 4750, 4950, 4350, 4750, 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,
|
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
|
# 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,
|
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_only_offset_is_reached=True, trailing_stop_positive_offset=0.10,
|
||||||
trailing_stop_positive=0.03,
|
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
|
# 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,
|
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_only_offset_is_reached=True, trailing_stop_positive_offset=0.05,
|
||||||
trailing_stop_positive=0.03,
|
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
|
# 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,
|
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_only_offset_is_reached=True, trailing_stop_positive_offset=0.05,
|
||||||
trailing_stop_positive=0.03,
|
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
|
# Test 13: Buy and sell ROI on same candle
|
||||||
@ -219,7 +219,7 @@ tc13 = BTContainer(data=[
|
|||||||
[3, 4850, 5050, 4750, 4750, 6172, 0, 0],
|
[3, 4850, 5050, 4750, 4750, 6172, 0, 0],
|
||||||
[4, 4750, 4950, 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,
|
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
|
# Test 14 - Buy and Stoploss on same candle
|
||||||
@ -232,7 +232,7 @@ tc14 = BTContainer(data=[
|
|||||||
[3, 4850, 5050, 4750, 4750, 6172, 0, 0],
|
[3, 4850, 5050, 4750, 4750, 6172, 0, 0],
|
||||||
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
|
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
|
||||||
stop_loss=-0.05, roi={"0": 0.10}, profit_perc=-0.05,
|
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],
|
[3, 4850, 5050, 4750, 4750, 6172, 0, 0],
|
||||||
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
|
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
|
||||||
stop_loss=-0.05, roi={"0": 0.01}, profit_perc=-0.04,
|
stop_loss=-0.05, roi={"0": 0.01}, profit_perc=-0.04,
|
||||||
trades=[BTrade(exit_reason=SellType.ROI, open_tick=1, close_tick=1),
|
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=1),
|
||||||
BTrade(exit_reason=SellType.STOP_LOSS, open_tick=2, close_tick=2)]
|
BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=2, close_tick=2)]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Test 16: Buy, hold for 65 min, then forcesell using roi=-1
|
# 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],
|
[4, 4962, 4987, 4950, 4950, 6172, 0, 0],
|
||||||
[5, 4950, 4975, 4925, 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,
|
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
|
# 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],
|
[4, 4962, 4987, 4950, 4950, 6172, 0, 0],
|
||||||
[5, 4950, 4975, 4925, 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,
|
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],
|
[4, 4962, 4987, 4950, 4950, 6172, 0, 0],
|
||||||
[5, 4950, 4975, 4925, 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,
|
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.
|
# 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],
|
[4, 4962, 4987, 4950, 4950, 6172, 0, 0],
|
||||||
[5, 4550, 4975, 4550, 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,
|
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.
|
# 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],
|
[4, 4962, 4987, 4950, 4950, 6172, 0, 0],
|
||||||
[5, 4925, 4975, 4925, 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,
|
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.
|
# 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,
|
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_only_offset_is_reached=True, trailing_stop_positive_offset=0.05,
|
||||||
trailing_stop_positive=0.03,
|
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.
|
# 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,
|
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_only_offset_is_reached=True, trailing_stop_positive_offset=0.05,
|
||||||
trailing_stop_positive=0.03,
|
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)
|
# 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,
|
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_only_offset_is_reached=True, trailing_stop_positive_offset=0.05,
|
||||||
trailing_stop_positive=0.03,
|
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)
|
# 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],
|
[4, 5010, 5010, 4977, 4995, 6172, 0, 0],
|
||||||
[5, 4995, 4995, 4950, 4950, 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,
|
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)
|
# 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
|
[4, 5010, 5010, 4855, 4995, 6172, 0, 0], # Triggers stoploss + sellsignal acted on
|
||||||
[5, 4995, 4995, 4950, 4950, 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,
|
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)
|
# 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],
|
[4, 5010, 5010, 4855, 4995, 6172, 0, 0],
|
||||||
[5, 4995, 4995, 4950, 4950, 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,
|
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)
|
# 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
|
[4, 5010, 5251, 4855, 4995, 6172, 0, 0], # Triggers ROI, sell-signal acted on
|
||||||
[5, 4995, 4995, 4950, 4950, 6172, 0, 0]],
|
[5, 4995, 4995, 4950, 4950, 6172, 0, 0]],
|
||||||
stop_loss=-0.10, roi={"0": 0.05}, profit_perc=0.002, use_exit_signal=True,
|
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
|
# 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,
|
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_only_offset_is_reached=True, trailing_stop_positive_offset=0.05,
|
||||||
trailing_stop_positive=0.03,
|
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
|
# 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]],
|
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
|
||||||
stop_loss=-0.10, roi={"0": 0.10}, profit_perc=-0.02, trailing_stop=True,
|
stop_loss=-0.10, roi={"0": 0.10}, profit_perc=-0.02, trailing_stop=True,
|
||||||
trailing_stop_positive=0.03,
|
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.
|
# 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]],
|
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
|
||||||
stop_loss=-0.10, roi={"0": 0.10}, profit_perc=-0.01, trailing_stop=True,
|
stop_loss=-0.10, roi={"0": 0.10}, profit_perc=-0.01, trailing_stop=True,
|
||||||
trailing_stop_positive=0.01,
|
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.
|
# 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,
|
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_only_offset_is_reached=True, trailing_stop_positive_offset=0.02,
|
||||||
trailing_stop_positive=0.01,
|
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.
|
# 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,
|
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_only_offset_is_reached=True, trailing_stop_positive_offset=0.02,
|
||||||
trailing_stop_positive=0.01, use_custom_stoploss=True,
|
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.
|
# 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_only_offset_is_reached=True, trailing_stop_positive_offset=0.02,
|
||||||
trailing_stop_positive=0.01, use_custom_stoploss=True,
|
trailing_stop_positive=0.01, use_custom_stoploss=True,
|
||||||
trades=[BTrade(
|
trades=[BTrade(
|
||||||
exit_reason=SellType.TRAILING_STOP_LOSS,
|
exit_reason=ExitType.TRAILING_STOP_LOSS,
|
||||||
open_tick=1,
|
open_tick=1,
|
||||||
close_tick=1,
|
close_tick=1,
|
||||||
enter_tag='buy_signal_01'
|
enter_tag='buy_signal_01'
|
||||||
@ -548,7 +548,7 @@ tc34 = BTContainer(data=[
|
|||||||
[5, 4995, 4995, 4950, 4950, 6172, 0, 0]],
|
[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,
|
stop_loss=-0.01, roi={"0": 1}, profit_perc=0.002 * 5.0, use_exit_signal=True,
|
||||||
leverage=5.0,
|
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 = [
|
TESTS = [
|
||||||
|
@ -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.converter import clean_ohlcv_dataframe
|
||||||
from freqtrade.data.dataprovider import DataProvider
|
from freqtrade.data.dataprovider import DataProvider
|
||||||
from freqtrade.data.history import get_timerange
|
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.exceptions import DependencyException, OperationalException
|
||||||
from freqtrade.optimize.backtesting import Backtesting
|
from freqtrade.optimize.backtesting import Backtesting
|
||||||
from freqtrade.persistence import LocalTrade
|
from freqtrade.persistence import LocalTrade
|
||||||
@ -628,7 +628,7 @@ def test_backtest__get_sell_trade_entry(default_conf, fee, mocker) -> None:
|
|||||||
# No data available.
|
# No data available.
|
||||||
res = backtesting._get_sell_trade_entry(trade, row_sell)
|
res = backtesting._get_sell_trade_entry(trade, row_sell)
|
||||||
assert res is not None
|
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)
|
assert res.close_date_utc == datetime(2020, 1, 1, 5, 0, tzinfo=timezone.utc)
|
||||||
|
|
||||||
# Enter new trade
|
# 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)
|
res = backtesting._get_sell_trade_entry(trade, row_sell)
|
||||||
assert res is not None
|
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!)
|
# Sell at minute 3 (not available above!)
|
||||||
assert res.close_date_utc == datetime(2020, 1, 1, 5, 3, tzinfo=timezone.utc)
|
assert res.close_date_utc == datetime(2020, 1, 1, 5, 3, tzinfo=timezone.utc)
|
||||||
assert round(res.close_rate, 3) == round(209.0225, 3)
|
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],
|
'trade_duration': [235, 40],
|
||||||
'profit_ratio': [0.0, 0.0],
|
'profit_ratio': [0.0, 0.0],
|
||||||
'profit_abs': [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_abs': [0.0940005, 0.09272236],
|
||||||
'initial_stop_loss_ratio': [-0.1, -0.1],
|
'initial_stop_loss_ratio': [-0.1, -0.1],
|
||||||
'stop_loss_abs': [0.0940005, 0.09272236],
|
'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],
|
'close_rate': [0.104969, 0.103541],
|
||||||
"is_short": [False, False],
|
"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'],
|
result2 = pd.DataFrame({'pair': ['XRP/BTC', 'LTC/BTC', 'ETH/BTC'],
|
||||||
'profit_ratio': [0.03, 0.01, 0.1],
|
'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],
|
'open_rate': [0.104445, 0.10302485, 0.122541],
|
||||||
'close_rate': [0.104969, 0.103541, 0.123541],
|
'close_rate': [0.104969, 0.103541, 0.123541],
|
||||||
"is_short": [False, False, False],
|
"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=[
|
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],
|
'stake_amount': [0.01, 0.01],
|
||||||
'open_rate': [0.104445, 0.10302485],
|
'open_rate': [0.104445, 0.10302485],
|
||||||
'close_rate': [0.104969, 0.103541],
|
'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'],
|
result2 = pd.DataFrame({'pair': ['XRP/BTC', 'LTC/BTC', 'ETH/BTC'],
|
||||||
'profit_ratio': [0.03, 0.01, 0.1],
|
'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],
|
'stake_amount': [0.01, 0.01, 0.01],
|
||||||
'open_rate': [0.104445, 0.10302485, 0.122541],
|
'open_rate': [0.104445, 0.10302485, 0.122541],
|
||||||
'close_rate': [0.104969, 0.103541, 0.123541],
|
'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=[
|
backtestmock = MagicMock(side_effect=[
|
||||||
{
|
{
|
||||||
|
@ -10,7 +10,7 @@ from filelock import Timeout
|
|||||||
|
|
||||||
from freqtrade.commands.optimize_commands import setup_optimize_configuration, start_hyperopt
|
from freqtrade.commands.optimize_commands import setup_optimize_configuration, start_hyperopt
|
||||||
from freqtrade.data.history import load_data
|
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.exceptions import OperationalException
|
||||||
from freqtrade.optimize.hyperopt import Hyperopt
|
from freqtrade.optimize.hyperopt import Hyperopt
|
||||||
from freqtrade.optimize.hyperopt_auto import HyperOptAuto
|
from freqtrade.optimize.hyperopt_auto import HyperOptAuto
|
||||||
@ -359,8 +359,8 @@ def test_hyperopt_format_results(hyperopt):
|
|||||||
"is_open": [False, False, False, True],
|
"is_open": [False, False, False, True],
|
||||||
"is_short": [False, False, False, False],
|
"is_short": [False, False, False, False],
|
||||||
"stake_amount": [0.01, 0.01, 0.01, 0.01],
|
"stake_amount": [0.01, 0.01, 0.01, 0.01],
|
||||||
"exit_reason": [SellType.ROI, SellType.STOP_LOSS,
|
"exit_reason": [ExitType.ROI, ExitType.STOP_LOSS,
|
||||||
SellType.ROI, SellType.FORCE_SELL]
|
ExitType.ROI, ExitType.FORCE_SELL]
|
||||||
}),
|
}),
|
||||||
'config': hyperopt.config,
|
'config': hyperopt.config,
|
||||||
'locks': [],
|
'locks': [],
|
||||||
@ -428,8 +428,8 @@ def test_generate_optimizer(mocker, hyperopt_conf) -> None:
|
|||||||
"is_open": [False, False, False, True],
|
"is_open": [False, False, False, True],
|
||||||
"is_short": [False, False, False, False],
|
"is_short": [False, False, False, False],
|
||||||
"stake_amount": [0.01, 0.01, 0.01, 0.01],
|
"stake_amount": [0.01, 0.01, 0.01, 0.01],
|
||||||
"exit_reason": [SellType.ROI, SellType.STOP_LOSS,
|
"exit_reason": [ExitType.ROI, ExitType.STOP_LOSS,
|
||||||
SellType.ROI, SellType.FORCE_SELL]
|
ExitType.ROI, ExitType.FORCE_SELL]
|
||||||
}),
|
}),
|
||||||
'config': hyperopt_conf,
|
'config': hyperopt_conf,
|
||||||
'locks': [],
|
'locks': [],
|
||||||
|
@ -13,7 +13,7 @@ from freqtrade.data import history
|
|||||||
from freqtrade.data.btanalysis import (get_latest_backtest_filename, load_backtest_data,
|
from freqtrade.data.btanalysis import (get_latest_backtest_filename, load_backtest_data,
|
||||||
load_backtest_stats)
|
load_backtest_stats)
|
||||||
from freqtrade.edge import PairInfo
|
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,
|
from freqtrade.optimize.optimize_reports import (_get_resample_from_period, generate_backtest_stats,
|
||||||
generate_daily_stats, generate_edge_table,
|
generate_daily_stats, generate_edge_table,
|
||||||
generate_pair_metrics,
|
generate_pair_metrics,
|
||||||
@ -78,8 +78,8 @@ def test_generate_backtest_stats(default_conf, testdatadir, tmpdir):
|
|||||||
"is_open": [False, False, False, True],
|
"is_open": [False, False, False, True],
|
||||||
"is_short": [False, False, False, False],
|
"is_short": [False, False, False, False],
|
||||||
"stake_amount": [0.01, 0.01, 0.01, 0.01],
|
"stake_amount": [0.01, 0.01, 0.01, 0.01],
|
||||||
"exit_reason": [SellType.ROI, SellType.STOP_LOSS,
|
"exit_reason": [ExitType.ROI, ExitType.STOP_LOSS,
|
||||||
SellType.ROI, SellType.FORCE_SELL]
|
ExitType.ROI, ExitType.FORCE_SELL]
|
||||||
}),
|
}),
|
||||||
'config': default_conf,
|
'config': default_conf,
|
||||||
'locks': [],
|
'locks': [],
|
||||||
@ -127,8 +127,8 @@ def test_generate_backtest_stats(default_conf, testdatadir, tmpdir):
|
|||||||
"is_open": [False, False, False, True],
|
"is_open": [False, False, False, True],
|
||||||
"is_short": [False, False, False, False],
|
"is_short": [False, False, False, False],
|
||||||
"stake_amount": [0.01, 0.01, 0.01, 0.01],
|
"stake_amount": [0.01, 0.01, 0.01, 0.01],
|
||||||
"exit_reason": [SellType.ROI, SellType.ROI,
|
"exit_reason": [ExitType.ROI, ExitType.ROI,
|
||||||
SellType.STOP_LOSS, SellType.FORCE_SELL]
|
ExitType.STOP_LOSS, ExitType.FORCE_SELL]
|
||||||
}),
|
}),
|
||||||
'config': default_conf,
|
'config': default_conf,
|
||||||
'locks': [],
|
'locks': [],
|
||||||
@ -271,7 +271,7 @@ def test_text_table_exit_reason():
|
|||||||
'wins': [2, 0, 0],
|
'wins': [2, 0, 0],
|
||||||
'draws': [0, 0, 0],
|
'draws': [0, 0, 0],
|
||||||
'losses': [0, 0, 1],
|
'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],
|
'wins': [2, 0, 0],
|
||||||
'draws': [0, 0, 0],
|
'draws': [0, 0, 0],
|
||||||
'losses': [0, 0, 1],
|
'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],
|
'wins': [2, 0, 0],
|
||||||
'draws': [0, 0, 0],
|
'draws': [0, 0, 0],
|
||||||
'losses': [0, 0, 1],
|
'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}
|
), 'config': default_conf}
|
||||||
results['TestStrategy2'] = {'results': pd.DataFrame(
|
results['TestStrategy2'] = {'results': pd.DataFrame(
|
||||||
@ -356,7 +356,7 @@ def test_text_table_strategy(default_conf):
|
|||||||
'wins': [4, 1, 0],
|
'wins': [4, 1, 0],
|
||||||
'draws': [0, 0, 0],
|
'draws': [0, 0, 0],
|
||||||
'losses': [0, 0, 1],
|
'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}
|
), 'config': default_conf}
|
||||||
|
|
||||||
|
@ -4,14 +4,14 @@ from datetime import datetime, timedelta
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from freqtrade import constants
|
from freqtrade import constants
|
||||||
from freqtrade.enums import SellType
|
from freqtrade.enums import ExitType
|
||||||
from freqtrade.persistence import PairLocks, Trade
|
from freqtrade.persistence import PairLocks, Trade
|
||||||
from freqtrade.plugins.protectionmanager import ProtectionManager
|
from freqtrade.plugins.protectionmanager import ProtectionManager
|
||||||
from tests.conftest import get_patched_freqtradebot, log_has_re
|
from tests.conftest import get_patched_freqtradebot, log_has_re
|
||||||
|
|
||||||
|
|
||||||
def generate_mock_trade(pair: str, fee: float, is_open: bool,
|
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,
|
min_ago_open: int = None, min_ago_close: int = None,
|
||||||
profit_rate: float = 0.9
|
profit_rate: float = 0.9
|
||||||
):
|
):
|
||||||
@ -91,7 +91,7 @@ def test_stoploss_guard(mocker, default_conf, fee, caplog):
|
|||||||
caplog.clear()
|
caplog.clear()
|
||||||
|
|
||||||
Trade.query.session.add(generate_mock_trade(
|
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,
|
min_ago_open=200, min_ago_close=30,
|
||||||
))
|
))
|
||||||
|
|
||||||
@ -100,12 +100,12 @@ def test_stoploss_guard(mocker, default_conf, fee, caplog):
|
|||||||
caplog.clear()
|
caplog.clear()
|
||||||
# This trade does not count, as it's closed too long ago
|
# This trade does not count, as it's closed too long ago
|
||||||
Trade.query.session.add(generate_mock_trade(
|
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,
|
min_ago_open=250, min_ago_close=100,
|
||||||
))
|
))
|
||||||
|
|
||||||
Trade.query.session.add(generate_mock_trade(
|
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,
|
min_ago_open=240, min_ago_close=30,
|
||||||
))
|
))
|
||||||
# 3 Trades closed - but the 2nd has been closed too long ago.
|
# 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()
|
caplog.clear()
|
||||||
|
|
||||||
Trade.query.session.add(generate_mock_trade(
|
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,
|
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()
|
caplog.clear()
|
||||||
|
|
||||||
Trade.query.session.add(generate_mock_trade(
|
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,
|
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()
|
caplog.clear()
|
||||||
# This trade does not count, as it's closed too long ago
|
# This trade does not count, as it's closed too long ago
|
||||||
Trade.query.session.add(generate_mock_trade(
|
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,
|
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 does not count for per pair stop as it's the wrong pair.
|
||||||
Trade.query.session.add(generate_mock_trade(
|
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,
|
min_ago_open=240, min_ago_close=30, profit_rate=0.9,
|
||||||
))
|
))
|
||||||
# 3 Trades closed - but the 2nd has been closed too long ago.
|
# 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
|
# 2nd Trade that counts with correct pair
|
||||||
Trade.query.session.add(generate_mock_trade(
|
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,
|
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()
|
caplog.clear()
|
||||||
|
|
||||||
Trade.query.session.add(generate_mock_trade(
|
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,
|
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()
|
assert not PairLocks.is_global_lock()
|
||||||
|
|
||||||
Trade.query.session.add(generate_mock_trade(
|
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,
|
min_ago_open=205, min_ago_close=35,
|
||||||
))
|
))
|
||||||
|
|
||||||
@ -242,7 +242,7 @@ def test_LowProfitPairs(mocker, default_conf, fee, caplog):
|
|||||||
caplog.clear()
|
caplog.clear()
|
||||||
|
|
||||||
Trade.query.session.add(generate_mock_trade(
|
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,
|
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()
|
assert not PairLocks.is_global_lock()
|
||||||
|
|
||||||
Trade.query.session.add(generate_mock_trade(
|
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,
|
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
|
# Add positive trade
|
||||||
Trade.query.session.add(generate_mock_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,
|
min_ago_open=20, min_ago_close=10, profit_rate=1.15,
|
||||||
))
|
))
|
||||||
assert not freqtrade.protections.stop_per_pair('XRP/BTC')
|
assert not freqtrade.protections.stop_per_pair('XRP/BTC')
|
||||||
assert not PairLocks.is_pair_locked('XRP/BTC')
|
assert not PairLocks.is_pair_locked('XRP/BTC')
|
||||||
|
|
||||||
Trade.query.session.add(generate_mock_trade(
|
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,
|
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()
|
caplog.clear()
|
||||||
|
|
||||||
Trade.query.session.add(generate_mock_trade(
|
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,
|
min_ago_open=1000, min_ago_close=900, profit_rate=1.1,
|
||||||
))
|
))
|
||||||
Trade.query.session.add(generate_mock_trade(
|
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,
|
min_ago_open=1000, min_ago_close=900, profit_rate=1.1,
|
||||||
))
|
))
|
||||||
Trade.query.session.add(generate_mock_trade(
|
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,
|
min_ago_open=1000, min_ago_close=900, profit_rate=1.1,
|
||||||
))
|
))
|
||||||
# No losing trade yet ... so max_drawdown will raise exception
|
# 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')
|
assert not freqtrade.protections.stop_per_pair('XRP/BTC')
|
||||||
|
|
||||||
Trade.query.session.add(generate_mock_trade(
|
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,
|
min_ago_open=500, min_ago_close=400, profit_rate=0.9,
|
||||||
))
|
))
|
||||||
# Not locked with one trade
|
# Not locked with one trade
|
||||||
@ -326,7 +326,7 @@ def test_MaxDrawdown(mocker, default_conf, fee, caplog):
|
|||||||
assert not PairLocks.is_global_lock()
|
assert not PairLocks.is_global_lock()
|
||||||
|
|
||||||
Trade.query.session.add(generate_mock_trade(
|
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,
|
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!)
|
# Winning trade ... (should not lock, does not change drawdown!)
|
||||||
Trade.query.session.add(generate_mock_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=320, min_ago_close=410, profit_rate=1.5,
|
min_ago_open=320, min_ago_close=410, profit_rate=1.5,
|
||||||
))
|
))
|
||||||
assert not freqtrade.protections.global_stop()
|
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%
|
# Add additional negative trade, causing a loss of > 15%
|
||||||
Trade.query.session.add(generate_mock_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=0.8,
|
min_ago_open=20, min_ago_close=10, profit_rate=0.8,
|
||||||
))
|
))
|
||||||
assert not freqtrade.protections.stop_per_pair('XRP/BTC')
|
assert not freqtrade.protections.stop_per_pair('XRP/BTC')
|
||||||
|
@ -18,7 +18,7 @@ from telegram.error import BadRequest, NetworkError, TelegramError
|
|||||||
from freqtrade import __version__
|
from freqtrade import __version__
|
||||||
from freqtrade.constants import CANCEL_REASON
|
from freqtrade.constants import CANCEL_REASON
|
||||||
from freqtrade.edge import PairInfo
|
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.exceptions import OperationalException
|
||||||
from freqtrade.freqtradebot import FreqtradeBot
|
from freqtrade.freqtradebot import FreqtradeBot
|
||||||
from freqtrade.loggers import setup_logging
|
from freqtrade.loggers import setup_logging
|
||||||
@ -962,7 +962,7 @@ def test_telegram_forcesell_handle(default_conf, update, ticker, fee,
|
|||||||
'fiat_currency': 'USD',
|
'fiat_currency': 'USD',
|
||||||
'buy_tag': ANY,
|
'buy_tag': ANY,
|
||||||
'enter_tag': ANY,
|
'enter_tag': ANY,
|
||||||
'exit_reason': SellType.FORCE_SELL.value,
|
'exit_reason': ExitType.FORCE_SELL.value,
|
||||||
'open_date': ANY,
|
'open_date': ANY,
|
||||||
'close_date': ANY,
|
'close_date': ANY,
|
||||||
'close_rate': ANY,
|
'close_rate': ANY,
|
||||||
@ -1030,7 +1030,7 @@ def test_telegram_forcesell_down_handle(default_conf, update, ticker, fee,
|
|||||||
'fiat_currency': 'USD',
|
'fiat_currency': 'USD',
|
||||||
'buy_tag': ANY,
|
'buy_tag': ANY,
|
||||||
'enter_tag': ANY,
|
'enter_tag': ANY,
|
||||||
'exit_reason': SellType.FORCE_SELL.value,
|
'exit_reason': ExitType.FORCE_SELL.value,
|
||||||
'open_date': ANY,
|
'open_date': ANY,
|
||||||
'close_date': ANY,
|
'close_date': ANY,
|
||||||
'close_rate': ANY,
|
'close_rate': ANY,
|
||||||
@ -1088,7 +1088,7 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None
|
|||||||
'fiat_currency': 'USD',
|
'fiat_currency': 'USD',
|
||||||
'buy_tag': ANY,
|
'buy_tag': ANY,
|
||||||
'enter_tag': ANY,
|
'enter_tag': ANY,
|
||||||
'exit_reason': SellType.FORCE_SELL.value,
|
'exit_reason': ExitType.FORCE_SELL.value,
|
||||||
'open_date': ANY,
|
'open_date': ANY,
|
||||||
'close_date': ANY,
|
'close_date': ANY,
|
||||||
'close_rate': ANY,
|
'close_rate': ANY,
|
||||||
@ -1826,7 +1826,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None:
|
|||||||
'stake_currency': 'ETH',
|
'stake_currency': 'ETH',
|
||||||
'fiat_currency': 'USD',
|
'fiat_currency': 'USD',
|
||||||
'enter_tag': 'buy_signal1',
|
'enter_tag': 'buy_signal1',
|
||||||
'exit_reason': SellType.STOP_LOSS.value,
|
'exit_reason': ExitType.STOP_LOSS.value,
|
||||||
'open_date': arrow.utcnow().shift(hours=-1),
|
'open_date': arrow.utcnow().shift(hours=-1),
|
||||||
'close_date': arrow.utcnow(),
|
'close_date': arrow.utcnow(),
|
||||||
})
|
})
|
||||||
@ -1860,7 +1860,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None:
|
|||||||
'profit_ratio': -0.57405275,
|
'profit_ratio': -0.57405275,
|
||||||
'stake_currency': 'ETH',
|
'stake_currency': 'ETH',
|
||||||
'enter_tag': 'buy_signal1',
|
'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),
|
'open_date': arrow.utcnow().shift(days=-1, hours=-2, minutes=-30),
|
||||||
'close_date': arrow.utcnow(),
|
'close_date': arrow.utcnow(),
|
||||||
})
|
})
|
||||||
@ -1939,7 +1939,7 @@ def test_send_msg_sell_fill_notification(default_conf, mocker, direction,
|
|||||||
'profit_ratio': -0.57405275,
|
'profit_ratio': -0.57405275,
|
||||||
'stake_currency': 'ETH',
|
'stake_currency': 'ETH',
|
||||||
'enter_tag': enter_signal,
|
'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),
|
'open_date': arrow.utcnow().shift(days=-1, hours=-2, minutes=-30),
|
||||||
'close_date': arrow.utcnow(),
|
'close_date': arrow.utcnow(),
|
||||||
})
|
})
|
||||||
@ -2063,7 +2063,7 @@ def test_send_msg_sell_notification_no_fiat(
|
|||||||
'stake_currency': 'ETH',
|
'stake_currency': 'ETH',
|
||||||
'fiat_currency': 'USD',
|
'fiat_currency': 'USD',
|
||||||
'enter_tag': enter_signal,
|
'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),
|
'open_date': arrow.utcnow().shift(hours=-2, minutes=-35, seconds=-3),
|
||||||
'close_date': arrow.utcnow(),
|
'close_date': arrow.utcnow(),
|
||||||
})
|
})
|
||||||
|
@ -5,7 +5,7 @@ from unittest.mock import MagicMock
|
|||||||
import pytest
|
import pytest
|
||||||
from requests import RequestException
|
from requests import RequestException
|
||||||
|
|
||||||
from freqtrade.enums import RPCMessageType, SellType
|
from freqtrade.enums import RPCMessageType, ExitType
|
||||||
from freqtrade.rpc import RPC
|
from freqtrade.rpc import RPC
|
||||||
from freqtrade.rpc.webhook import Webhook
|
from freqtrade.rpc.webhook import Webhook
|
||||||
from tests.conftest import get_patched_freqtradebot, log_has
|
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_amount': 0.001,
|
||||||
'profit_ratio': 0.20,
|
'profit_ratio': 0.20,
|
||||||
'stake_currency': 'BTC',
|
'stake_currency': 'BTC',
|
||||||
'exit_reason': SellType.STOP_LOSS.value
|
'exit_reason': ExitType.STOP_LOSS.value
|
||||||
}
|
}
|
||||||
webhook.send_msg(msg=msg)
|
webhook.send_msg(msg=msg)
|
||||||
assert msg_mock.call_count == 1
|
assert msg_mock.call_count == 1
|
||||||
@ -269,7 +269,7 @@ def test_send_msg_webhook(default_conf, mocker):
|
|||||||
'profit_amount': 0.001,
|
'profit_amount': 0.001,
|
||||||
'profit_ratio': 0.20,
|
'profit_ratio': 0.20,
|
||||||
'stake_currency': 'BTC',
|
'stake_currency': 'BTC',
|
||||||
'exit_reason': SellType.STOP_LOSS.value
|
'exit_reason': ExitType.STOP_LOSS.value
|
||||||
}
|
}
|
||||||
webhook.send_msg(msg=msg)
|
webhook.send_msg(msg=msg)
|
||||||
assert msg_mock.call_count == 1
|
assert msg_mock.call_count == 1
|
||||||
@ -294,7 +294,7 @@ def test_send_msg_webhook(default_conf, mocker):
|
|||||||
'profit_amount': 0.001,
|
'profit_amount': 0.001,
|
||||||
'profit_ratio': 0.20,
|
'profit_ratio': 0.20,
|
||||||
'stake_currency': 'BTC',
|
'stake_currency': 'BTC',
|
||||||
'exit_reason': SellType.STOP_LOSS.value
|
'exit_reason': ExitType.STOP_LOSS.value
|
||||||
}
|
}
|
||||||
webhook.send_msg(msg=msg)
|
webhook.send_msg(msg=msg)
|
||||||
assert msg_mock.call_count == 1
|
assert msg_mock.call_count == 1
|
||||||
|
@ -11,7 +11,7 @@ from pandas import DataFrame
|
|||||||
from freqtrade.configuration import TimeRange
|
from freqtrade.configuration import TimeRange
|
||||||
from freqtrade.data.dataprovider import DataProvider
|
from freqtrade.data.dataprovider import DataProvider
|
||||||
from freqtrade.data.history import load_data
|
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.exceptions import OperationalException, StrategyError
|
||||||
from freqtrade.optimize.space import SKDecimal
|
from freqtrade.optimize.space import SKDecimal
|
||||||
from freqtrade.persistence import PairLocks, Trade
|
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,expected,trailing,custom,profit2,adjusted2,expected2,custom_stop', [
|
||||||
# Profit, adjusted stoploss(absolute), profit for 2nd call, enable trailing,
|
# Profit, adjusted stoploss(absolute), profit for 2nd call, enable trailing,
|
||||||
# enable custom stoploss, expected after 1st call, expected after 2nd call
|
# 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, ExitType.NONE, False, False, 0.3, 0.9, ExitType.NONE, None),
|
||||||
(0.2, 0.9, SellType.NONE, False, False, -0.2, 0.9, SellType.STOP_LOSS, None),
|
(0.2, 0.9, ExitType.NONE, False, False, -0.2, 0.9, ExitType.STOP_LOSS, None),
|
||||||
(0.2, 1.14, SellType.NONE, True, False, 0.05, 1.14, SellType.TRAILING_STOP_LOSS, None),
|
(0.2, 1.14, ExitType.NONE, True, False, 0.05, 1.14, ExitType.TRAILING_STOP_LOSS, None),
|
||||||
(0.01, 0.96, SellType.NONE, True, False, 0.05, 1, SellType.NONE, None),
|
(0.01, 0.96, ExitType.NONE, True, False, 0.05, 1, ExitType.NONE, None),
|
||||||
(0.05, 1, SellType.NONE, True, False, -0.01, 1, SellType.TRAILING_STOP_LOSS, None),
|
(0.05, 1, ExitType.NONE, True, False, -0.01, 1, ExitType.TRAILING_STOP_LOSS, None),
|
||||||
# Default custom case - trails with 10%
|
# 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, ExitType.NONE, False, True, -0.02, 0.95, ExitType.NONE, None),
|
||||||
(0.05, 0.95, SellType.NONE, False, True, -0.06, 0.95, SellType.TRAILING_STOP_LOSS, None),
|
(0.05, 0.95, ExitType.NONE, False, True, -0.06, 0.95, ExitType.TRAILING_STOP_LOSS, None),
|
||||||
(0.05, 1, SellType.NONE, False, True, -0.06, 1, SellType.TRAILING_STOP_LOSS,
|
(0.05, 1, ExitType.NONE, False, True, -0.06, 1, ExitType.TRAILING_STOP_LOSS,
|
||||||
lambda **kwargs: -0.05),
|
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),
|
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)),
|
lambda current_profit, **kwargs: -0.1 if current_profit < 0.6 else -(current_profit * 2)),
|
||||||
# Error case - static stoploss in place
|
# 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),
|
lambda **kwargs: None),
|
||||||
])
|
])
|
||||||
def test_stop_loss_reached(default_conf, fee, profit, adjusted, expected, trailing, custom,
|
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)
|
force_stoploss=0, high=None)
|
||||||
assert isinstance(sl_flag, SellCheckTuple)
|
assert isinstance(sl_flag, SellCheckTuple)
|
||||||
assert sl_flag.sell_type == expected
|
assert sl_flag.sell_type == expected
|
||||||
if expected == SellType.NONE:
|
if expected == ExitType.NONE:
|
||||||
assert sl_flag.sell_flag is False
|
assert sl_flag.sell_flag is False
|
||||||
else:
|
else:
|
||||||
assert sl_flag.sell_flag is True
|
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,
|
current_time=now, current_profit=profit2,
|
||||||
force_stoploss=0, high=None)
|
force_stoploss=0, high=None)
|
||||||
assert sl_flag.sell_type == expected2
|
assert sl_flag.sell_type == expected2
|
||||||
if expected2 == SellType.NONE:
|
if expected2 == ExitType.NONE:
|
||||||
assert sl_flag.sell_flag is False
|
assert sl_flag.sell_flag is False
|
||||||
else:
|
else:
|
||||||
assert sl_flag.sell_flag is True
|
assert sl_flag.sell_flag is True
|
||||||
@ -480,14 +480,14 @@ def test_custom_sell(default_conf, fee, caplog) -> None:
|
|||||||
low=None, high=None)
|
low=None, high=None)
|
||||||
|
|
||||||
assert res.sell_flag is False
|
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)
|
strategy.custom_sell = MagicMock(return_value=True)
|
||||||
res = strategy.should_exit(trade, 1, now,
|
res = strategy.should_exit(trade, 1, now,
|
||||||
enter=False, exit_=False,
|
enter=False, exit_=False,
|
||||||
low=None, high=None)
|
low=None, high=None)
|
||||||
assert res.sell_flag is True
|
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'
|
assert res.exit_reason == 'custom_sell'
|
||||||
|
|
||||||
strategy.custom_sell = MagicMock(return_value='hello world')
|
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,
|
res = strategy.should_exit(trade, 1, now,
|
||||||
enter=False, exit_=False,
|
enter=False, exit_=False,
|
||||||
low=None, high=None)
|
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.sell_flag is True
|
||||||
assert res.exit_reason == 'hello world'
|
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,
|
res = strategy.should_exit(trade, 1, now,
|
||||||
enter=False, exit_=False,
|
enter=False, exit_=False,
|
||||||
low=None, high=None)
|
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.sell_flag is True
|
||||||
assert res.exit_reason == 'h' * 64
|
assert res.exit_reason == 'h' * 64
|
||||||
assert log_has_re('Custom sell reason returned from custom_sell is too long.*', caplog)
|
assert log_has_re('Custom sell reason returned from custom_sell is too long.*', caplog)
|
||||||
|
@ -12,7 +12,7 @@ import pytest
|
|||||||
from pandas import DataFrame
|
from pandas import DataFrame
|
||||||
|
|
||||||
from freqtrade.constants import CANCEL_REASON, MATH_CLOSE_PREC, UNLIMITED_STAKE_AMOUNT
|
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,
|
from freqtrade.exceptions import (DependencyException, ExchangeError, InsufficientFundsError,
|
||||||
InvalidOrderException, OperationalException, PricingError,
|
InvalidOrderException, OperationalException, PricingError,
|
||||||
TemporaryError)
|
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
|
assert freqtrade.handle_trade(trade) is not ignore_strat_sl
|
||||||
if not ignore_strat_sl:
|
if not ignore_strat_sl:
|
||||||
assert log_has_re('Exit for NEO/BTC detected. Reason: stop_loss.*', caplog)
|
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:
|
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()
|
caplog.clear()
|
||||||
freqtrade.create_stoploss_order(trade, 200)
|
freqtrade.create_stoploss_order(trade, 200)
|
||||||
assert trade.stoploss_order_id is None
|
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("Unable to place a stoploss order on exchange. ", caplog)
|
||||||
assert log_has("Exiting the trade forcefully", 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
|
# Rpc is sending first buy, then sell
|
||||||
assert rpc_mock.call_count == 2
|
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'
|
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()
|
caplog.clear()
|
||||||
patch_get_signal(freqtrade)
|
patch_get_signal(freqtrade)
|
||||||
assert freqtrade.handle_trade(trade)
|
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)
|
caplog)
|
||||||
|
|
||||||
|
|
||||||
@ -2135,7 +2135,7 @@ def test_handle_trade_use_exit_signal(
|
|||||||
else:
|
else:
|
||||||
patch_get_signal(freqtrade, enter_long=False, exit_long=True)
|
patch_get_signal(freqtrade, enter_long=False, exit_long=True)
|
||||||
assert freqtrade.handle_trade(trade)
|
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)
|
caplog)
|
||||||
|
|
||||||
|
|
||||||
@ -2855,7 +2855,7 @@ def test_execute_trade_exit_up(default_conf_usdt, ticker_usdt, fee, ticker_usdt_
|
|||||||
freqtrade.execute_trade_exit(
|
freqtrade.execute_trade_exit(
|
||||||
trade=trade,
|
trade=trade,
|
||||||
limit=(ticker_usdt_sell_down()['ask'] if is_short else ticker_usdt_sell_up()['bid']),
|
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 rpc_mock.call_count == 0
|
||||||
assert freqtrade.strategy.confirm_trade_exit.call_count == 1
|
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(
|
freqtrade.execute_trade_exit(
|
||||||
trade=trade,
|
trade=trade,
|
||||||
limit=(ticker_usdt_sell_down()['ask'] if is_short else ticker_usdt_sell_up()['bid']),
|
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
|
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,
|
'profit_ratio': 0.00493809 if is_short else 0.09451372,
|
||||||
'stake_currency': 'USDT',
|
'stake_currency': 'USDT',
|
||||||
'fiat_currency': 'USD',
|
'fiat_currency': 'USD',
|
||||||
'exit_reason': SellType.ROI.value,
|
'exit_reason': ExitType.ROI.value,
|
||||||
'open_date': ANY,
|
'open_date': ANY,
|
||||||
'close_date': ANY,
|
'close_date': ANY,
|
||||||
'close_rate': 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(
|
freqtrade.execute_trade_exit(
|
||||||
trade=trade, limit=(ticker_usdt_sell_up if is_short else ticker_usdt_sell_down)()['bid'],
|
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
|
assert rpc_mock.call_count == 2
|
||||||
last_msg = rpc_mock.call_args_list[-1][0][0]
|
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,
|
'profit_ratio': -0.0945681 if is_short else -1.247e-05,
|
||||||
'stake_currency': 'USDT',
|
'stake_currency': 'USDT',
|
||||||
'fiat_currency': 'USD',
|
'fiat_currency': 'USD',
|
||||||
'exit_reason': SellType.STOP_LOSS.value,
|
'exit_reason': ExitType.STOP_LOSS.value,
|
||||||
'open_date': ANY,
|
'open_date': ANY,
|
||||||
'close_date': ANY,
|
'close_date': ANY,
|
||||||
'close_rate': ANY,
|
'close_rate': ANY,
|
||||||
@ -3003,7 +3003,7 @@ def test_execute_trade_exit_custom_exit_price(
|
|||||||
freqtrade.execute_trade_exit(
|
freqtrade.execute_trade_exit(
|
||||||
trade=trade,
|
trade=trade,
|
||||||
limit=ticker_usdt_sell_up()['ask' if is_short else 'bid'],
|
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
|
# 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,
|
'profit_ratio': profit_ratio,
|
||||||
'stake_currency': 'USDT',
|
'stake_currency': 'USDT',
|
||||||
'fiat_currency': 'USD',
|
'fiat_currency': 'USD',
|
||||||
'exit_reason': SellType.SELL_SIGNAL.value,
|
'exit_reason': ExitType.SELL_SIGNAL.value,
|
||||||
'open_date': ANY,
|
'open_date': ANY,
|
||||||
'close_date': ANY,
|
'close_date': ANY,
|
||||||
'close_rate': 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
|
trade.stop_loss = 2.0 * 1.01 if is_short else 2.0 * 0.99
|
||||||
freqtrade.execute_trade_exit(
|
freqtrade.execute_trade_exit(
|
||||||
trade=trade, limit=(ticker_usdt_sell_up if is_short else ticker_usdt_sell_down())['bid'],
|
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
|
assert rpc_mock.call_count == 2
|
||||||
last_msg = rpc_mock.call_args_list[-1][0][0]
|
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,
|
'profit_ratio': -0.00501253 if is_short else -0.01493766,
|
||||||
'stake_currency': 'USDT',
|
'stake_currency': 'USDT',
|
||||||
'fiat_currency': 'USD',
|
'fiat_currency': 'USD',
|
||||||
'exit_reason': SellType.STOP_LOSS.value,
|
'exit_reason': ExitType.STOP_LOSS.value,
|
||||||
'open_date': ANY,
|
'open_date': ANY,
|
||||||
'close_date': ANY,
|
'close_date': ANY,
|
||||||
'close_rate': ANY,
|
'close_rate': ANY,
|
||||||
@ -3134,7 +3134,7 @@ def test_execute_trade_exit_sloe_cancel_exception(
|
|||||||
trade.stoploss_order_id = "abcd"
|
trade.stoploss_order_id = "abcd"
|
||||||
|
|
||||||
freqtrade.execute_trade_exit(trade=trade, limit=1234,
|
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 create_order_mock.call_count == 2
|
||||||
assert log_has('Could not cancel stoploss order abcd', caplog)
|
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(
|
freqtrade.execute_trade_exit(
|
||||||
trade=trade,
|
trade=trade,
|
||||||
limit=ticker_usdt_sell_up()['ask' if is_short else 'bid'],
|
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()
|
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)
|
freqtrade.exit_positions(trades)
|
||||||
assert trade.stoploss_order_id is None
|
assert trade.stoploss_order_id is None
|
||||||
assert trade.is_open is False
|
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_count == 3
|
||||||
assert rpc_mock.call_args_list[0][0][0]['type'] == RPCMessageType.BUY
|
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
|
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(
|
freqtrade.execute_trade_exit(
|
||||||
trade=trade,
|
trade=trade,
|
||||||
limit=ticker_usdt_sell_up()['ask' if is_short else 'bid'],
|
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
|
assert not trade.is_open
|
||||||
@ -3355,7 +3355,7 @@ def test_execute_trade_exit_market_order(
|
|||||||
'profit_ratio': profit_ratio,
|
'profit_ratio': profit_ratio,
|
||||||
'stake_currency': 'USDT',
|
'stake_currency': 'USDT',
|
||||||
'fiat_currency': 'USD',
|
'fiat_currency': 'USD',
|
||||||
'exit_reason': SellType.ROI.value,
|
'exit_reason': ExitType.ROI.value,
|
||||||
'open_date': ANY,
|
'open_date': ANY,
|
||||||
'close_date': ANY,
|
'close_date': ANY,
|
||||||
'close_rate': 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
|
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(
|
assert not freqtrade.execute_trade_exit(
|
||||||
trade=trade,
|
trade=trade,
|
||||||
limit=ticker_usdt_sell_up()['ask' if is_short else 'bid'],
|
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', [
|
@pytest.mark.parametrize('profit_only,bid,ask,handle_first,handle_second,sell_type,is_short', [
|
||||||
# Enable profit
|
# Enable profit
|
||||||
(True, 2.18, 2.2, False, True, SellType.SELL_SIGNAL.value, False),
|
(True, 2.18, 2.2, False, True, ExitType.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, True),
|
||||||
# # Disable profit
|
# # Disable profit
|
||||||
(False, 3.19, 3.2, True, False, SellType.SELL_SIGNAL.value, False),
|
(False, 3.19, 3.2, True, False, ExitType.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, True),
|
||||||
# # Enable loss
|
# # 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, 0.21, 0.22, False, False, None, False),
|
||||||
(True, 2.41, 2.42, False, False, None, True),
|
(True, 2.41, 2.42, False, False, None, True),
|
||||||
# Disable loss
|
# Disable loss
|
||||||
(False, 0.10, 0.22, True, False, SellType.SELL_SIGNAL.value, False),
|
(False, 0.10, 0.22, True, False, ExitType.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, True),
|
||||||
])
|
])
|
||||||
def test_sell_profit_only(
|
def test_sell_profit_only(
|
||||||
default_conf_usdt, limit_order, limit_order_open, is_short,
|
default_conf_usdt, limit_order, limit_order_open, is_short,
|
||||||
@ -3441,11 +3441,11 @@ def test_sell_profit_only(
|
|||||||
})
|
})
|
||||||
freqtrade = FreqtradeBot(default_conf_usdt)
|
freqtrade = FreqtradeBot(default_conf_usdt)
|
||||||
patch_get_signal(freqtrade, enter_short=is_short, enter_long=not is_short)
|
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)
|
freqtrade.strategy.min_roi_reached = MagicMock(return_value=False)
|
||||||
else:
|
else:
|
||||||
freqtrade.strategy.stop_loss_reached = MagicMock(return_value=SellCheckTuple(
|
freqtrade.strategy.stop_loss_reached = MagicMock(return_value=SellCheckTuple(
|
||||||
sell_type=SellType.NONE))
|
sell_type=ExitType.NONE))
|
||||||
freqtrade.enter_positions()
|
freqtrade.enter_positions()
|
||||||
|
|
||||||
trade = Trade.query.first()
|
trade = Trade.query.first()
|
||||||
@ -3561,7 +3561,7 @@ def test_locked_pairs(default_conf_usdt, ticker_usdt, fee,
|
|||||||
freqtrade.execute_trade_exit(
|
freqtrade.execute_trade_exit(
|
||||||
trade=trade,
|
trade=trade,
|
||||||
limit=ticker_usdt_sell_down()['ask' if is_short else 'bid'],
|
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'])
|
trade.close(ticker_usdt_sell_down()['bid'])
|
||||||
assert freqtrade.strategy.is_pair_locked(trade.pair)
|
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:
|
else:
|
||||||
patch_get_signal(freqtrade, enter_long=False, exit_long=False)
|
patch_get_signal(freqtrade, enter_long=False, exit_long=False)
|
||||||
assert freqtrade.handle_trade(trade) is True
|
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", [
|
@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"stoploss is {(2.0 * val1 * stop_multi):6f}, "
|
||||||
f"initial stoploss was at {(2.0 * stop_multi):6f}, trade opened at 2.000000",
|
f"initial stoploss was at {(2.0 * stop_multi):6f}, trade opened at 2.000000",
|
||||||
caplog)
|
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', [
|
@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"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",
|
f"trade opened at {2.2 if is_short else 2.0}00000",
|
||||||
caplog)
|
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])
|
@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
|
# Test if buy-signal is absent
|
||||||
patch_get_signal(freqtrade)
|
patch_get_signal(freqtrade)
|
||||||
assert freqtrade.handle_trade(trade) is True
|
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,
|
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,
|
trade=trade,
|
||||||
# The values of the next 2 params are irrelevant for this test
|
# The values of the next 2 params are irrelevant for this test
|
||||||
limit=ticker_usdt_sell_up()['bid'],
|
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(
|
assert trade.funding_fees == pytest.approx(sum(
|
||||||
trade.amount *
|
trade.amount *
|
||||||
|
@ -2,7 +2,7 @@ from unittest.mock import MagicMock
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from freqtrade.enums import SellType
|
from freqtrade.enums import ExitType
|
||||||
from freqtrade.persistence import Trade
|
from freqtrade.persistence import Trade
|
||||||
from freqtrade.rpc.rpc import RPC
|
from freqtrade.rpc.rpc import RPC
|
||||||
from freqtrade.strategy.interface import SellCheckTuple
|
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])
|
side_effect=[stoploss_order_closed, stoploss_order_open, stoploss_order_open])
|
||||||
# Sell 3rd trade (not called for the first trade)
|
# Sell 3rd trade (not called for the first trade)
|
||||||
should_sell_mock = MagicMock(side_effect=[
|
should_sell_mock = MagicMock(side_effect=[
|
||||||
SellCheckTuple(sell_type=SellType.NONE),
|
SellCheckTuple(sell_type=ExitType.NONE),
|
||||||
SellCheckTuple(sell_type=SellType.SELL_SIGNAL)]
|
SellCheckTuple(sell_type=ExitType.SELL_SIGNAL)]
|
||||||
)
|
)
|
||||||
cancel_order_mock = MagicMock()
|
cancel_order_mock = MagicMock()
|
||||||
mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss)
|
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
|
assert wallets_mock.call_count == 4
|
||||||
|
|
||||||
trade = trades[0]
|
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
|
assert not trade.is_open
|
||||||
|
|
||||||
trade = trades[1]
|
trade = trades[1]
|
||||||
@ -119,7 +119,7 @@ def test_may_execute_exit_stoploss_on_exchange_multi(default_conf, ticker, fee,
|
|||||||
assert trade.is_open
|
assert trade.is_open
|
||||||
|
|
||||||
trade = trades[2]
|
trade = trades[2]
|
||||||
assert trade.exit_reason == SellType.SELL_SIGNAL.value
|
assert trade.exit_reason == ExitType.SELL_SIGNAL.value
|
||||||
assert not trade.is_open
|
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(),
|
_notify_exit=MagicMock(),
|
||||||
)
|
)
|
||||||
should_sell_mock = MagicMock(side_effect=[
|
should_sell_mock = MagicMock(side_effect=[
|
||||||
SellCheckTuple(sell_type=SellType.NONE),
|
SellCheckTuple(sell_type=ExitType.NONE),
|
||||||
SellCheckTuple(sell_type=SellType.SELL_SIGNAL),
|
SellCheckTuple(sell_type=ExitType.SELL_SIGNAL),
|
||||||
SellCheckTuple(sell_type=SellType.NONE),
|
SellCheckTuple(sell_type=ExitType.NONE),
|
||||||
SellCheckTuple(sell_type=SellType.NONE),
|
SellCheckTuple(sell_type=ExitType.NONE),
|
||||||
SellCheckTuple(sell_type=SellType.NONE)]
|
SellCheckTuple(sell_type=ExitType.NONE)]
|
||||||
)
|
)
|
||||||
mocker.patch("freqtrade.strategy.interface.IStrategy.should_exit", should_sell_mock)
|
mocker.patch("freqtrade.strategy.interface.IStrategy.should_exit", should_sell_mock)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user