降低入场门槛,抬高出场门槛

This commit is contained in:
zhangkun9038@dingtalk.com 2026-01-31 18:25:34 +08:00
parent f4bfa42e70
commit b9d8ee0ebb

View File

@ -697,45 +697,74 @@ class FreqaiPrimer(IStrategy):
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# 出场信号基于趋势和量价关系
# 条件1: 价格突破布林带上轨(使用可优化的偏差参数)
breakout_condition = dataframe['close'] >= dataframe['bb_upper_1h'] * self.exit_bb_upper_deviation.value
# 出场信号基于趋势和量价关系 - 收紧条件减少过早出场 ⭐优化
# 条件2: 成交量显著放大(使用可优化的成交量乘数
volume_spike = dataframe['volume'] > dataframe['volume_ma'] * self.exit_volume_multiplier.value
# 条件1: 价格显著突破布林带上轨(收紧:需要更明显的突破)
breakout_condition = dataframe['close'] >= dataframe['bb_upper_1h'] * 1.02 # 收紧需要超出BB上轨2%
# 条件3: MACD 下降趋势
macd_downward = dataframe['macd_1h'] < dataframe['macd_signal_1h']
# 条件2: 成交量剧烈放大(收紧:需要更大的放量)
volume_spike = dataframe['volume'] > dataframe['volume_ma'] * 2.5 # 收紧1.5倍 → 2.5倍
# 条件4: RSI 进入超买区域(使用可优化的超买阈值)
rsi_overbought = dataframe['rsi_1h'] > self.rsi_overbought.value
# 条件3: MACD 明确下降(收紧:需要更强的下跌确认)
macd_downward = (
(dataframe['macd_1h'] < dataframe['macd_signal_1h']) & # MACD < 信号线
(dataframe['macd_hist_1h'] < 0) & # 新增:柱状图必须为负
(dataframe['macd_hist_1h'] < dataframe['macd_hist_1h'].shift(1)) # 且递减
)
# ========== KDJ 出场辅助判断 ==========
# 3m KDJ 高位死叉K > 80 且 K 下穿 D部分止盈信号
# 条件4: RSI 极度超买(收紧:提高阈值)
rsi_overbought = dataframe['rsi_1h'] > 75 # 收紧70 → 75
# ========== KDJ 出场辅助判断(收紧条件)==========
# 3m KDJ 极度高位死叉K > 85 且 K 下穿 D收紧提高阈值
kdj_3m_exit = False
if 'kdj_k_3m' in dataframe.columns and 'kdj_d_3m' in dataframe.columns:
kdj_3m_death_cross = (dataframe['kdj_k_3m'] > 80) & (dataframe['kdj_k_3m'] < dataframe['kdj_d_3m']) & (dataframe['kdj_k_3m'].shift(1) >= dataframe['kdj_d_3m'].shift(1))
kdj_3m_death_cross = (
(dataframe['kdj_k_3m'] > 85) & # 收紧80 → 85更极端的高位
(dataframe['kdj_k_3m'] < dataframe['kdj_d_3m']) &
(dataframe['kdj_k_3m'].shift(1) >= dataframe['kdj_d_3m'].shift(1))
)
kdj_3m_exit = kdj_3m_death_cross
# ========== SAR 出场辅助判断(趋势反转)==========
# ========== SAR 出场辅助判断(保持不变)==========
# SAR 反转是强信号,保持原逻辑
sar_exit = False
if 'sar_3m' in dataframe.columns:
# SAR 反转:价格跌破 SAR 止损位(从上方穿到下方)
# SAR 反转:价格跌破 SAR 止损位
sar_reversal = (dataframe['close'] < dataframe['sar_3m']) & (dataframe['close'].shift(1) >= dataframe['sar_3m'].shift(1))
sar_exit = sar_reversal
# ========== Ichimoku 出场辅助判断云突破、TK死叉==========
# ========== Ichimoku 出场辅助判断(仅保留云突破)==========
# 收紧只用云突破不用TK死叉TK死叉太敏感
ichimoku_exit = False
if 'ichimoku_price_vs_cloud_3m' in dataframe.columns and 'ichimoku_tk_cross_3m' in dataframe.columns:
# 条件1价格跌破云从云上跌到云下或云中
price_below_cloud = (dataframe['ichimoku_price_vs_cloud_3m'] <= 0) & (dataframe['ichimoku_price_vs_cloud_3m'].shift(1) == 1)
# 条件jTK死叉转换线下穿基准线
tk_death_cross = (dataframe['ichimoku_tk_cross_3m'] == -1) & (dataframe['ichimoku_tk_cross_3m'].shift(1) == 1)
# 任一条件满足即触发
ichimoku_exit = price_below_cloud | tk_death_cross
if 'ichimoku_price_vs_cloud_3m' in dataframe.columns:
# 条件1价格跌破云从云上跌到云下
price_below_cloud = (
(dataframe['ichimoku_price_vs_cloud_3m'] == -1) & # 当前在云下
(dataframe['ichimoku_price_vs_cloud_3m'].shift(1) == 1) # 前一根在云上
)
ichimoku_exit = price_below_cloud
# 合并所有条件SAR、Ichimoku 作为可选信号,不强制)
final_condition = breakout_condition | volume_spike | macd_downward | rsi_overbought | kdj_3m_exit | sar_exit | ichimoku_exit
# ========== 合并出场条件(收紧逻辑:需要多重确认)⭐优化 ==========
# 原逻辑:任一条件满足就出场(太敏感)
# 新逻辑:需要满足以下任一组合
# 组合1强制出场信号单一强信号即可
strong_exit = sar_exit | ichimoku_exit # SAR反转或跌破云
# 组合2多重技术指标确认需要至少2个条件
tech_indicators = [
breakout_condition, # 突破BB上轨
volume_spike, # 放量
macd_downward, # MACD下降
rsi_overbought, # RSI超买
kdj_3m_exit # KDJ死叉
]
tech_count = sum([cond.astype(int) for cond in tech_indicators])
multi_tech_exit = tech_count >= 2 # 需要至少2个技术指标同时触发
# 最终出场条件:强制信号 或 多重技术确认
final_condition = strong_exit | multi_tech_exit
# 设置出场信号
dataframe.loc[final_condition, 'exit_long'] = 1
@ -873,41 +902,42 @@ class FreqaiPrimer(IStrategy):
# === 底部识别5种方法===
# 方法1传统双底识别插针型
# 方法1传统双底识别插针型- 放宽阈值
recent_low_20 = dataframe['low'].rolling(window=20, min_periods=1).min()
recent_high_20 = dataframe['high'].rolling(window=20, min_periods=1).max()
price_vs_recent_low = (dataframe['close'] - recent_low_20) / recent_low_20
price_vs_recent_high = (recent_high_20 - dataframe['close']) / recent_high_20
near_low_traditional = price_vs_recent_low <= 0.03 # 距离低点 ≤ 3%
near_low_traditional = price_vs_recent_low <= 0.05 # 放宽3% → 5%(增加入场机会)
away_from_high_traditional = price_vs_recent_high >= 0.02 # 距离高点 ≥ 2%
# 方法2动量衰减识别缓慢下跌底部
# 方法2动量衰减识别缓慢下跌底部- 放宽条件
price_change_5 = dataframe['close'].pct_change(5)
price_change_10 = dataframe['close'].pct_change(10)
momentum_slowing_down = (
(price_change_5 < 0) & # 仍在下跌
(price_change_5 > price_change_10 / 2) & # 但跌幅变小
(price_change_10 < -0.02) # 且之前有明显下跌
(price_change_10 < -0.015) # 放宽:-2% → -1.5%(更早识别)
)
# 方法3RSI超卖识别
# 方法3RSI超卖识别 - 放宽阈值
rsi_oversold = pd.Series(False, index=dataframe.index)
if 'rsi_1h' in dataframe.columns:
rsi_oversold = dataframe['rsi_1h'] < 35
rsi_oversold = dataframe['rsi_1h'] < 40 # 放宽:35 → 40更早识别超卖
# 方法4布林带下轨突破识别
# 方法4布林带下轨突破识别 - 放宽范围
bb_oversold = pd.Series(False, index=dataframe.index)
if 'bb_lower_1h' in dataframe.columns:
bb_lower = dataframe['bb_lower_1h']
bb_oversold = (dataframe['close'] <= bb_lower * 1.02) & (dataframe['close'] >= bb_lower * 0.98)
# 放宽±2% → ±5%(覆盖更多底部区域)
bb_oversold = (dataframe['close'] <= bb_lower * 1.05) & (dataframe['close'] >= bb_lower * 0.95)
# 方法5成交量萎缩识别抛压减弱
# 方法5成交量萎缩识别抛压减弱- 放宽条件
volume_ma_20 = dataframe['volume'].rolling(window=20, min_periods=1).mean()
volume_shrinking = (
(dataframe['volume'] < volume_ma_20 * 0.7) &
(dataframe['volume'] < volume_ma_20 * 0.8) & # 放宽70% → 80%(更早识别)
(price_change_5 < 0)
)
@ -949,20 +979,26 @@ class FreqaiPrimer(IStrategy):
(dataframe['macd_hist_3m'].shift(1) <= 0) # 前一根为负或零
)
# === 方法73m StochRSI 超卖识别比RSI更敏感⭐新增 ===
# === 方法73m StochRSI 超卖识别比RSI更敏感⭐新增 - 放宽阈值 ===
stochrsi_oversold_3m = pd.Series(False, index=dataframe.index)
if 'stochrsi_k_3m' in dataframe.columns:
stochrsi_oversold_3m = dataframe['stochrsi_k_3m'] < 20 # 深度超卖
stochrsi_oversold_3m = dataframe['stochrsi_k_3m'] < 30 # 放宽20 → 30更早识别
# === 底部组合(允许入场)===
# === 底部组合(允许入场)- 增加灵活组合 ===
bottom_combo1 = near_low_traditional & away_from_high_traditional # 传统双底
bottom_combo2 = momentum_slowing_down & rsi_oversold # 缓慢下跌见底
bottom_combo3 = bb_oversold & volume_shrinking # 深度回调见底
bottom_combo4 = rsi_oversold & away_from_high_traditional # 超卖回调
bottom_combo5 = momentum_slowing_down & macd_turning_3m # 动量衰减+MACD反转 ⭐新增
bottom_combo6 = stochrsi_oversold_3m & near_low_traditional # StochRSI超卖+接近低点 ⭐新增
bottom_combo5 = momentum_slowing_down & macd_turning_3m # 动量衰减+MACD反转
bottom_combo6 = stochrsi_oversold_3m & near_low_traditional # StochRSI超卖+接近低点
is_bottom = bottom_combo1 | bottom_combo2 | bottom_combo3 | bottom_combo4 | bottom_combo5 | bottom_combo6
# === 新增:单一强信号也允许入场(提高入场频率)⭐ ===
bottom_combo7 = near_low_traditional & rsi_oversold # 接近低点+RSI超卖放宽组合
bottom_combo8 = bb_oversold & rsi_oversold # 布林带超卖+RSI超卖双重确认
bottom_combo9 = stochrsi_oversold_3m & momentum_slowing_down # StochRSI+动量衰减
is_bottom = (bottom_combo1 | bottom_combo2 | bottom_combo3 | bottom_combo4 |
bottom_combo5 | bottom_combo6 | bottom_combo7 | bottom_combo8 | bottom_combo9)
# === 顶部组合(禁止入场)⭐新增 ===
top_combo1 = near_high_traditional # 接近历史高点(追高危险)
@ -1199,7 +1235,7 @@ class FreqaiPrimer(IStrategy):
self.strategy_log(f"[{pair}] 🚫 拉升后不稳固区域,取消入场")
allow_trade = False
# 检查3防止追高 - 简单规则3m EMA20 之上拒绝入场
# 检查3防止追高 - 放宽规则:价格显著高于 EMA20 才拒绝(放宽条件)
if allow_trade:
try:
df, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
@ -1210,12 +1246,12 @@ class FreqaiPrimer(IStrategy):
# 检查 3m EMA20
ema20_3m = float(last_row.get('ema_20_3m', current_close))
# 价格在 EMA20 之上 → 拒绝入场(追高
if current_close > ema20_3m:
price_vs_ema20 = (current_close - ema20_3m) / ema20_3m
# 放宽:价格高于 EMA20 超过 2% 才拒绝(之前是只要高于就拒绝
price_vs_ema20 = (current_close - ema20_3m) / ema20_3m
if price_vs_ema20 > 0.02: # 新增超过2%才算追高
self.strategy_log(
f"[{pair}] 🚫 追高过滤: 价格 {current_close:.6f} 高于3m EMA20 {ema20_3m:.6f} "
f"({price_vs_ema20:+.2%}),取消入场"
f"[{pair}] 🚫 追高过滤: 价格 {current_close:.6f} 显著高于3m EMA20 {ema20_3m:.6f} "
f"({price_vs_ema20:+.2%} > +2%),取消入场"
)
allow_trade = False