💬 Forum

AutoQuantRobustV3

🏆 League #429 / 1941

4tie/fortiesr/user_data/strategies/AutoQuantRobustV3.py · first seen 2026-07-16 · repo updated 2026-07-09

Basics mode: spot timeframe: 4h interface version: 3
Settings stoploss: -0.15 has minimal roi trailing process only new candles startup candle count: 200 hyperopt hyperopt params: 4
Indicators TEMA talib
Concepts trailing
3 related strategies ( identical code, similar name)

Each tile is a different kind of check — from an instant code lint to full sandboxed backtests and forward tests on recent data. Not sure what a check actually proves? See the FAQ →

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
from freqtrade.strategy import IntParameter, IStrategy
from pandas import DataFrame
import talib.abstract as ta
from functools import reduce


class AutoQuantRobustV3(IStrategy):
    INTERFACE_VERSION: int = 3

    # ROI Table - based on MultiMa success
    minimal_roi = {
        "0": 0.08,
        "240": 0.04,
        "720": 0.02,
        "1440": 0,
    }

    # Stoploss - wider to allow room for volatility
    stoploss = -0.15

    # Timeframe - 4h like MultiMa
    timeframe = "4h"

    # Trailing stop
    trailing_stop = True
    trailing_stop_positive = 0.02
    trailing_stop_positive_offset = 0.04
    trailing_only_offset_is_reached = True

    # Process only new candles
    process_only_new_candles = True
    startup_candle_count = 200

    # ── Tunable Parameters for Optimizer ──
    
    # TEMA parameters
    buy_ma_count = IntParameter(2, 8, default=3, space="buy", optimize=True)
    buy_ma_gap = IntParameter(5, 20, default=10, space="buy", optimize=True)
    
    sell_ma_count = IntParameter(2, 8, default=4, space="sell", optimize=True)
    sell_ma_gap = IntParameter(10, 30, default=20, space="sell", optimize=True)

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # Compute only needed TEMA periods to save memory
        needed_periods = set()
        
        # Buy side periods
        for ma_count in range(self.buy_ma_count.value + 1):
            needed_periods.add(ma_count * self.buy_ma_gap.value)
        
        # Sell side periods
        for ma_count in range(self.sell_ma_count.value + 1):
            needed_periods.add(ma_count * self.sell_ma_gap.value)
        
        # Compute TEMA indicators
        for period in needed_periods:
            if period > 1:
                dataframe[f"tema_{int(period)}"] = ta.TEMA(dataframe, timeperiod=int(period))

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Entry based on TEMA alignment (multiple MAs pointing down)
        """
        conditions = []
        
        for ma_count in range(self.buy_ma_count.value):
            key = ma_count * self.buy_ma_gap.value
            past_key = (ma_count - 1) * self.buy_ma_gap.value
            if past_key > 1:
                tema_current = f"tema_{int(key)}"
                tema_past = f"tema_{int(past_key)}"
                if tema_current in dataframe.columns and tema_past in dataframe.columns:
                    # Price below shorter TEMA, shorter TEMA below longer TEMA
                    conditions.append(
                        (dataframe["close"] < dataframe[tema_current]) &
                        (dataframe[tema_current] < dataframe[tema_past])
                    )

        if conditions:
            dataframe.loc[reduce(lambda x, y: x & y, conditions), "enter_long"] = 1
        
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Exit based on TEMA reversal (shorter TEMA crosses above longer TEMA)
        """
        conditions = []
        
        for ma_count in range(self.sell_ma_count.value):
            key = ma_count * self.sell_ma_gap.value
            past_key = (ma_count - 1) * self.sell_ma_gap.value
            if past_key > 1:
                tema_current = f"tema_{int(key)}"
                tema_past = f"tema_{int(past_key)}"
                if tema_current in dataframe.columns and tema_past in dataframe.columns:
                    # Shorter TEMA crosses above longer TEMA
                    conditions.append(dataframe[tema_current] > dataframe[tema_past])

        if conditions:
            dataframe.loc[reduce(lambda x, y: x | y, conditions), "exit_long"] = 1
        
        return dataframe