From 1d4f85b1027f7591b9db0b0584cfae2e6bee5dc0 Mon Sep 17 00:00:00 2001 From: "zhangkun9038@dingtalk.com" Date: Fri, 22 Aug 2025 18:00:41 +0800 Subject: [PATCH] =?UTF-8?q?redis=E8=AE=B0=E5=BD=95=E5=85=A5=E5=9C=BA?= =?UTF-8?q?=E4=BF=A1=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- freqtrade/templates/freqaiprimer.py | 93 ++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/freqtrade/templates/freqaiprimer.py b/freqtrade/templates/freqaiprimer.py index 2d332a23..4c0881bc 100644 --- a/freqtrade/templates/freqaiprimer.py +++ b/freqtrade/templates/freqaiprimer.py @@ -834,6 +834,38 @@ class FreqaiPrimer(IStrategy): # 绿色通道和趋势状态的条件已经设置好buy_condition conditions.append(buy_condition) + # 🎯 计算信号强度评分 (0-100分) 并作为tag传递 + signal_strength = 0.0 + if len(dataframe) > 0: + # 基础评分:趋势得分影响 + base_score = trend_score * 0.4 # 趋势得分占40% + + # 条件满足评分 + if is_green_channel: + # 绿色通道:基础分60 + 条件满足加分 + satisfied_count = int(cond1.iloc[-1]) + int(cond2.iloc[-1]) + int(cond3.iloc[-1]) + int(cond4.iloc[-1]) + int(cond5.iloc[-1]) + signal_strength = 60 + (satisfied_count * 8) + base_score + elif trend_status == "bullish": + # 牛市正常:基础分50 + 条件满足加分 + satisfied_count = int(cond1.iloc[-1]) + int(cond2.iloc[-1]) + int(cond3.iloc[-1]) + int(cond4.iloc[-1]) + int(cond5.iloc[-1]) + signal_strength = 50 + (satisfied_count * 7) + base_score * 1.2 + elif trend_status == "bearish": + # 熊市:基础分40 + 超跌加分 + satisfied_count = int(cond1.iloc[-1]) + int(cond2.iloc[-1]) + int(cond3.iloc[-1]) + int(cond4.iloc[-1]) + int(cond5.iloc[-1]) + oversold_bonus = max(0, (100 - trend_score) * 0.3) + signal_strength = 40 + (satisfied_count * 8) + oversold_bonus + else: # ranging + # 震荡市:基础分45 + 条件满足加分 + satisfied_count = int(cond1.iloc[-1]) + int(cond2.iloc[-1]) + int(cond3.iloc[-1]) + int(cond4.iloc[-1]) + int(cond5.iloc[-1]) + signal_strength = 45 + (satisfied_count * 8) + base_score + + # 限制在0-100分范围 + signal_strength = max(0, min(100, signal_strength)) + + # 存储信号强度到dataframe + dataframe.loc[buy_condition, 'signal_strength'] = signal_strength + dataframe.loc[buy_condition, 'immediate_entry'] = signal_strength >= 75 # 75分以上立即入场 + # 调试日志 - 仅在日志中使用最后一行的值 if len(dataframe) > 0: divergence_value = dataframe["&-price_value_divergence"].iloc[-1] @@ -892,6 +924,54 @@ class FreqaiPrimer(IStrategy): dataframe.loc[combined_condition, 'enter_long'] = 1 dataframe.loc[combined_condition, 'entry_tag'] = entry_tag + # 🎯 记录实际入场信号到Redis(只在enter_long=1时) + enter_long_indices = dataframe[dataframe['enter_long'] == 1].index + if len(enter_long_indices) > 0: + # 获取最后一根K线的信号数据(避免重复记录) + last_idx = enter_long_indices[-1] + + try: + # 获取主机名 + hostname = socket.gethostname() + + # 将币对名从BTC/USDT格式转换为BTC-USDT格式 + pair_redis = pair.replace('/', '-') + + # 获取当前时间戳(毫秒) + timestamp_ms = int(time.time() * 1000) + + # 构建Redis key: ${主机名}_${币对名}_entry_${时间戳} + redis_key = f"{hostname}_{pair_redis}_entry_{timestamp_ms}" + + # 获取Redis客户端 + redis_client = self._get_redis_client() + if redis_client: + # 准备要存储的信号数据 + signal_data = { + 'signal_strength': float(dataframe.loc[last_idx, 'signal_strength']) if 'signal_strength' in dataframe.columns else 0.0, + 'entry_tag': str(dataframe.loc[last_idx, 'entry_tag']) if 'entry_tag' in dataframe.columns else str(entry_tag), + 'trend_score': float(trend_score), + 'market_regime': str(market_regime), + 'timestamp': timestamp_ms, + 'pair': str(pair), + 'hostname': str(hostname), + 'immediate_entry': bool(dataframe.loc[last_idx, 'immediate_entry']) if 'immediate_entry' in dataframe.columns else False + } + + # 将信号数据序列化为JSON字符串 + signal_json = json.dumps(signal_data) + + # 存储到Redis,设置24小时过期时间 + redis_client.setex(redis_key, 86400, signal_json) + + logger.info(f"[Redis] ✅ 实际入场信号已记录: {redis_key}, 信号强度: {signal_data['signal_strength']:.2f}, 趋势: {signal_data['entry_tag']}") + + else: + logger.debug(f"[Redis] ⚠️ Redis客户端不可用,跳过记录: {pair}") + + except Exception as e: + logger.error(f"[Redis] ❌ 记录入场信号失败: {e}") + # 输出每个条件的状态 logger.info(f"[{pair}] === 买入条件检查 ===") satisfied_conditions = [] @@ -1331,7 +1411,7 @@ class FreqaiPrimer(IStrategy): return None def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, - time_in_force: str, current_time: datetime, **kwargs) -> bool: + time_in_force: str, current_time: datetime, entry_tag: str | None = None, **kwargs) -> bool: # 调试日志:记录输入参数 logger.info(f"[{pair}] confirm_trade_entry called with rate={rate}, type(rate)={type(rate)}, " f"amount={amount}, order_type={order_type}, time_in_force={time_in_force}") @@ -1781,6 +1861,17 @@ class FreqaiPrimer(IStrategy): # 初始化循环计数器 self._loop_counter = 0 + + # 🎯 测试Redis连接 + redis_client = self._get_redis_client() + if redis_client: + try: + redis_client.ping() + logger.info("✅ Redis连接测试成功 - 入场信号记录已启用") + except Exception as e: + logger.error(f"❌ Redis连接测试失败: {e}") + else: + logger.warning("⚠️ Redis客户端初始化失败,入场信号将不会记录到Redis") def bot_stop(self, **kwargs) -> None: """