SellType -> ExitType
This commit is contained in:
@@ -13,7 +13,7 @@ from pandas import DataFrame
|
||||
from freqtrade.configuration import TimeRange
|
||||
from freqtrade.constants import DATETIME_PRINT_FORMAT, UNLIMITED_STAKE_AMOUNT
|
||||
from freqtrade.data.history import get_timerange, load_data, refresh_data
|
||||
from freqtrade.enums import RunMode, SellType
|
||||
from freqtrade.enums import RunMode, ExitType
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.exchange.exchange import timeframe_to_seconds
|
||||
from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist
|
||||
@@ -454,7 +454,7 @@ class Edge:
|
||||
|
||||
if stop_index <= sell_index:
|
||||
exit_index = open_trade_index + stop_index
|
||||
exit_type = SellType.STOP_LOSS
|
||||
exit_type = ExitType.STOP_LOSS
|
||||
exit_price = stop_price
|
||||
elif stop_index > sell_index:
|
||||
# If exit is SELL then we exit at the next candle
|
||||
@@ -464,7 +464,7 @@ class Edge:
|
||||
if len(ohlc_columns) - 1 < exit_index:
|
||||
break
|
||||
|
||||
exit_type = SellType.SELL_SIGNAL
|
||||
exit_type = ExitType.SELL_SIGNAL
|
||||
exit_price = ohlc_columns[exit_index, 0]
|
||||
|
||||
trade = {'pair': pair,
|
||||
|
||||
@@ -5,7 +5,7 @@ from freqtrade.enums.collateral import Collateral
|
||||
from freqtrade.enums.ordertypevalue import OrderTypeValues
|
||||
from freqtrade.enums.rpcmessagetype import RPCMessageType
|
||||
from freqtrade.enums.runmode import NON_UTIL_MODES, OPTIMIZE_MODES, TRADING_MODES, RunMode
|
||||
from freqtrade.enums.selltype import SellType
|
||||
from freqtrade.enums.exittype import ExitType
|
||||
from freqtrade.enums.signaltype import SignalDirection, SignalTagType, SignalType
|
||||
from freqtrade.enums.state import State
|
||||
from freqtrade.enums.tradingmode import TradingMode
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class SellType(Enum):
|
||||
class ExitType(Enum):
|
||||
"""
|
||||
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.dataprovider import DataProvider
|
||||
from freqtrade.edge import Edge
|
||||
from freqtrade.enums import (Collateral, RPCMessageType, SellType, SignalDirection, State,
|
||||
from freqtrade.enums import (Collateral, RPCMessageType, ExitType, SignalDirection, State,
|
||||
TradingMode)
|
||||
from freqtrade.exceptions import (DependencyException, ExchangeError, InsufficientFundsError,
|
||||
InvalidOrderException, PricingError)
|
||||
@@ -915,7 +915,7 @@ class FreqtradeBot(LoggingMixin):
|
||||
logger.error(f'Unable to place a stoploss order on exchange. {e}')
|
||||
logger.warning('Exiting the trade forcefully')
|
||||
self.execute_trade_exit(trade, trade.stop_loss, exit_reason=SellCheckTuple(
|
||||
sell_type=SellType.EMERGENCY_SELL))
|
||||
sell_type=ExitType.EMERGENCY_SELL))
|
||||
|
||||
except ExchangeError:
|
||||
trade.stoploss_order_id = None
|
||||
@@ -947,7 +947,7 @@ class FreqtradeBot(LoggingMixin):
|
||||
# We check if stoploss order is fulfilled
|
||||
if stoploss_order and stoploss_order['status'] in ('closed', 'triggered'):
|
||||
# TODO-lev: Update to exit reason
|
||||
trade.exit_reason = SellType.STOPLOSS_ON_EXCHANGE.value
|
||||
trade.exit_reason = ExitType.STOPLOSS_ON_EXCHANGE.value
|
||||
self.update_trade_state(trade, trade.stoploss_order_id, stoploss_order,
|
||||
stoploss_order=True)
|
||||
# Lock pair for one candle to prevent immediate rebuys
|
||||
@@ -1102,7 +1102,7 @@ class FreqtradeBot(LoggingMixin):
|
||||
try:
|
||||
self.execute_trade_exit(
|
||||
trade, order.get('price'),
|
||||
exit_reason=SellCheckTuple(sell_type=SellType.EMERGENCY_SELL))
|
||||
exit_reason=SellCheckTuple(sell_type=ExitType.EMERGENCY_SELL))
|
||||
except DependencyException as exception:
|
||||
logger.warning(
|
||||
f'Unable to emergency sell trade {trade.pair}: {exception}')
|
||||
@@ -1284,7 +1284,7 @@ class FreqtradeBot(LoggingMixin):
|
||||
trade.open_date
|
||||
)
|
||||
exit_type = 'sell' # TODO-lev: Update to exit
|
||||
if exit_reason.sell_type in (SellType.STOP_LOSS, SellType.TRAILING_STOP_LOSS):
|
||||
if exit_reason.sell_type in (ExitType.STOP_LOSS, ExitType.TRAILING_STOP_LOSS):
|
||||
exit_type = 'stoploss'
|
||||
|
||||
# if stoploss is on exchange and we are on dry_run mode,
|
||||
@@ -1314,7 +1314,7 @@ class FreqtradeBot(LoggingMixin):
|
||||
logger.exception(f"Could not cancel stoploss order {trade.stoploss_order_id}")
|
||||
|
||||
order_type = ordertype or self.strategy.order_types[exit_type]
|
||||
if exit_reason.sell_type == SellType.EMERGENCY_SELL:
|
||||
if exit_reason.sell_type == ExitType.EMERGENCY_SELL:
|
||||
# Emergency sells (default to market!)
|
||||
order_type = self.strategy.order_types.get("emergencysell", "market")
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ from freqtrade.data import history
|
||||
from freqtrade.data.btanalysis import trade_list_to_dataframe
|
||||
from freqtrade.data.converter import trim_dataframe, trim_dataframes
|
||||
from freqtrade.data.dataprovider import DataProvider
|
||||
from freqtrade.enums import BacktestState, CandleType, SellType, TradingMode
|
||||
from freqtrade.enums import BacktestState, CandleType, ExitType, TradingMode
|
||||
from freqtrade.exceptions import DependencyException, OperationalException
|
||||
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds
|
||||
from freqtrade.mixins import LoggingMixin
|
||||
@@ -314,7 +314,7 @@ class Backtesting:
|
||||
Get close rate for backtesting result
|
||||
"""
|
||||
# Special handling if high or low hit STOP_LOSS or ROI
|
||||
if sell.sell_type in (SellType.STOP_LOSS, SellType.TRAILING_STOP_LOSS):
|
||||
if sell.sell_type in (ExitType.STOP_LOSS, ExitType.TRAILING_STOP_LOSS):
|
||||
if trade.stop_loss > sell_row[HIGH_IDX]:
|
||||
# our stoploss was already higher than candle high,
|
||||
# possibly due to a cancelled trade exit.
|
||||
@@ -324,7 +324,7 @@ class Backtesting:
|
||||
# Special case: trailing triggers within same candle as trade opened. Assume most
|
||||
# pessimistic price movement, which is moving just enough to arm stoploss and
|
||||
# immediately going down to stop price.
|
||||
if sell.sell_type == SellType.TRAILING_STOP_LOSS and trade_dur == 0:
|
||||
if sell.sell_type == ExitType.TRAILING_STOP_LOSS and trade_dur == 0:
|
||||
if (
|
||||
not self.strategy.use_custom_stoploss and self.strategy.trailing_stop
|
||||
and self.strategy.trailing_only_offset_is_reached
|
||||
@@ -345,7 +345,7 @@ class Backtesting:
|
||||
|
||||
# Set close_rate to stoploss
|
||||
return trade.stop_loss
|
||||
elif sell.sell_type == (SellType.ROI):
|
||||
elif sell.sell_type == (ExitType.ROI):
|
||||
roi_entry, roi = self.strategy.min_roi_reached_entry(trade_dur)
|
||||
if roi is not None and roi_entry is not None:
|
||||
if roi == -1 and roi_entry % self.timeframe_min == 0:
|
||||
@@ -395,7 +395,7 @@ class Backtesting:
|
||||
closerate = self._get_close_rate(sell_row, trade, sell, trade_dur)
|
||||
# call the custom exit price,with default value as previous closerate
|
||||
current_profit = trade.calc_profit_ratio(closerate)
|
||||
if sell.sell_type in (SellType.SELL_SIGNAL, SellType.CUSTOM_SELL):
|
||||
if sell.sell_type in (ExitType.SELL_SIGNAL, ExitType.CUSTOM_SELL):
|
||||
# Custom exit pricing only for sell-signals
|
||||
closerate = strategy_safe_wrapper(self.strategy.custom_exit_price,
|
||||
default_retval=closerate)(
|
||||
@@ -542,7 +542,7 @@ class Backtesting:
|
||||
sell_row = data[pair][-1]
|
||||
|
||||
trade.close_date = sell_row[DATE_IDX].to_pydatetime()
|
||||
trade.exit_reason = SellType.FORCE_SELL.value
|
||||
trade.exit_reason = ExitType.FORCE_SELL.value
|
||||
trade.close(sell_row[OPEN_IDX], show_msg=False)
|
||||
LocalTrade.close_bt_trade(trade)
|
||||
# Deepcopy object to have wallets update correctly
|
||||
|
||||
@@ -14,7 +14,7 @@ from sqlalchemy.pool import StaticPool
|
||||
from sqlalchemy.sql.schema import UniqueConstraint
|
||||
|
||||
from freqtrade.constants import DATETIME_PRINT_FORMAT, NON_OPEN_EXCHANGE_STATES
|
||||
from freqtrade.enums import SellType, TradingMode
|
||||
from freqtrade.enums import ExitType, TradingMode
|
||||
from freqtrade.exceptions import DependencyException, OperationalException
|
||||
from freqtrade.leverage import interest
|
||||
from freqtrade.misc import safe_value_fallback
|
||||
@@ -575,7 +575,7 @@ class LocalTrade():
|
||||
elif order_type in ('stop_loss_limit', 'stop-loss', 'stop-loss-limit', 'stop'):
|
||||
self.stoploss_order_id = None
|
||||
self.close_rate_requested = self.stop_loss
|
||||
self.exit_reason = SellType.STOPLOSS_ON_EXCHANGE.value
|
||||
self.exit_reason = ExitType.STOPLOSS_ON_EXCHANGE.value
|
||||
if self.is_open:
|
||||
logger.info(f'{order_type.upper()} is hit for {self}.')
|
||||
self.close(safe_value_fallback(order, 'average', 'price'))
|
||||
|
||||
@@ -3,7 +3,7 @@ import logging
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Any, Dict
|
||||
|
||||
from freqtrade.enums import SellType
|
||||
from freqtrade.enums import ExitType
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.plugins.protections import IProtection, ProtectionReturn
|
||||
|
||||
@@ -44,8 +44,8 @@ class StoplossGuard(IProtection):
|
||||
# filters = [
|
||||
# Trade.is_open.is_(False),
|
||||
# Trade.close_date > look_back_until,
|
||||
# or_(Trade.exit_reason == SellType.STOP_LOSS.value,
|
||||
# and_(Trade.exit_reason == SellType.TRAILING_STOP_LOSS.value,
|
||||
# or_(Trade.exit_reason == ExitType.STOP_LOSS.value,
|
||||
# and_(Trade.exit_reason == ExitType.TRAILING_STOP_LOSS.value,
|
||||
# Trade.close_profit < 0))
|
||||
# ]
|
||||
# if pair:
|
||||
@@ -55,8 +55,8 @@ class StoplossGuard(IProtection):
|
||||
|
||||
trades1 = Trade.get_trades_proxy(pair=pair, is_open=False, close_date=look_back_until)
|
||||
trades = [trade for trade in trades1 if (str(trade.exit_reason) in (
|
||||
SellType.TRAILING_STOP_LOSS.value, SellType.STOP_LOSS.value,
|
||||
SellType.STOPLOSS_ON_EXCHANGE.value)
|
||||
ExitType.TRAILING_STOP_LOSS.value, ExitType.STOP_LOSS.value,
|
||||
ExitType.STOPLOSS_ON_EXCHANGE.value)
|
||||
and trade.close_profit and trade.close_profit < 0)]
|
||||
|
||||
if len(trades) < self._trade_limit:
|
||||
|
||||
@@ -17,7 +17,7 @@ from freqtrade import __version__
|
||||
from freqtrade.configuration.timerange import TimeRange
|
||||
from freqtrade.constants import CANCEL_REASON, DATETIME_PRINT_FORMAT
|
||||
from freqtrade.data.history import load_data
|
||||
from freqtrade.enums import SellType, State
|
||||
from freqtrade.enums import ExitType, State
|
||||
from freqtrade.exceptions import ExchangeError, PricingError
|
||||
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_msecs
|
||||
from freqtrade.loggers import bufferHandler
|
||||
@@ -672,7 +672,7 @@ class RPC:
|
||||
closing_side = "buy" if trade.is_short else "sell"
|
||||
current_rate = self._freqtrade.exchange.get_rate(
|
||||
trade.pair, refresh=False, side=closing_side)
|
||||
exit_reason = SellCheckTuple(sell_type=SellType.FORCE_SELL)
|
||||
exit_reason = SellCheckTuple(sell_type=ExitType.FORCE_SELL)
|
||||
order_type = ordertype or self._freqtrade.strategy.order_types.get(
|
||||
"forcesell", self._freqtrade.strategy.order_types["sell"])
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ from pandas import DataFrame
|
||||
|
||||
from freqtrade.constants import ListPairsWithTimeframes
|
||||
from freqtrade.data.dataprovider import DataProvider
|
||||
from freqtrade.enums import CandleType, SellType, SignalDirection, SignalTagType, SignalType
|
||||
from freqtrade.enums import CandleType, ExitType, SignalDirection, SignalTagType, SignalType
|
||||
from freqtrade.exceptions import OperationalException, StrategyError
|
||||
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds
|
||||
from freqtrade.exchange.exchange import timeframe_to_next_date
|
||||
@@ -34,16 +34,16 @@ class SellCheckTuple:
|
||||
"""
|
||||
NamedTuple for Sell type + reason
|
||||
"""
|
||||
sell_type: SellType
|
||||
sell_type: ExitType
|
||||
exit_reason: str = ''
|
||||
|
||||
def __init__(self, sell_type: SellType, exit_reason: str = ''):
|
||||
def __init__(self, sell_type: ExitType, exit_reason: str = ''):
|
||||
self.sell_type = sell_type
|
||||
self.exit_reason = exit_reason or sell_type.value
|
||||
|
||||
@property
|
||||
def sell_flag(self):
|
||||
return self.sell_type != SellType.NONE
|
||||
return self.sell_type != ExitType.NONE
|
||||
|
||||
|
||||
class IStrategy(ABC, HyperStrategyMixin):
|
||||
@@ -784,7 +784,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
and self.min_roi_reached(trade=trade, current_profit=current_profit,
|
||||
current_time=date))
|
||||
|
||||
sell_signal = SellType.NONE
|
||||
sell_signal = ExitType.NONE
|
||||
custom_reason = ''
|
||||
# use provided rate in backtesting, not high/low.
|
||||
current_rate = rate
|
||||
@@ -795,14 +795,14 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
pass
|
||||
elif self.use_exit_signal and not enter:
|
||||
if exit_:
|
||||
sell_signal = SellType.SELL_SIGNAL
|
||||
sell_signal = ExitType.SELL_SIGNAL
|
||||
else:
|
||||
trade_type = "exit_short" if trade.is_short else "sell"
|
||||
custom_reason = strategy_safe_wrapper(self.custom_sell, default_retval=False)(
|
||||
pair=trade.pair, trade=trade, current_time=date, current_rate=current_rate,
|
||||
current_profit=current_profit)
|
||||
if custom_reason:
|
||||
sell_signal = SellType.CUSTOM_SELL
|
||||
sell_signal = ExitType.CUSTOM_SELL
|
||||
if isinstance(custom_reason, str):
|
||||
if len(custom_reason) > CUSTOM_SELL_MAX_LENGTH:
|
||||
logger.warning(f'Custom {trade_type} reason returned from '
|
||||
@@ -811,9 +811,9 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
custom_reason = custom_reason[:CUSTOM_SELL_MAX_LENGTH]
|
||||
else:
|
||||
custom_reason = None
|
||||
if sell_signal in (SellType.CUSTOM_SELL, SellType.SELL_SIGNAL):
|
||||
if sell_signal in (ExitType.CUSTOM_SELL, ExitType.SELL_SIGNAL):
|
||||
logger.debug(f"{trade.pair} - Sell signal received. "
|
||||
f"sell_type=SellType.{sell_signal.name}" +
|
||||
f"sell_type=ExitType.{sell_signal.name}" +
|
||||
(f", custom_reason={custom_reason}" if custom_reason else ""))
|
||||
return SellCheckTuple(sell_type=sell_signal, exit_reason=custom_reason)
|
||||
|
||||
@@ -821,9 +821,9 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
# Exit-signal
|
||||
# ROI (if not stoploss)
|
||||
# Stoploss
|
||||
if roi_reached and stoplossflag.sell_type != SellType.STOP_LOSS:
|
||||
logger.debug(f"{trade.pair} - Required profit reached. sell_type=SellType.ROI")
|
||||
return SellCheckTuple(sell_type=SellType.ROI)
|
||||
if roi_reached and stoplossflag.sell_type != ExitType.STOP_LOSS:
|
||||
logger.debug(f"{trade.pair} - Required profit reached. sell_type=ExitType.ROI")
|
||||
return SellCheckTuple(sell_type=ExitType.ROI)
|
||||
|
||||
if stoplossflag.sell_flag:
|
||||
|
||||
@@ -832,7 +832,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
|
||||
# This one is noisy, commented out...
|
||||
# logger.debug(f"{trade.pair} - No exit signal.")
|
||||
return SellCheckTuple(sell_type=SellType.NONE)
|
||||
return SellCheckTuple(sell_type=ExitType.NONE)
|
||||
|
||||
def stop_loss_reached(self, current_rate: float, trade: Trade,
|
||||
current_time: datetime, current_profit: float,
|
||||
@@ -896,11 +896,11 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
if ((sl_higher_short or sl_lower_long) and
|
||||
(not self.order_types.get('stoploss_on_exchange') or self.config['dry_run'])):
|
||||
|
||||
sell_type = SellType.STOP_LOSS
|
||||
sell_type = ExitType.STOP_LOSS
|
||||
|
||||
# If initial stoploss is not the same as current one then it is trailing.
|
||||
if trade.initial_stop_loss != trade.stop_loss:
|
||||
sell_type = SellType.TRAILING_STOP_LOSS
|
||||
sell_type = ExitType.TRAILING_STOP_LOSS
|
||||
logger.debug(
|
||||
f"{trade.pair} - HIT STOP: current price at "
|
||||
f"{((high if trade.is_short else low) or current_rate):.6f}, "
|
||||
@@ -917,7 +917,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
|
||||
return SellCheckTuple(sell_type=sell_type)
|
||||
|
||||
return SellCheckTuple(sell_type=SellType.NONE)
|
||||
return SellCheckTuple(sell_type=ExitType.NONE)
|
||||
|
||||
def min_roi_reached_entry(self, trade_dur: int) -> Tuple[Optional[int], Optional[float]]:
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user