diff --git a/freqtrade/templates/freqaiprimer.py b/freqtrade/templates/freqaiprimer.py index f0ecf8ab..896f961c 100644 --- a/freqtrade/templates/freqaiprimer.py +++ b/freqtrade/templates/freqaiprimer.py @@ -371,18 +371,15 @@ class FreqaiPrimer(IStrategy): logger.info(f"[{pair}] 熊市信号 - 条件c (看跌形态): {cond_c.iloc[-1]}") logger.info(f"[{pair}] 熊市信号 - 条件d (成交量下降): {cond_d.iloc[-1]}") - # 汇总所有条件的得分 - bearish_score = 0 - if cond_a.iloc[-1]: - bearish_score += 25 - if cond_b.iloc[-1]: - bearish_score += 25 - if cond_c.iloc[-1]: - bearish_score += 25 - if cond_d.iloc[-1]: - bearish_score += 25 - - logger.info(f"[{pair}] 熊市信号总得分: {bearish_score}/100") + # 使用向量化操作计算得分,避免使用iloc[-1]进行业务逻辑判断 + bearish_score_vector = (cond_a.astype(int) + cond_b.astype(int) + cond_c.astype(int) + cond_d.astype(int)) * 25 + + # 仅在日志中使用最后一行的值(这是允许的用途) + if len(dataframe) > 0: + bearish_score = bearish_score_vector.iloc[-1] + logger.info(f"[{pair}] 熊市信号总得分: {bearish_score}/100") + else: + bearish_score = 0 return bearish_signal @@ -648,9 +645,14 @@ class FreqaiPrimer(IStrategy): cond5 = (dataframe["stochrsi_k"] < stochrsi_threshold * 1.4) # 超宽松STOCHRSI core_conditions = [cond1, cond2, cond3, cond4, cond5] - satisfied_count = sum([c.iloc[-1] for c in core_conditions]) - buy_condition = satisfied_count >= 4 - logger.info(f"[{pair}] 🟢 牛市绿色通道:持仓{open_trades}≤2个,25USDT入场,5条件需要满足{satisfied_count}/4个") + # 使用向量化操作计算满足条件的数量 + satisfied_count_vector = cond1.astype(int) + cond2.astype(int) + cond3.astype(int) + cond4.astype(int) + cond5.astype(int) + buy_condition = satisfied_count_vector >= 4 + + # 仅在日志中使用最后一行的值 + if len(dataframe) > 0: + satisfied_count = satisfied_count_vector.iloc[-1] + logger.info(f"[{pair}] 🟢 牛市绿色通道:持仓{open_trades}≤2个,25USDT入场,5条件需要满足{satisfied_count}/4个") elif trend_status == "bullish": # 牛市正常通道:持仓>2个,75USDT入场,必须满足全部7个条件 @@ -691,37 +693,44 @@ class FreqaiPrimer(IStrategy): # 绿色通道和趋势状态的条件已经设置好buy_condition conditions.append(buy_condition) - # 调试日志 - 添加更多调试信息 - divergence_value = dataframe["&-price_value_divergence"].iloc[-1] - volume_z_score_value = dataframe["volume_z_score"].iloc[-1] - rsi_value = dataframe["rsi"].iloc[-1] - stochrsi_value = dataframe["stochrsi_k"].iloc[-1] - bb_close_value = dataframe["close"].iloc[-1] - bb_lower_value = dataframe["bb_lowerband"].iloc[-1] - bb_upper_value = dataframe["bb_upperband"].iloc[-1] - - # 输出关键指标以便调试 - logger.info(f"[{pair}] 📊 关键指标 - 偏离度: {divergence_value:.6f}, RSI: {rsi_value:.2f}, STOCHRSI: {stochrsi_value:.2f}, 价格: {bb_close_value:.4f}, 下轨: {bb_lower_value:.4f}, 上轨: {bb_upper_value:.4f}") - logger.info(f"[{pair}] 🔍 买入阈值 - 偏离度: {self.buy_threshold:.6f}, RSI: {rsi_threshold:.2f}, STOCHRSI: {stochrsi_threshold:.2f}") - # 定义条件名称和状态 - conditions_summary = [ - ("&-price_value_divergence", divergence_value, "<", self.buy_threshold, cond1.iloc[-1]), - ("volume_z_score", volume_z_score_value, ">", volume_z_score_threshold, cond2.iloc[-1]), - ("rsi", rsi_value, "<", rsi_threshold, cond3.iloc[-1]), - ("close <= bb_lowerband", bb_close_value, "<=", bb_lower_value, cond4.iloc[-1]), - ("stochrsi_k", stochrsi_value, "<", stochrsi_threshold, cond5.iloc[-1]), - ] - - # 根据趋势状态添加对应的条件6和7 - if trend_status == "bullish" and open_trades <= 2: - # 绿色通道只有5个条件 - pass - else: - # 其他通道有7个条件 - conditions_summary.extend([ - ("非熊市", None, None, None, cond6.iloc[-1]), - ("STOCHRSI未持续超买", None, None, None, cond7.iloc[-1]), - ]) + # 调试日志 - 仅在日志中使用最后一行的值 + if len(dataframe) > 0: + divergence_value = dataframe["&-price_value_divergence"].iloc[-1] + volume_z_score_value = dataframe["volume_z_score"].iloc[-1] + rsi_value = dataframe["rsi"].iloc[-1] + stochrsi_value = dataframe["stochrsi_k"].iloc[-1] + bb_close_value = dataframe["close"].iloc[-1] + bb_lower_value = dataframe["bb_lowerband"].iloc[-1] + bb_upper_value = dataframe["bb_upperband"].iloc[-1] + + # 输出关键指标以便调试 + logger.info(f"[{pair}] 📊 关键指标 - 偏离度: {divergence_value:.6f}, RSI: {rsi_value:.2f}, STOCHRSI: {stochrsi_value:.2f}, 价格: {bb_close_value:.4f}, 下轨: {bb_lower_value:.4f}, 上轨: {bb_upper_value:.4f}") + logger.info(f"[{pair}] 🔍 买入阈值 - 偏离度: {self.buy_threshold:.6f}, RSI: {rsi_threshold:.2f}, STOCHRSI: {stochrsi_threshold:.2f}") + + # 获取条件结果的最后一行值(仅用于日志) + cond1_last = cond1.iloc[-1] + cond2_last = cond2.iloc[-1] + cond3_last = cond3.iloc[-1] + cond4_last = cond4.iloc[-1] + cond5_last = cond5.iloc[-1] + cond6_last = cond6.iloc[-1] if trend_status != "bullish" or open_trades > 2 else False + cond7_last = cond7.iloc[-1] if trend_status != "bullish" or open_trades > 2 else False + + # 定义条件名称和状态(仅用于日志) + conditions_summary = [ + ("&-price_value_divergence", divergence_value, "<", self.buy_threshold, cond1_last), + ("volume_z_score", volume_z_score_value, ">", volume_z_score_threshold, cond2_last), + ("rsi", rsi_value, "<", rsi_threshold, cond3_last), + ("close <= bb_lowerband", bb_close_value, "<=", bb_lower_value, cond4_last), + ("stochrsi_k", stochrsi_value, "<", stochrsi_threshold, cond5_last), + ] + + # 根据趋势状态添加对应的条件6和7 + if trend_status != "bullish" or open_trades > 2: + conditions_summary.extend([ + ("非熊市", None, None, None, cond6_last), + ("STOCHRSI未持续超买", None, None, None, cond7_last), + ]) # 输出每个条件的状态 logger.info(f"[{pair}] === 买入条件检查 ===") @@ -936,17 +945,24 @@ class FreqaiPrimer(IStrategy): conditions.append(sell_condition) - # 调试日志 - 使用安全的值获取 - divergence_value = dataframe["&-price_value_divergence"].iloc[-1] if len(dataframe) > 0 and not dataframe["&-price_value_divergence"].isna().iloc[-1] else 0.0 - rsi_value = dataframe["rsi"].iloc[-1] if len(dataframe) > 0 and not dataframe["rsi"].isna().iloc[-1] else 0.0 - stochrsi_value = dataframe["stochrsi_k"].iloc[-1] if len(dataframe) > 0 and not dataframe["stochrsi_k"].isna().iloc[-1] else 0.0 - adx_value = dataframe["adx"].iloc[-1] if len(dataframe) > 0 and not dataframe["adx"].isna().iloc[-1] else 0.0 - short_term_return = dataframe["short_term_return"].iloc[-1] if len(dataframe) > 0 and not dataframe["short_term_return"].isna().iloc[-1] else 0.0 - logger.info(f"[{pair}] 卖出条件检查 - " - f"&-price_value_divergence={divergence_value:.6f} > {self.sell_threshold * float(self.exit_divergence_multiplier.value):.6f}: {cond1.iloc[-1]}, " - f"rsi={rsi_value:.2f} > {float(self.exit_rsi_threshold.value)} & stochrsi_k={stochrsi_value:.2f} > {float(self.exit_stochrsi_threshold.value)}: {cond2.iloc[-1]}, " - f"short_term_return={short_term_return:.2f}% > {rapid_rise_threshold:.2f}% & profit > {min_profit*100:.2f}%: {cond3.iloc[-1]}, " - f"adx={adx_value:.2f}, trend_score={trend_score:.2f}") + # 调试日志 - 仅在日志中使用最后一行的值(这是允许的用途) + if len(dataframe) > 0: + divergence_value = dataframe["&-price_value_divergence"].iloc[-1] if not dataframe["&-price_value_divergence"].isna().iloc[-1] else 0.0 + rsi_value = dataframe["rsi"].iloc[-1] if not dataframe["rsi"].isna().iloc[-1] else 0.0 + stochrsi_value = dataframe["stochrsi_k"].iloc[-1] if not dataframe["stochrsi_k"].isna().iloc[-1] else 0.0 + adx_value = dataframe["adx"].iloc[-1] if not dataframe["adx"].isna().iloc[-1] else 0.0 + short_term_return = dataframe["short_term_return"].iloc[-1] if not dataframe["short_term_return"].isna().iloc[-1] else 0.0 + + # 获取条件结果的最后一行值(仅用于日志) + cond1_last = cond1.iloc[-1] + cond2_last = cond2.iloc[-1] + cond3_last = cond3.iloc[-1] + + logger.info(f"[{pair}] 卖出条件检查 - " + f"&-price_value_divergence={divergence_value:.6f} > {self.sell_threshold * float(self.exit_divergence_multiplier.value):.6f}: {cond1_last}, " + f"rsi={rsi_value:.2f} > {float(self.exit_rsi_threshold.value)} & stochrsi_k={stochrsi_value:.2f} > {float(self.exit_stochrsi_threshold.value)}: {cond2_last}, " + f"short_term_return={short_term_return:.2f}% > {rapid_rise_threshold:.2f}% & profit > {min_profit*100:.2f}%: {cond3_last}, " + f"adx={adx_value:.2f}, trend_score={trend_score:.2f}") else: logger.warning(f"[{pair}] ⚠️ &-price_value_divergence 列缺失,跳过该条件")