# Auto-generated by Strategy Lab — Auto-Quant Factory (Adaptive Regime Edition) # Regime is detected from ATR vs its rolling median (high ATR → trending). # Hyperopt should use: freqtrade hyperopt --strategy IntradayAdaptive_v1 --spaces buy roi stoploss from freqtrade.strategy import IntParameter, DecimalParameter, IStrategy from pandas import DataFrame import talib.abstract as ta import freqtrade.vendor.qtpylib.indicators as qtpylib import numpy as np class IntradayAdaptive_v1(IStrategy): INTERFACE_VERSION: int = 3 minimal_roi = { "0": 0.08, "30": 0.04, "60": 0.02, "120": 0, } stoploss = -0.05 timeframe = "5m" trailing_stop = False process_only_new_candles = True # ── Regime-adaptive entry parameters ───────────────────────────────────── # Trending (high ATR) thresholds — more aggressive rsi_entry_trend = IntParameter(20, 40, default=28, space="buy", optimize=True) macd_hist_min_trend = DecimalParameter(0.0, 0.005, default=0.001, space="buy", optimize=True) # Ranging (low ATR) thresholds — more conservative rsi_entry_range = IntParameter(25, 45, default=35, space="buy", optimize=True) bb_entry_pct = DecimalParameter(0.95, 1.0, default=0.98, space="buy", optimize=True) # ATR regime window atr_regime_window = IntParameter(30, 100, default=50, space="buy", optimize=False) def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # ATR + rolling median for regime detection dataframe["atr"] = ta.ATR(dataframe, timeperiod=14) dataframe["atr_median"] = ( dataframe["atr"] .rolling(window=self.atr_regime_window.value, min_periods=1) .median() ) # 1 = trending (ATR above median), 0 = ranging dataframe["regime"] = np.where( dataframe["atr"] > dataframe["atr_median"], 1, 0 ) # MACD macd = ta.MACD(dataframe, fastperiod=12, slowperiod=26, signalperiod=9) dataframe["macd"] = macd["macd"] dataframe["macdsignal"] = macd["macdsignal"] dataframe["macdhist"] = macd["macdhist"] # RSI dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14) # Bollinger Bands bollinger = qtpylib.bollinger_bands( qtpylib.typical_price(dataframe), window=20, stds=2 ) dataframe["bb_lowerband"] = bollinger["lower"] dataframe["bb_upperband"] = bollinger["upper"] return dataframe def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # Trending regime: MACD cross + RSI filter trend_cond = ( (dataframe["regime"] == 1) & (dataframe["macdhist"] > self.macd_hist_min_trend.value) & qtpylib.crossed_above(dataframe["macd"], dataframe["macdsignal"]) & (dataframe["rsi"] < self.rsi_entry_trend.value + 30) & (dataframe["volume"] > 0) ) # Ranging regime: RSI oversold + price near lower BB range_cond = ( (dataframe["regime"] == 0) & (dataframe["rsi"] < self.rsi_entry_range.value) & (dataframe["close"] <= dataframe["bb_lowerband"] * (1 + (1 - self.bb_entry_pct.value))) & (dataframe["volume"] > 0) ) dataframe.loc[trend_cond | range_cond, "enter_long"] = 1 return dataframe def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: return dataframe