sell_signal -> exit_signal
This commit is contained in:
parent
93e332e506
commit
19692ff4e8
@ -275,7 +275,7 @@ A backtesting result will look like that:
|
||||
|:-------------------|--------:|------:|-------:|--------:|
|
||||
| trailing_stop_loss | 205 | 150 | 0 | 55 |
|
||||
| stop_loss | 166 | 0 | 0 | 166 |
|
||||
| sell_signal | 56 | 36 | 0 | 20 |
|
||||
| exit_signal | 56 | 36 | 0 | 20 |
|
||||
| force_sell | 2 | 0 | 0 | 2 |
|
||||
====================================================== LEFT OPEN TRADES REPORT ======================================================
|
||||
| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit BTC | Tot Profit % | Avg Duration | Win Draw Loss Win% |
|
||||
@ -357,7 +357,7 @@ Hence, keep in mind that your performance is an integral mix of all different el
|
||||
### Sell reasons table
|
||||
|
||||
The 2nd table contains a recap of sell reasons.
|
||||
This table can tell you which area needs some additional work (e.g. all or many of the `sell_signal` trades are losses, so you should work on improving the sell signal, or consider disabling it).
|
||||
This table can tell you which area needs some additional work (e.g. all or many of the `exit_signal` trades are losses, so you should work on improving the sell signal, or consider disabling it).
|
||||
|
||||
### Left open trades table
|
||||
|
||||
|
@ -98,7 +98,7 @@ def custom_sell(self, pair: str, trade: Trade, current_time: datetime, current_r
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||
last_candle = dataframe.iloc[-1].squeeze()
|
||||
if trade.enter_tag == 'buy_signal_rsi' and last_candle['rsi'] > 80:
|
||||
return 'sell_signal_rsi'
|
||||
return 'exit_signal_rsi'
|
||||
return None
|
||||
|
||||
```
|
||||
|
@ -557,7 +557,7 @@ class AwesomeStrategy(IStrategy):
|
||||
:param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled).
|
||||
:param exit_reason: Sell reason.
|
||||
Can be any of ['roi', 'stop_loss', 'stoploss_on_exchange', 'trailing_stop_loss',
|
||||
'sell_signal', 'force_sell', 'emergency_sell']
|
||||
'exit_signal', 'force_sell', 'emergency_sell']
|
||||
:param current_time: datetime object, containing the current datetime
|
||||
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
|
||||
:return bool: When True is returned, then the sell-order is placed on the exchange.
|
||||
|
@ -86,7 +86,7 @@ Example configuration showing the different settings:
|
||||
"roi": "silent",
|
||||
"emergency_sell": "on",
|
||||
"force_sell": "on",
|
||||
"sell_signal": "silent",
|
||||
"exit_signal": "silent",
|
||||
"trailing_stop_loss": "on",
|
||||
"stop_loss": "on",
|
||||
"stoploss_on_exchange": "on",
|
||||
|
@ -9,7 +9,7 @@ class ExitType(Enum):
|
||||
STOP_LOSS = "stop_loss"
|
||||
STOPLOSS_ON_EXCHANGE = "stoploss_on_exchange"
|
||||
TRAILING_STOP_LOSS = "trailing_stop_loss"
|
||||
EXIT_SIGNAL = "sell_signal"
|
||||
EXIT_SIGNAL = "exit_signal"
|
||||
FORCE_SELL = "force_sell"
|
||||
EMERGENCY_SELL = "emergency_sell"
|
||||
CUSTOM_SELL = "custom_sell"
|
||||
|
@ -346,7 +346,7 @@ class PairHistory(BaseModel):
|
||||
data: List[Any]
|
||||
length: int
|
||||
buy_signals: int
|
||||
sell_signals: int
|
||||
exit_signals: int
|
||||
enter_long_signals: int
|
||||
exit_long_signals: int
|
||||
enter_short_signals: int
|
||||
|
@ -958,7 +958,7 @@ class RPC:
|
||||
'data': dataframe.values.tolist(),
|
||||
'length': len(dataframe),
|
||||
'buy_signals': signals['enter_long'], # Deprecated
|
||||
'sell_signals': signals['exit_long'], # Deprecated
|
||||
'exit_signals': signals['exit_long'], # Deprecated
|
||||
'enter_long_signals': signals['enter_long'],
|
||||
'exit_long_signals': signals['exit_long'],
|
||||
'enter_short_signals': signals['enter_short'],
|
||||
|
@ -693,7 +693,7 @@ class Telegram(RPCHandler):
|
||||
'stop_loss': 'Stoploss',
|
||||
'trailing_stop_loss': 'Trail. Stop',
|
||||
'stoploss_on_exchange': 'Stoploss',
|
||||
'sell_signal': 'Sell Signal',
|
||||
'exit_signal': 'Sell Signal',
|
||||
'force_sell': 'Forcesell',
|
||||
'emergency_sell': 'Emergency Sell',
|
||||
}
|
||||
|
@ -275,7 +275,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
:param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled).
|
||||
:param exit_reason: Exit reason.
|
||||
Can be any of ['roi', 'stop_loss', 'stoploss_on_exchange', 'trailing_stop_loss',
|
||||
'sell_signal', 'force_sell', 'emergency_sell']
|
||||
'exit_signal', 'force_sell', 'emergency_sell']
|
||||
:param current_time: datetime object, containing the current datetime
|
||||
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
|
||||
:return bool: When True, then the sell-order/exit_short-order is placed on the exchange.
|
||||
@ -784,7 +784,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
and self.min_roi_reached(trade=trade, current_profit=current_profit,
|
||||
current_time=date))
|
||||
|
||||
sell_signal = ExitType.NONE
|
||||
exit_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 = ExitType.EXIT_SIGNAL
|
||||
exit_signal = ExitType.EXIT_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 = ExitType.CUSTOM_SELL
|
||||
exit_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,11 +811,11 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
custom_reason = custom_reason[:CUSTOM_SELL_MAX_LENGTH]
|
||||
else:
|
||||
custom_reason = None
|
||||
if sell_signal in (ExitType.CUSTOM_SELL, ExitType.EXIT_SIGNAL):
|
||||
if exit_signal in (ExitType.CUSTOM_SELL, ExitType.EXIT_SIGNAL):
|
||||
logger.debug(f"{trade.pair} - Sell signal received. "
|
||||
f"exit_type=ExitType.{sell_signal.name}" +
|
||||
f"exit_type=ExitType.{exit_signal.name}" +
|
||||
(f", custom_reason={custom_reason}" if custom_reason else ""))
|
||||
return SellCheckTuple(exit_type=sell_signal, exit_reason=custom_reason)
|
||||
return SellCheckTuple(exit_type=exit_signal, exit_reason=custom_reason)
|
||||
|
||||
# Sequence:
|
||||
# Exit-signal
|
||||
|
@ -122,7 +122,7 @@ def confirm_trade_exit(self, pair: str, trade: 'Trade', order_type: str, amount:
|
||||
:param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled).
|
||||
:param exit_reason: Sell reason.
|
||||
Can be any of ['roi', 'stop_loss', 'stoploss_on_exchange', 'trailing_stop_loss',
|
||||
'sell_signal', 'force_sell', 'emergency_sell']
|
||||
'exit_signal', 'force_sell', 'emergency_sell']
|
||||
:param current_time: datetime object, containing the current datetime
|
||||
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
|
||||
:return bool: When True is returned, then the sell-order is placed on the exchange.
|
||||
|
@ -103,7 +103,7 @@ def mock_trade_2(fee, is_short: bool):
|
||||
strategy='StrategyTestV3',
|
||||
timeframe=5,
|
||||
enter_tag='TEST1',
|
||||
exit_reason='sell_signal',
|
||||
exit_reason='exit_signal',
|
||||
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20),
|
||||
close_date=datetime.now(tz=timezone.utc) - timedelta(minutes=2),
|
||||
is_short=is_short
|
||||
@ -400,7 +400,7 @@ def short_trade(fee):
|
||||
open_order_id='dry_run_exit_short_12345',
|
||||
strategy='DefaultStrategy',
|
||||
timeframe=5,
|
||||
exit_reason='sell_signal', # TODO-lev: Update to exit/close reason
|
||||
exit_reason='exit_signal', # TODO-lev: Update to exit/close reason
|
||||
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20),
|
||||
# close_date=datetime.now(tz=timezone.utc) - timedelta(minutes=2),
|
||||
is_short=True
|
||||
@ -489,7 +489,7 @@ def leverage_trade(fee):
|
||||
open_order_id='dry_run_leverage_buy_12368',
|
||||
strategy='DefaultStrategy',
|
||||
timeframe=5,
|
||||
exit_reason='sell_signal',
|
||||
exit_reason='exit_signal',
|
||||
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=300),
|
||||
close_date=datetime.now(tz=timezone.utc),
|
||||
interest_rate=0.0005
|
||||
|
@ -89,7 +89,7 @@ def mock_trade_usdt_2(fee):
|
||||
open_order_id='dry_run_sell_12345',
|
||||
strategy='StrategyTestV2',
|
||||
timeframe=5,
|
||||
exit_reason='sell_signal',
|
||||
exit_reason='exit_signal',
|
||||
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20),
|
||||
close_date=datetime.now(tz=timezone.utc) - timedelta(minutes=2),
|
||||
)
|
||||
|
@ -391,7 +391,7 @@ def test_process_expectancy(mocker, edge_conf, fee, risk_reward_ratio, expectanc
|
||||
'trade_duration': '',
|
||||
'open_rate': 17,
|
||||
'close_rate': 17,
|
||||
'exit_type': 'sell_signal'},
|
||||
'exit_type': 'exit_signal'},
|
||||
|
||||
{'pair': 'TEST/BTC',
|
||||
'stoploss': -0.9,
|
||||
@ -402,7 +402,7 @@ def test_process_expectancy(mocker, edge_conf, fee, risk_reward_ratio, expectanc
|
||||
'trade_duration': '',
|
||||
'open_rate': 20,
|
||||
'close_rate': 20,
|
||||
'exit_type': 'sell_signal'},
|
||||
'exit_type': 'exit_signal'},
|
||||
|
||||
{'pair': 'TEST/BTC',
|
||||
'stoploss': -0.9,
|
||||
@ -413,7 +413,7 @@ def test_process_expectancy(mocker, edge_conf, fee, risk_reward_ratio, expectanc
|
||||
'trade_duration': '',
|
||||
'open_rate': 26,
|
||||
'close_rate': 34,
|
||||
'exit_type': 'sell_signal'}
|
||||
'exit_type': 'exit_signal'}
|
||||
]
|
||||
|
||||
trades_df = DataFrame(trades)
|
||||
@ -457,7 +457,7 @@ def test_process_expectancy_remove_pumps(mocker, edge_conf, fee,):
|
||||
'trade_duration': '',
|
||||
'open_rate': 17,
|
||||
'close_rate': 15,
|
||||
'exit_type': 'sell_signal'},
|
||||
'exit_type': 'exit_signal'},
|
||||
|
||||
{'pair': 'TEST/BTC',
|
||||
'stoploss': -0.9,
|
||||
@ -470,7 +470,7 @@ def test_process_expectancy_remove_pumps(mocker, edge_conf, fee,):
|
||||
'trade_duration': '',
|
||||
'open_rate': 20,
|
||||
'close_rate': 10,
|
||||
'exit_type': 'sell_signal'},
|
||||
'exit_type': 'exit_signal'},
|
||||
{'pair': 'TEST/BTC',
|
||||
'stoploss': -0.9,
|
||||
'profit_percent': '',
|
||||
@ -482,7 +482,7 @@ def test_process_expectancy_remove_pumps(mocker, edge_conf, fee,):
|
||||
'trade_duration': '',
|
||||
'open_rate': 20,
|
||||
'close_rate': 10,
|
||||
'exit_type': 'sell_signal'},
|
||||
'exit_type': 'exit_signal'},
|
||||
{'pair': 'TEST/BTC',
|
||||
'stoploss': -0.9,
|
||||
'profit_percent': '',
|
||||
@ -494,7 +494,7 @@ def test_process_expectancy_remove_pumps(mocker, edge_conf, fee,):
|
||||
'trade_duration': '',
|
||||
'open_rate': 20,
|
||||
'close_rate': 10,
|
||||
'exit_type': 'sell_signal'},
|
||||
'exit_type': 'exit_signal'},
|
||||
{'pair': 'TEST/BTC',
|
||||
'stoploss': -0.9,
|
||||
'profit_percent': '',
|
||||
@ -506,7 +506,7 @@ def test_process_expectancy_remove_pumps(mocker, edge_conf, fee,):
|
||||
'trade_duration': '',
|
||||
'open_rate': 20,
|
||||
'close_rate': 10,
|
||||
'exit_type': 'sell_signal'},
|
||||
'exit_type': 'exit_signal'},
|
||||
|
||||
{'pair': 'TEST/BTC',
|
||||
'stoploss': -0.9,
|
||||
@ -519,7 +519,7 @@ def test_process_expectancy_remove_pumps(mocker, edge_conf, fee,):
|
||||
'trade_duration': '',
|
||||
'open_rate': 26,
|
||||
'close_rate': 134,
|
||||
'exit_type': 'sell_signal'}
|
||||
'exit_type': 'exit_signal'}
|
||||
]
|
||||
|
||||
trades_df = DataFrame(trades)
|
||||
@ -551,7 +551,7 @@ def test_process_expectancy_only_wins(mocker, edge_conf, fee,):
|
||||
'trade_duration': '',
|
||||
'open_rate': 15,
|
||||
'close_rate': 17,
|
||||
'exit_type': 'sell_signal'},
|
||||
'exit_type': 'exit_signal'},
|
||||
{'pair': 'TEST/BTC',
|
||||
'stoploss': -0.9,
|
||||
'profit_percent': '',
|
||||
@ -563,7 +563,7 @@ def test_process_expectancy_only_wins(mocker, edge_conf, fee,):
|
||||
'trade_duration': '',
|
||||
'open_rate': 10,
|
||||
'close_rate': 20,
|
||||
'exit_type': 'sell_signal'},
|
||||
'exit_type': 'exit_signal'},
|
||||
{'pair': 'TEST/BTC',
|
||||
'stoploss': -0.9,
|
||||
'profit_percent': '',
|
||||
@ -575,7 +575,7 @@ def test_process_expectancy_only_wins(mocker, edge_conf, fee,):
|
||||
'trade_duration': '',
|
||||
'open_rate': 26,
|
||||
'close_rate': 134,
|
||||
'exit_type': 'sell_signal'}
|
||||
'exit_type': 'exit_signal'}
|
||||
]
|
||||
|
||||
trades_df = DataFrame(trades)
|
||||
|
@ -973,7 +973,7 @@ def test_exit_reason_performance_handle_2(mocker, default_conf, markets, fee):
|
||||
res = rpc._rpc_exit_reason_performance(None)
|
||||
|
||||
assert len(res) == 2
|
||||
assert res[0]['exit_reason'] == 'sell_signal'
|
||||
assert res[0]['exit_reason'] == 'exit_signal'
|
||||
assert res[0]['count'] == 1
|
||||
assert prec_satoshi(res[0]['profit_pct'], 0.5)
|
||||
assert res[1]['exit_reason'] == 'roi'
|
||||
@ -984,7 +984,7 @@ def test_exit_reason_performance_handle_2(mocker, default_conf, markets, fee):
|
||||
res = rpc._rpc_exit_reason_performance('ETC/BTC')
|
||||
assert len(res) == 1
|
||||
assert res[0]['count'] == 1
|
||||
assert res[0]['exit_reason'] == 'sell_signal'
|
||||
assert res[0]['exit_reason'] == 'exit_signal'
|
||||
assert prec_satoshi(res[0]['profit_pct'], 0.5)
|
||||
|
||||
|
||||
@ -1046,7 +1046,7 @@ def test_mix_tag_performance_handle_2(mocker, default_conf, markets, fee):
|
||||
res = rpc._rpc_mix_tag_performance(None)
|
||||
|
||||
assert len(res) == 2
|
||||
assert res[0]['mix_tag'] == 'TEST1 sell_signal'
|
||||
assert res[0]['mix_tag'] == 'TEST1 exit_signal'
|
||||
assert res[0]['count'] == 1
|
||||
assert prec_satoshi(res[0]['profit_pct'], 0.5)
|
||||
assert res[1]['mix_tag'] == 'Other roi'
|
||||
@ -1058,7 +1058,7 @@ def test_mix_tag_performance_handle_2(mocker, default_conf, markets, fee):
|
||||
|
||||
assert len(res) == 1
|
||||
assert res[0]['count'] == 1
|
||||
assert res[0]['mix_tag'] == 'TEST1 sell_signal'
|
||||
assert res[0]['mix_tag'] == 'TEST1 exit_signal'
|
||||
assert prec_satoshi(res[0]['profit_pct'], 0.5)
|
||||
|
||||
|
||||
|
@ -2091,7 +2091,7 @@ def test_send_msg_sell_notification_no_fiat(
|
||||
({'profit_percent': 1.0, 'exit_reason': 'roi'}, "\N{EIGHT SPOKED ASTERISK}"),
|
||||
({'profit_percent': 0.0, 'exit_reason': 'roi'}, "\N{EIGHT SPOKED ASTERISK}"),
|
||||
({'profit_percent': -5.0, 'exit_reason': 'stop_loss'}, "\N{WARNING SIGN}"),
|
||||
({'profit_percent': -2.0, 'exit_reason': 'sell_signal'}, "\N{CROSS MARK}"),
|
||||
({'profit_percent': -2.0, 'exit_reason': 'exit_signal'}, "\N{CROSS MARK}"),
|
||||
])
|
||||
def test__sell_emoji(default_conf, mocker, msg, expected):
|
||||
del default_conf['fiat_display_currency']
|
||||
|
@ -69,22 +69,22 @@ def test_returns_latest_signal(ohlcv_history):
|
||||
mocked_history.loc[1, 'enter_long'] = 0
|
||||
mocked_history.loc[1, 'enter_short'] = 1
|
||||
mocked_history.loc[1, 'exit_short'] = 0
|
||||
mocked_history.loc[1, 'enter_tag'] = 'sell_signal_01'
|
||||
mocked_history.loc[1, 'enter_tag'] = 'exit_signal_01'
|
||||
|
||||
assert _STRATEGY.get_entry_signal(
|
||||
'ETH/BTC', '5m', mocked_history) == (SignalDirection.SHORT, 'sell_signal_01')
|
||||
'ETH/BTC', '5m', mocked_history) == (SignalDirection.SHORT, 'exit_signal_01')
|
||||
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history) == (False, False, None)
|
||||
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history, True) == (True, False, None)
|
||||
|
||||
mocked_history.loc[1, 'enter_short'] = 0
|
||||
mocked_history.loc[1, 'exit_short'] = 1
|
||||
mocked_history.loc[1, 'exit_tag'] = 'sell_signal_02'
|
||||
mocked_history.loc[1, 'exit_tag'] = 'exit_signal_02'
|
||||
assert _STRATEGY.get_entry_signal(
|
||||
'ETH/BTC', '5m', mocked_history) == (None, None)
|
||||
assert _STRATEGY.get_exit_signal(
|
||||
'ETH/BTC', '5m', mocked_history) == (False, False, 'sell_signal_02')
|
||||
'ETH/BTC', '5m', mocked_history) == (False, False, 'exit_signal_02')
|
||||
assert _STRATEGY.get_exit_signal(
|
||||
'ETH/BTC', '5m', mocked_history, True) == (False, True, 'sell_signal_02')
|
||||
'ETH/BTC', '5m', mocked_history, True) == (False, True, 'exit_signal_02')
|
||||
|
||||
|
||||
def test_analyze_pair_empty(default_conf, mocker, caplog, ohlcv_history):
|
||||
|
@ -1966,7 +1966,7 @@ def test_handle_trade(
|
||||
freqtrade.wallets.update()
|
||||
|
||||
patch_get_signal(freqtrade, enter_long=False, exit_short=is_short,
|
||||
exit_long=not is_short, exit_tag='sell_signal1')
|
||||
exit_long=not is_short, exit_tag='exit_signal1')
|
||||
assert freqtrade.handle_trade(trade) is True
|
||||
assert trade.open_order_id == exit_order['id']
|
||||
|
||||
@ -1977,7 +1977,7 @@ def test_handle_trade(
|
||||
assert trade.close_profit == close_profit
|
||||
assert trade.calc_profit() == 5.685
|
||||
assert trade.close_date is not None
|
||||
assert trade.exit_reason == 'sell_signal1'
|
||||
assert trade.exit_reason == 'exit_signal1'
|
||||
|
||||
|
||||
@pytest.mark.parametrize("is_short", [False, True])
|
||||
|
Loading…
Reference in New Issue
Block a user