DISCLAIMER
The codes in this post is just for educational purpose, and not to be used on live trading
Let’s say you want to exit a trade when the rsi enter overbought area, because you aren’t sure that the price will keep going up, then you can use custom_exit to do it. First, you need to calculate rsi in populate_indicators
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['ema_9'] = ta.EMA(dataframe, 9)
dataframe['ema_20'] = ta.EMA(dataframe, 20)
dataframe['rsi'] = ta.RSI(dataframe, 14)
return dataframe
Then you need to write custom_exit lines. For this example, we tell the bot to exit on overbought rsi only when the profit above or equal 0. But similar to tsl example, since we want to make the code backtest-able, we tied the profit to last candle’s close.
def custom_exit(self, pair: str, trade: Trade, current_time: datetime, current_rate: float, current_profit: float, **kwargs) -> Optional[Union[str, bool]]:
if ((current_time - timedelta(minutes=15)) >= trade.open_date_utc):
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
current_candle = dataframe.iloc[-1].squeeze()
current_profit = trade.calc_profit_ratio(current_candle['close'])
if (current_profit >= 0):
if (current_candle['rsi'] >= 70):
return "rsi_overbought"
The full code will look like below. Don’t forget to copy the import lines, since there are new imports.
from freqtrade.strategy import IStrategy
from pandas import DataFrame
import freqtrade.vendor.qtpylib.indicators as qtpylib
import talib.abstract as ta
from freqtrade.persistence import Trade
from datetime import datetime, timedelta
from typing import Optional, Union
class strat_template (IStrategy):
def version(self) -> str:
return "template-v1"
INTERFACE_VERSION = 3
minimal_roi = {
"0": 0.05
}
stoploss = -0.05
timeframe = '15m'
process_only_new_candles = True
startup_candle_count = 999
use_custom_stoploss = True
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, current_rate: float, current_profit: float, **kwargs) -> float:
sl_new = 1
if (current_time - timedelta(minutes=15) >= trade.open_date_utc):
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
current_candle = dataframe.iloc[-1].squeeze()
current_profit = trade.calc_profit_ratio(current_candle['close'])
if (current_profit >= 0.03):
sl_new = 0.01
return sl_new
def custom_exit(self, pair: str, trade: Trade, current_time: datetime, current_rate: float, current_profit: float, **kwargs) -> Optional[Union[str, bool]]:
if ((current_time - timedelta(minutes=15)) >= trade.open_date_utc):
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
current_candle = dataframe.iloc[-1].squeeze()
current_profit = trade.calc_profit_ratio(current_candle['close'])
if (current_profit >= 0):
if (current_candle['rsi'] >= 70):
return "rsi_overbought"
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['ema_9'] = ta.EMA(dataframe, 9)
dataframe['ema_20'] = ta.EMA(dataframe, 20)
dataframe['rsi'] = ta.RSI(dataframe, 14)
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
qtpylib.crossed_above(dataframe['ema_9'], dataframe['ema_20'])
&
(dataframe['volume'] > 0)
, ['enter_long', 'enter_tag']
] = (1, 'golden cross')
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
qtpylib.crossed_below(dataframe['ema_9'], dataframe['ema_20'])
&
(dataframe['volume'] > 0)
, ['exit_long', 'exit_tag']
] = (1, 'death cross')
return dataframe
[…] Previous – Create moving average cross strategy Next – Custom exit […]
[…] Previous – Custom exit Next […]
[…] Custom exit […]