from functools import reduce from freqtrade.strategy import IStrategy, IntParameter from pandas import DataFrame import talib.abstract as ta class BTC1h(IStrategy): # 1-hour timeframe timeframe = "1h" # Higher timeframe for trend filter informative_timeframe = "4h" # ROI table (0 = latest candle) minimal_roi = { "0": 0.10, "120": 0.05, "360": 0.03, "720": 0, } stoploss = -0.05 trailing_stop = False trailing_stop_positive = 0.01 trailing_stop_positive_offset = 0.03 trailing_only_offset_is_reached = True use_exit_signal = True exit_profit_only = False startup_candle_count = 200 order_types = { "entry": "limit", "exit": "limit", "stoploss": "market", "stoploss_on_exchange": False, } # --- Hyperoptable parameters --- ema_short = IntParameter(20, 50, default=34, space="buy") ema_long = IntParameter(100, 200, default=144, space="buy") rsi_entry = IntParameter(25, 45, default=35, space="buy") rsi_exit = IntParameter(60, 80, default=70, space="sell") def informative_pairs(self): pairs = self.dp.current_whitelist() return [(pair, self.informative_timeframe) for pair in pairs] def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # --- Higher timeframe trend filter --- if self.dp: informative = self.dp.get_pair_dataframe( pair=metadata["pair"], timeframe=self.informative_timeframe ) informative["ema_200"] = ta.EMA(informative, timeperiod=200) informative["htf_bull"] = ( informative["close"] > informative["ema_200"] ).astype(int) # Merge HTF data into 1h dataframe dataframe = dataframe.merge( informative[["date", "htf_bull"]], on="date", how="left" ) dataframe["htf_bull"] = dataframe["htf_bull"].ffill().fillna(0) else: dataframe["htf_bull"] = 1 # --- EMAs --- dataframe["ema_short"] = ta.EMA(dataframe, timeperiod=self.ema_short.value) dataframe["ema_long"] = ta.EMA(dataframe, timeperiod=self.ema_long.value) # --- RSI --- dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14) # --- MACD --- macd = ta.MACD(dataframe) dataframe["macd"] = macd["macd"] dataframe["macd_signal"] = macd["macdsignal"] dataframe["macd_hist"] = macd["macdhist"] # --- Volume --- dataframe["volume_ma"] = ta.SMA(dataframe, timeperiod=20) # --- ATR --- dataframe["atr"] = ta.ATR(dataframe, timeperiod=14) return dataframe def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: conditions = [ # 4h trend is bullish dataframe["htf_bull"] == 1, # Price above long-term EMA dataframe["close"] > dataframe["ema_long"], # Pullback near short-term EMA dataframe["close"] < dataframe["ema_short"] * 1.02, # RSI dip dataframe["rsi"] < self.rsi_entry.value, # MACD turning up dataframe["macd_hist"] > dataframe["macd_hist"].shift(1), # Volume confirmation dataframe["volume"] > dataframe["volume_ma"], ] dataframe.loc[reduce(lambda a, b: a & b, conditions), "enter_long"] = 1 return dataframe def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: conditions = [ # RSI overbought dataframe["rsi"] > self.rsi_exit.value, # MACD bearish cross ( (dataframe["macd"] < dataframe["macd_signal"]) & (dataframe["macd"].shift(1) > dataframe["macd_signal"].shift(1)) ), ] dataframe.loc[reduce(lambda a, b: a | b, conditions), "exit_long"] = 1 return dataframe