# Auto-generated by Strategy Lab — Auto-Quant Factory (Momentum / EMA Crossover Edition) # Entry: EMA fast/slow crossover filtered by ATR > rolling median (trending markets only). # Optimise with: freqtrade hyperopt --strategy IntradayMomentum_v1 --spaces buy roi stoploss from freqtrade.strategy import IntParameter, IStrategy from pandas import DataFrame import talib.abstract as ta import freqtrade.vendor.qtpylib.indicators as qtpylib import numpy as np class IntradayMomentum_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 # ── Tunable EMA periods ─────────────────────────────────────────────────── ema_fast = IntParameter(5, 20, default=9, space="buy", optimize=True) ema_slow = IntParameter(15, 50, default=21, space="buy", optimize=True) # ── ATR rolling-median window (volatility gate) ─────────────────────────── atr_window = IntParameter(10, 50, default=14, space="buy", optimize=True) def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # Dynamic EMA pair — recalculated for the current parameter values dataframe["ema_fast"] = ta.EMA(dataframe, timeperiod=self.ema_fast.value) dataframe["ema_slow"] = ta.EMA(dataframe, timeperiod=self.ema_slow.value) # ATR(14) and its rolling median for regime gating dataframe["atr"] = ta.ATR(dataframe, timeperiod=14) dataframe["atr_median"] = ( dataframe["atr"] .rolling(window=self.atr_window.value, min_periods=1) .median() ) return dataframe def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # EMA crossover in a trending (high-ATR) market only dataframe.loc[ ( qtpylib.crossed_above(dataframe["ema_fast"], dataframe["ema_slow"]) & (dataframe["atr"] > dataframe["atr_median"]) & (dataframe["volume"] > 0) ), "enter_long", ] = 1 return dataframe def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: return dataframe