DISCLAIMER
The codes in this post is just for educational purpose, and not to be used on live trading
To have multiple logics is quite easy. You can just do multiple dataframe.loc[]
like this
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ entry_1 , ['enter_long', 'enter_tag'] ] = (1, 'entry_1 ') dataframe.loc[ entry_2 , ['enter_long', 'enter_tag'] ] = (1, 'entry_2 ') dataframe.loc[ entry_3 , ['enter_long', 'enter_tag'] ] = (1, 'entry_3 ') return dataframe def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ exit_1 , ['exit_long', 'exit_tag'] ] = (1, 'exit_1 ') dataframe.loc[ exit_2 , ['exit_long', 'exit_tag'] ] = (1, 'exit_2 ') dataframe.loc[ exit_3 , ['exit_long', 'exit_tag'] ] = (1, 'exit_3 ') return dataframe
The issue with the code above is if multiple logics are triggered, then your enter_tag
and exit_tag
only have the last logic’s tag. For example, let’s say all the entry and exit logics are triggered respectively on enter and exit, then your enter_tag
and exit_tag
will be entry_3
and exit_3
. While this won’t have any effect on current code, if you want to have exit logics that are tied to specific enter_tag (I’ll discuss this next), then you want to have your enter_tag
to be accurate, which means it should be entry_1 entry_2 entry_3
.
To have that accurate enter and exit tag, the code should look like this
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe['enter_tag'] = '' dataframe.loc[ entry_1 | entry_2 | entry_3 , 'enter_long' ] = 1 dataframe.loc[ entry_1 , 'enter_tag' ] += 'entry_1 ' dataframe.loc[ entry_2 , 'enter_tag' ] += 'entry_2 ' dataframe.loc[ entry_3 , 'enter_tag' ] += 'entry_3 ' return dataframe def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe['exit_tag'] = '' dataframe.loc[ exit_1 | exit_2 | exit_3 , 'exit_long' ] = 1 dataframe.loc[ exit_1 , 'exit_tag' ] += 'exit_1 ' dataframe.loc[ exit_2 , 'exit_tag' ] += 'exit_2 ' dataframe.loc[ exit_3 , 'exit_tag' ] += 'exit_3 ' return dataframe
One important thing to note, if possible, don’t use space for your enter and exit tags if you want to use them further. Now let’s try to implement it on our sample strategy. On top of the golden/death cross, let’s add 2 more entry and exit logics, when close below ema_9/20 for entry and when close above ema_9/20 for exit. Our strategy now looks like this
from freqtrade.strategy import IStrategy, informative 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 def EWO(source, sma_length=5, sma2_length=35): sma1 = ta.SMA(source, timeperiod=sma_length) sma2 = ta.SMA(source, timeperiod=sma2_length) smadif = (sma1 - sma2) / source * 100 return smadif 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" @informative('30m') def populate_indicators_inf1(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe['rsi'] = ta.RSI(dataframe['close'], 14) return dataframe @informative('1h') def populate_indicators_inf2(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe['rsi'] = ta.RSI(dataframe['close'], 14) return dataframe def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe['ema_9'] = ta.EMA(dataframe['close'], 9) dataframe['ema_20'] = ta.EMA(dataframe['close'], 20) dataframe['rsi'] = ta.RSI(dataframe['close'], 14) dataframe['ema_9_rsi'] = ta.EMA(dataframe['rsi'], 9) dataframe['ewo'] = EWO(dataframe['close'], 50, 200) return dataframe def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe['enter_tag'] = '' enter_1 = ( qtpylib.crossed_above(dataframe['ema_9'], dataframe['ema_20']) & (dataframe['rsi_30m'] < 50) & (dataframe['rsi_1h'] < 30) & (dataframe['ema_9_rsi'] < 70) & (dataframe['ewo'] > 3) & (dataframe['volume'] > 0) ) enter_2 = ( (dataframe['close'] < dataframe['ema_9']) & (dataframe['volume'] > 0) ) enter_3 = ( (dataframe['close'] < dataframe['ema_20']) & (dataframe['volume'] > 0) ) dataframe.loc[ enter_1 | enter_2 | enter_3 , 'enter_long' ] = 1 dataframe.loc[ enter_1 , 'enter_tag' ] += 'golden_cross ' dataframe.loc[ enter_2 , 'enter_tag' ] += 'close_below_9 ' dataframe.loc[ enter_3 , 'enter_tag' ] += 'close_below_20 ' return dataframe def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe['exit_tag'] = '' exit_1 = ( qtpylib.crossed_below(dataframe['ema_9'], dataframe['ema_20']) & (dataframe['volume'] > 0) ) exit_2 = ( (dataframe['close'] > dataframe['ema_9']) & (dataframe['volume'] > 0) ) exit_3 = ( (dataframe['close'] > dataframe['ema_20']) & (dataframe['volume'] > 0) ) dataframe.loc[ exit_1 | exit_2 | exit_3 , 'exit_long' ] = 1 dataframe.loc[ exit_1 , 'exit_tag' ] += 'death_cross ' dataframe.loc[ exit_2 , 'exit_tag' ] += 'close_above_9 ' dataframe.loc[ exit_3 , 'exit_tag' ] += 'close_above_20 ' return dataframe
[…] Previous – Custom indicators part 1 Next – Multiple entry and exit logics […]
[…] Previous – Multiple entry and exit logics Next […]
[…] Multiple entry and exit logics […]