diff --git a/freqtrade/templates/freqaiprimer.py b/freqtrade/templates/freqaiprimer.py index 063542e3..0cd0f729 100644 --- a/freqtrade/templates/freqaiprimer.py +++ b/freqtrade/templates/freqaiprimer.py @@ -388,40 +388,40 @@ class FreqaiPrimer(IStrategy): return dataframe def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: - # 入场信号主要依据1小时周期 - # 条件1: 价格接近布林带下轨 - close_to_bb_lower_1h = (dataframe['close'] <= dataframe['bb_lower_1h'] * 1.02) + # 获取当前市场状态 + current_state = dataframe['market_state'].iloc[-1] if 'market_state' in dataframe.columns else 'neutral' - # 条件2: RSI 不高于阈值(更严格) - rsi_condition_1h = dataframe['rsi_1h'] < 40 # 进一步收紧 RSI 阈值 + # 条件1: 价格接近布林带下轨(允许一定偏差) + close_to_bb_lower_1h = (dataframe['close'] <= dataframe['bb_lower_1h'] * 1.03) # 放宽到3%偏差 - # 条件3: StochRSI 处于超卖区域(更严格) - stochrsi_condition_1h = (dataframe['stochrsi_k_1h'] < 20) & (dataframe['stochrsi_d_1h'] < 20) # 进一步收紧 StochRSI 阈值 + # 条件2: RSI 不高于阈值(根据市场状态动态调整) + rsi_threshold = 45 if current_state in ['strong_bull', 'weak_bull'] else 40 + rsi_condition_1h = dataframe['rsi_1h'] < rsi_threshold + + # 条件3: StochRSI 处于超卖区域(根据市场状态动态调整) + stochrsi_threshold = 30 if current_state in ['strong_bull', 'weak_bull'] else 20 + stochrsi_condition_1h = (dataframe['stochrsi_k_1h'] < stochrsi_threshold) & (dataframe['stochrsi_d_1h'] < stochrsi_threshold) # 条件4: MACD 上升趋势 macd_condition_1h = dataframe['macd_1h'] > dataframe['macd_signal_1h'] - # 条件5: 成交量显著放大 + # 条件5: 成交量显著放大(可选条件) volume_spike = dataframe['volume'] > dataframe['volume_ma'] * 1.5 # 条件6: 布林带宽度过滤(避免窄幅震荡) bb_width = (dataframe['bb_upper_1h'] - dataframe['bb_lower_1h']) / dataframe['close'] bb_width_condition = bb_width > 0.02 # 布林带宽度大于2% - # 辅助条件: 3m 和 15m 趋势确认 - trend_confirmation = (dataframe['trend_3m'] == 1) & (dataframe['trend_15m'] == 1) + # 辅助条件: 3m 和 15m 趋势确认(允许部分时间框架不一致) + trend_confirmation = (dataframe['trend_3m'] == 1) | (dataframe['trend_15m'] == 1) - # 增加布林带宽度过滤器,避免窄幅震荡市场 - bb_width_condition = (dataframe['bb_upper_1h'] - dataframe['bb_lower_1h']) / dataframe['close'] > 0.03 # 布林带宽度大于3% - - # 合并所有条件(增加成交量和布林带宽度过滤) + # 合并所有条件(减少强制性条件) final_condition = ( close_to_bb_lower_1h & - rsi_condition_1h & # 严格要求RSI满足条件 - stochrsi_condition_1h & # 严格要求StochRSI满足条件 + rsi_condition_1h & + stochrsi_condition_1h & macd_condition_1h & - volume_spike & # 成交量显著放大 - bb_width_condition & # 布林带宽度过滤 + (volume_spike | bb_width_condition) & # 成交量或布林带宽度满足其一即可 trend_confirmation ) @@ -434,6 +434,7 @@ class FreqaiPrimer(IStrategy): logger.info(f" - RSI 超卖: {rsi_condition_1h.sum()} 次") logger.info(f" - StochRSI 超卖: {stochrsi_condition_1h.sum()} 次") logger.info(f" - MACD 上升趋势: {macd_condition_1h.sum()} 次") + logger.info(f" - 成交量或布林带宽度: {(volume_spike | bb_width_condition).sum()} 次") logger.info(f" - 趋势确认: {trend_confirmation.sum()} 次") logger.info(f" - 最终条件: {final_condition.sum()} 次") @@ -442,84 +443,6 @@ class FreqaiPrimer(IStrategy): logger.info(f"[{metadata['pair']}] 发现入场信号数量: {dataframe['enter_long'].sum()}") return dataframe - # 缓存数据框以便在trailing_stop_positive属性中使用 - self._dataframe_cache = dataframe - - # 基础退出条件 - basic_exit = ( - (dataframe['close'] >= dataframe['bb_upper_3m']) | - (dataframe['rsi_3m'] > self.rsi_overbought) - ) - - # 强劲趋势条件:1h趋势向上 + 熊牛得分>70 - strong_trend = (dataframe['trend_1h_ema'] == 1) & (dataframe['market_score'] > 70) - - # 一般趋势条件:熊牛得分50-70 - normal_trend = (dataframe['market_score'] >= 50) & (dataframe['market_score'] <= 70) - - # 极端强劲趋势条件:熊牛得分>95 - extreme_strong_trend = (dataframe['market_score'] > 95) - - # 获取15m数据进行趋势确认 - df_15m = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe='15m') - - # 确保df_15m中包含rsi_15m列,如果没有则计算 - try: - import pandas_ta as ta - if 'rsi_15m' not in df_15m.columns: - # 使用pandas_ta计算14期RSI - rsi_series = ta.rsi(df_15m['close'], length=14) - df_15m['rsi_15m'] = rsi_series - except Exception as e: - # 如果计算失败,创建一个默认值列 - logger.warning(f"[{metadata['pair']}] 计算15m RSI时出错: {e}") - df_15m['rsi_15m'] = 50 # 设置默认值为中性 - - # 重命名date列并保留必要的列 - df_15m = df_15m[['date', 'rsi_15m']].rename(columns={'date': 'date_15m'}) - - # 合并数据 - merged_data = dataframe.copy() - # 创建合并列 - merged_data['rsi_15m'] = 50 # 设置默认值 - - # 尝试合并数据 - try: - # 使用更简单的方式:直接将df_15m的rsi_15m列映射到dataframe - # 创建一个日期到rsi的映射字典 - date_rsi_map = df_15m.set_index('date_15m')['rsi_15m'].to_dict() - # 使用映射填充rsi_15m列 - merged_data['rsi_15m'] = merged_data['date'].map(date_rsi_map).ffill().bfill() - except Exception as e: - logger.warning(f"[{metadata['pair']}] 合并15m数据时出错: {e}") - - # 趋势反转信号:15m RSI超买 - trend_reversal = merged_data['rsi_15m'] > 75 - - # 动态调整退出条件 - 提高ATR倍数以增加单笔盈利潜力 - # 强劲趋势中:大幅提高ATR倍数到5.5倍,充分利用趋势利润 - # 但在极端强劲趋势(market_score>95)下不给出退出信号 - dataframe.loc[strong_trend & ~extreme_strong_trend & ((dataframe['close'] > dataframe['open'] + dataframe['atr'] * 5.5) | (basic_exit & trend_reversal)), 'exit_long'] = 1 - - # 一般趋势中:提高到4倍ATR退出 - # 但在极端强劲趋势(market_score>95)下不给出退出信号 - dataframe.loc[normal_trend & ~extreme_strong_trend & ((dataframe['close'] > dataframe['open'] + dataframe['atr'] * 4) | basic_exit), 'exit_long'] = 1 - - # 非趋势或弱势:保持2倍ATR退出 - # 但在极端强劲趋势(market_score>95)下不给出退出信号 - - # 记录退出决策日志 - if len(dataframe[dataframe['exit_long'] == 1]) > 0: - last_exit = dataframe[dataframe['exit_long'] == 1].iloc[-1] - current_state = dataframe['market_state'].iloc[-1] - logger.info(f"[{metadata['pair']}] 触发退出信号,市场状态: {current_state}, 价格: {last_exit['close']:.2f}") - - # 记录因极端强劲趋势阻止的退出信号 - extreme_strong_prevented = dataframe[extreme_strong_trend & ((strong_trend & ((dataframe['close'] > dataframe['open'] + dataframe['atr'] * 5.5) | (basic_exit & trend_reversal))) | (normal_trend & ((dataframe['close'] > dataframe['open'] + dataframe['atr'] * 4) | basic_exit)))] - if len(extreme_strong_prevented) > 0: - logger.info(f"[{metadata['pair']}] 由于极端强劲趋势(market_score>95),阻止了 {len(extreme_strong_prevented)} 个潜在的退出信号") - - return dataframe def detect_h1_rapid_rise(self, pair: str, dataframe: DataFrame, metadata: dict) -> tuple[bool, float]: """