From a1a06d055a9f45faa03c7ea0f715e27fe5bceacf Mon Sep 17 00:00:00 2001 From: aszerW Date: Mon, 27 Oct 2025 00:51:34 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- user_data/strategies/trend_strategy.py | 129 ++++++++++++------------- 1 file changed, 64 insertions(+), 65 deletions(-) diff --git a/user_data/strategies/trend_strategy.py b/user_data/strategies/trend_strategy.py index 94bd856..00e2f77 100644 --- a/user_data/strategies/trend_strategy.py +++ b/user_data/strategies/trend_strategy.py @@ -48,49 +48,51 @@ class TrendStrategy(IStrategy): stoploss = -0.05 # 5% 止损 # Trailing stoploss - trailing_stop = False - trailing_stop_positive = None - trailing_stop_positive_offset = 0.0 - trailing_only_offset_is_reached = False + # trailing_stop = False + # trailing_stop_positive = None + # trailing_stop_positive_offset = 0.0 + # trailing_only_offset_is_reached = False # Run "populate_indicators" only for new candle - process_only_new_candles = False + # process_only_new_candles = False # These values can be overridden in the config - use_exit_signal = True - exit_profit_only = False - ignore_roi_if_entry_signal = False + # use_exit_signal = True + # exit_profit_only = False + # ignore_roi_if_entry_signal = False # Number of candles the strategy requires before producing valid signals - startup_candle_count: int = 30 + startup_candle_count: int = 0 # Optional order type mapping - order_types = { - 'entry': 'limit', - 'exit': 'limit', - 'stoploss': 'market', - 'stoploss_on_exchange': False - } + # order_types = { + # 'entry': 'limit', + # 'exit': 'limit', + # 'stoploss': 'market', + # 'stoploss_on_exchange': False + # } # Optional order time in force - order_time_in_force = { - 'entry': 'gtc', - 'exit': 'gtc' - } + # order_time_in_force = { + # 'entry': 'gtc', + # 'exit': 'gtc' + # } # 策略参数 - ema_short_window = IntParameter(8, 15, default=10, space="buy") - ema_long_window = IntParameter(15, 25, default=20, space="buy") - rsi_short_window = IntParameter(4, 8, default=6, space="buy") - rsi_long_window = IntParameter(10, 15, default=12, space="buy") + ema_10_window = IntParameter(8, 15, default=10, space="buy") + ema_20_window = IntParameter(15, 25, default=20, space="buy") + rsi_6_window = IntParameter(4, 8, default=6, space="buy") + rsi_12_window = IntParameter(10, 15, default=12, space="buy") # RSI超卖阈值 - rsi_short_oversold = DecimalParameter(15.0, 25.0, default=21.0, space="buy") - rsi_long_oversold = DecimalParameter(20.0, 30.0, default=26.25, space="buy") + rsi_6_oversold = DecimalParameter(15.0, 30.0, default=21.0, space="buy") + rsi_12_oversold = DecimalParameter(20.0, 35.0, default=26.25, space="buy") - # 趋势检查窗口 - trend_check_window = IntParameter(3, 7, default=3, space="buy") - momentum_check_window = IntParameter(3, 7, default=5, space="sell") + # 趋势检查窗口(用于RSI超卖检查) + rsi_check_window = IntParameter(2, 5, default=3, space="buy") + # EMA下跌动量检查窗口(用于卖出条件) + ema_fall_window = IntParameter(3, 7, default=5, space="sell") + # EMA价差扩大检查窗口(用于卖出条件) diff_check_window = IntParameter(4, 8, default=6, space="sell") def informative_pairs(self): @@ -113,37 +115,21 @@ class TrendStrategy(IStrategy): """ # EMA指标 - dataframe['ema_short'] = ta.EMA(dataframe, timeperiod=self.ema_short_window.value) - dataframe['ema_long'] = ta.EMA(dataframe, timeperiod=self.ema_long_window.value) + dataframe['ema_10'] = ta.EMA(dataframe, timeperiod=self.ema_10_window.value) + dataframe['ema_20'] = ta.EMA(dataframe, timeperiod=self.ema_20_window.value) # RSI指标 - dataframe['rsi_short'] = ta.RSI(dataframe, timeperiod=self.rsi_short_window.value) - dataframe['rsi_long'] = ta.RSI(dataframe, timeperiod=self.rsi_long_window.value) + dataframe['rsi_6'] = ta.RSI(dataframe, timeperiod=self.rsi_6_window.value) + dataframe['rsi_12'] = ta.RSI(dataframe, timeperiod=self.rsi_12_window.value) # 计算EMA价差(用于卖出条件) - dataframe['ema_diff'] = dataframe['ema_long'] - dataframe['ema_short'] - - # 计算EMA短期趋势(用于买入条件) - dataframe['ema_short_rising'] = dataframe['ema_short'] > dataframe['ema_short'].shift(1) - dataframe['ema_short_rising_2'] = dataframe['ema_short'].shift(1) > dataframe['ema_short'].shift(2) - - # 计算RSI超卖条件 - dataframe['rsi_short_oversold'] = ( - dataframe['rsi_short'].shift(1).rolling(window=self.trend_check_window.value).max() < self.rsi_short_oversold.value - ) - dataframe['rsi_long_oversold'] = ( - dataframe['rsi_long'].shift(1).rolling(window=self.trend_check_window.value).max() < self.rsi_long_oversold.value - ) - - # 计算EMA10连续下跌条件(用于卖出) - dataframe['ema_short_falling'] = ( - dataframe['ema_short'] < dataframe['ema_short'].shift(1).rolling(window=self.momentum_check_window.value).min() - ) - - # 计算价差扩大条件(用于卖出) - dataframe['ema_diff_expanding'] = ( - dataframe['ema_diff'] == dataframe['ema_diff'].rolling(window=self.diff_check_window.value).max() - ) + dataframe['diff'] = dataframe['ema_20'] - dataframe['ema_10'] + + macd = ta.MACD(dataframe, fastperiod=12, slowperiod=26, signalperiod=9,) + dataframe["macd"] = macd["macd"] + dataframe["macdsignal"] = macd["macdsignal"] + dataframe["macdhist"] = macd["macdhist"] + dataframe['cci'] = ta.CCI(dataframe, 14) return dataframe @@ -156,20 +142,24 @@ class TrendStrategy(IStrategy): """ # 条件1:EMA多头排列 + 短期趋势加速 + # EMA10 > EMA20:短期趋势强于长期趋势(多头排列) + # EMA10昨日 > 前日:短期均线继续上行,显示动量增强 ema_bullish_cross = ( - (dataframe['ema_short'] > dataframe['ema_long']) & - (dataframe['ema_short_rising'] & dataframe['ema_short_rising_2']) + (dataframe['ema_10'] > dataframe['ema_20']) & + (dataframe['ema_10'].shift(1) > dataframe['ema_10'].shift(2)) ) - # 条件2:双周期RSI深度超卖反弹 + # 条件2:双周期RSI进入深度超卖区 + # 过去3天的6周期RSI最高值 < 21,表示近期极度超卖 + # 过去3天的12周期RSI最高值 < 26.25,确认中周期也处于超卖状态 rsi_oversold_bounce = ( - dataframe['rsi_short_oversold'] & - dataframe['rsi_long_oversold'] + (dataframe['rsi_6'].shift(1).rolling(window=self.rsi_check_window.value).max() < self.rsi_6_oversold.value) & + (dataframe['rsi_12'].shift(1).rolling(window=self.rsi_check_window.value).max() < self.rsi_12_oversold.value) ) # 合并买入条件:任一条件满足即产生买入信号 dataframe.loc[ - ema_bullish_cross | rsi_oversold_bounce, + ema_bullish_cross, 'enter_long' ] = 1 @@ -183,12 +173,21 @@ class TrendStrategy(IStrategy): :return: DataFrame with exit columns populated """ - # 卖出条件:EMA10连续下跌 + 空头趋势加速 - sell_condition = ( - dataframe['ema_short_falling'] & - dataframe['ema_diff_expanding'] + # 条件1:EMA10连续下跌(动量走弱) + # 当前EMA10 < 过去5天(不含今日)的最低EMA10值 + ema10_falling = ( + dataframe['ema_10'] < dataframe['ema_10'].shift(1).rolling(window=self.ema_fall_window.value).min() ) + # 条件2:空头趋势加速(价差达到近期最大) + # 当前diff是过去6天(含今日)中的最大值,表示空头力量最强 + diff_expanding = ( + dataframe['diff'] == dataframe['diff'].rolling(window=self.diff_check_window.value).max() + ) + + # 合并卖出条件:两个条件同时满足才卖出 + sell_condition = ema10_falling & diff_expanding + dataframe.loc[ sell_condition, 'exit_long'