💬 Forum

SupertrendFuturesStrategyV8_2

🏆 League #1904 / 1922

jinzheng8115/freqtrade-crypto-system/user_data/strategies/SupertrendFuturesStrategyV8_2.py · first seen 2026-07-16 · repo updated 2026-02-23

Basics mode: futures timeframe: 30m interface version: 3
Settings stoploss: -0.03 has minimal roi trailing startup candle count: 200 hyperopt hyperopt params: 10
Indicators ADX ATR EMA RSI Supertrend talib
Concepts trailing trend_following
15 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 →

Source

Download Raw
  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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
# SupertrendFuturesStrategyV8_2 - 市场环境自适应版
# 基于V8.1,添加牛熊市识别和动态调整

import numpy as np
import pandas as pd
from pandas import DataFrame
from datetime import datetime
from typing import Optional
from functools import reduce
import logging

from freqtrade.strategy import IStrategy, DecimalParameter, IntParameter
import talib.abstract as ta

logger = logging.getLogger(__name__)


class SupertrendFuturesStrategyV8_2(IStrategy):
    """
    V8.2: 市场环境自适应版
    
    新增功能:
    1. 市场环境识别(日线趋势)
       - 牛市:价格 > EMA200,做多优先
       - 熊市:价格 < EMA200,做空优先
       - 震荡:横盘整理,减少交易
    
    2. 动态条件调整
       - 牛市:放宽做多ADX(30),收紧做空ADX(35)
       - 熊市:放宽做空ADX(20),收紧做多ADX(40)
       - 震荡:ADX要求35+
    
    3. 杠杆动态调整
       - 顺势交易:2x杠杆
       - 逆势交易:1x杠杆
    
    基础参数继承V8.1优化结果
    """
    
    INTERFACE_VERSION = 3

    # V8.1 优化参数(从Hyperopt结果)
    atr_period = IntParameter(5, 30, default=21, space="buy")
    atr_multiplier = DecimalParameter(2.0, 5.0, default=4.622, space="buy")
    ema_fast = IntParameter(5, 50, default=21, space="buy")
    ema_slow = IntParameter(20, 200, default=47, space="buy")
    adx_threshold_long = IntParameter(20, 40, default=34, space="buy")
    adx_threshold_short = IntParameter(15, 35, default=23, space="buy")
    alpha_threshold = DecimalParameter(0.02, 0.15, default=0.118, space="buy")
    
    # V8.2 新增参数 - 市场环境
    trend_lookback = IntParameter(50, 200, default=100, space="buy")  # 趋势判断周期
    bear_adx_bonus = IntParameter(5, 15, default=10, space="buy")  # 熊市做空ADX放宽
    bull_adx_penalty = IntParameter(5, 15, default=10, space="buy")  # 牛市做空ADX收紧

    minimal_roi = {"0": 0.06}
    stoploss = -0.03
    timeframe = '30m'
    trailing_stop = True
    trailing_stop_positive = 0.02
    trailing_stop_positive_offset = 0.03
    trailing_only_offset_is_reached = True
    startup_candle_count = 200

    order_types = {
        'entry': 'limit',
        'exit': 'limit',
        'stoploss': 'market',
        'stoploss_on_exchange': False
    }

    can_short: bool = True
    leverage_default = 2

    def supertrend(self, dataframe, period=14, multiplier=3):
        """Supertrend计算"""
        df = dataframe.copy()
        hl2 = (df['high'] + df['low']) / 2
        atr = ta.ATR(df, timeperiod=period)
        upperband = hl2 + (multiplier * atr)
        lowerband = hl2 - (multiplier * atr)
        supertrend = [0] * len(df)
        direction = [1] * len(df)
        for i in range(1, len(df)):
            if df['close'].iloc[i] > upperband.iloc[i-1]:
                direction[i] = 1
            elif df['close'].iloc[i] < lowerband.iloc[i-1]:
                direction[i] = -1
            else:
                direction[i] = direction[i-1]
            supertrend[i] = lowerband.iloc[i] if direction[i] == 1 else upperband.iloc[i]
        return pd.Series(supertrend, index=df.index), pd.Series(direction, index=df.index)

    def detect_market_regime(self, dataframe: DataFrame) -> DataFrame:
        """
        检测市场环境
        返回: 1=牛市, -1=熊市, 0=震荡
        """
        # 使用长期EMA判断趋势
        dataframe['ema_trend'] = ta.EMA(dataframe['close'], timeperiod=self.trend_lookback.value)
        
        # 价格相对位置
        price_position = (dataframe['close'] - dataframe['ema_trend']) / dataframe['ema_trend'] * 100
        
        # 趋势强度(ADX)
        adx = ta.ADX(dataframe, timeperiod=14)
        
        # 市场环境判断 - 放宽条件
        conditions = [
            (price_position > 2) & (adx > 20),   # 牛市:放宽
            (price_position < -2) & (adx > 20),  # 熊市:放宽
        ]
        choices = [1, -1]  # 牛市=1, 熊市=-1
        
        dataframe['market_regime'] = np.select(conditions, choices, default=0)
        
        return dataframe

    def leverage(self, pair, current_time, current_rate, proposed_leverage, max_leverage, entry_tag, side, **kwargs):
        """动态杠杆 - 顺势加仓,逆势减仓"""
        dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
        
        if len(dataframe) < 1:
            return min(self.leverage_default, max_leverage)
        
        last_candle = dataframe.iloc[-1]
        regime = last_candle.get('market_regime', 0)
        
        # 顺势交易:2x杠杆
        # 逆势交易:1x杠杆
        # 震荡市:1.5x杠杆
        if regime == 1 and side == 'long':  # 牛市做多
            leverage = 2.0
        elif regime == -1 and side == 'short':  # 熊市做空
            leverage = 2.0
        elif regime == 1 and side == 'short':  # 牛市做空(逆势)
            leverage = 1.0
        elif regime == -1 and side == 'long':  # 熊市做多(逆势)
            leverage = 1.0
        else:  # 震荡市
            leverage = 1.5
        
        return min(leverage, max_leverage)

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """计算技术指标"""
        
        # === V8.1 核心指标 ===
        dataframe['ema_fast'] = ta.EMA(dataframe, timeperiod=self.ema_fast.value)
        dataframe['ema_slow'] = ta.EMA(dataframe, timeperiod=self.ema_slow.value)
        dataframe['supertrend'], dataframe['st_dir'] = self.supertrend(
            dataframe, period=self.atr_period.value, multiplier=self.atr_multiplier.value
        )
        
        # ADX
        dataframe['adx'] = ta.ADX(dataframe, timeperiod=14)
        dataframe['adx_pos'] = ta.PLUS_DI(dataframe, timeperiod=14)
        dataframe['adx_neg'] = ta.MINUS_DI(dataframe, timeperiod=14)
        
        # RSI
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
        
        # 成交量
        dataframe['volume_ma'] = dataframe['volume'].rolling(window=20).mean()
        
        # Alpha#101 (简化版)
        dataframe['alpha_101'] = (
            (dataframe['close'] - dataframe['close'].shift(5)) / dataframe['close'].shift(5) * 100 -
            (dataframe['volume'] - dataframe['volume'].shift(5)) / dataframe['volume'].shift(5) * 10
        )
        
        # 趋势判断
        dataframe['is_uptrend'] = dataframe['close'] > dataframe['supertrend']
        dataframe['is_downtrend'] = dataframe['close'] < dataframe['supertrend']
        
        # 波动率
        dataframe['volatility_ratio'] = ta.ATR(dataframe, timeperiod=14) / dataframe['close']
        
        # === V8.2 新增:市场环境判断 ===
        dataframe = self.detect_market_regime(dataframe)
        
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """做多 - 根据市场环境调整条件"""
        dataframe.loc[:, 'enter_long'] = 0
        
        # 获取当前市场环境
        regime = dataframe['market_regime'].iloc[-1] if len(dataframe) > 0 else 0
        
        # 根据市场环境调整ADX阈值
        if regime == 1:  # 牛市:放宽做多
            adx_threshold = self.adx_threshold_long.value - 5
        elif regime == -1:  # 熊市:收紧做多
            adx_threshold = self.adx_threshold_long.value + 10
        else:  # 震荡:标准
            adx_threshold = self.adx_threshold_long.value
        
        conditions = [
            # V8.1 核心条件
            dataframe['st_dir'] == 1,
            dataframe['ema_fast'] > dataframe['ema_slow'],
            dataframe['adx'] > adx_threshold,
            dataframe['adx_pos'] > dataframe['adx_neg'],
            dataframe['close'] > dataframe['supertrend'],
            dataframe['is_uptrend'],
            
            # V8.1 多因子
            (dataframe['rsi'] > 35) & (dataframe['rsi'] < 80),
            dataframe['alpha_101'] > self.alpha_threshold.value,
            dataframe['volume'] > dataframe['volume_ma'] * 1.1,
            dataframe['volatility_ratio'] < 0.06,
        ]

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

        return dataframe

    def populate_entry_trend_short(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """做空 - 根据市场环境调整条件"""
        dataframe.loc[:, 'enter_short'] = 0
        
        # 获取当前市场环境
        regime = dataframe['market_regime'].iloc[-1] if len(dataframe) > 0 else 0
        
        # 根据市场环境调整ADX阈值
        if regime == -1:  # 熊市:放宽做空
            adx_threshold = self.adx_threshold_short.value - self.bear_adx_bonus.value
        elif regime == 1:  # 牛市:收紧做空
            adx_threshold = self.adx_threshold_short.value + self.bull_adx_penalty.value
        else:  # 震荡:标准
            adx_threshold = self.adx_threshold_short.value
        
        conditions = [
            # V8.1 核心条件
            dataframe['st_dir'] == -1,
            dataframe['ema_fast'] < dataframe['ema_slow'],
            dataframe['adx'] > adx_threshold,
            dataframe['adx_neg'] > dataframe['adx_pos'],
            dataframe['close'] < dataframe['supertrend'],
            dataframe['is_downtrend'],
            
            # V8.1 多因子
            (dataframe['rsi'] > 20) & (dataframe['rsi'] < 65),
            dataframe['alpha_101'] < -self.alpha_threshold.value,
            dataframe['volume'] > dataframe['volume_ma'] * 1.1,
            dataframe['volatility_ratio'] < 0.06,
        ]

        if conditions:
            dataframe.loc[reduce(lambda x, y: x & y, conditions), 'enter_short'] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """做多平仓"""
        dataframe.loc[:, 'exit_long'] = 0
        conditions = [dataframe['st_dir'] == -1]
        if conditions:
            dataframe.loc[reduce(lambda x, y: x & y, conditions), 'exit_long'] = 1
        return dataframe

    def populate_exit_trend_short(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """做空平仓"""
        dataframe.loc[:, 'exit_short'] = 0
        conditions = [dataframe['st_dir'] == 1]
        if conditions:
            dataframe.loc[reduce(lambda x, y: x & y, conditions), 'exit_short'] = 1
        return dataframe

    def confirm_trade_entry(self, pair: str, order_type: str, amount: float, 
                           rate: float, time_in_force: str, current_time: datetime,
                           entry_tag: Optional[str], side: str, **kwargs) -> bool:
        """入场确认"""
        dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
        
        if len(dataframe) < 1:
            return False
        
        last_candle = dataframe.iloc[-1]
        
        # 避免极端波动
        if last_candle['volatility_ratio'] > 0.08:
            logger.info(f"波动率过高,跳过 {pair}")
            return False
        
        return True