diff --git a/freqtrade/templates/freqaiprimer.py b/freqtrade/templates/freqaiprimer.py index b1fad92d..2109b927 100644 --- a/freqtrade/templates/freqaiprimer.py +++ b/freqtrade/templates/freqaiprimer.py @@ -121,10 +121,37 @@ class FreqaiPrimer(IStrategy): # 读取 Redis 配置 self.redis_url = config.get('redis', {}).get('url', None) self.stats_logged = False + + # 初始化 Redis 客户端 if self.redis_url: - logger.info(f"✅ 成功读取 Redis 配置: {self.redis_url}") + logger.info(f"尝试初始化 Redis 客户端,URL={self.redis_url}") + try: + import redis + self.redis_client = redis.from_url(self.redis_url) + logger.info(f"✅ 成功初始化 Redis 客户端,URL={self.redis_url}") + + # 测试 Redis 连接 + logger.debug("正在测试 Redis 连接...") + try: + ping_result = self.redis_client.ping() + if ping_result: + logger.info("✅ Redis 连接测试成功: 收到 PONG 响应") + else: + logger.error("❌ Redis 连接测试失败: 未收到 PONG 响应") + raise RuntimeError("Redis 连接测试失败,请检查 Redis 服务状态") + except redis.exceptions.RedisError as e: + logger.error(f"❌ Redis PING 测试失败,错误: {e}") + raise + + except redis.exceptions.ConnectionError as e: + logger.error(f"❌ 无法连接到 Redis,URL={self.redis_url}, 错误: {e}") + raise SystemExit("Redis 服务不可用,请检查配置或服务状态") + except Exception as e: + logger.error(f"❌ Redis 初始化失败,未知错误: {e}") + raise SystemExit("Redis 初始化失败,请检查日志以获取更多信息") else: - logger.warning("⚠️ 未找到 Redis 配置") + logger.error("❌ 未找到 Redis 配置") + raise SystemExit("Redis 配置缺失,请在配置文件中添加 redis.url") # 配置日志格式,包含时间戳 logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', @@ -1048,27 +1075,48 @@ class FreqaiPrimer(IStrategy): # 创建 Redis 客户端 if not hasattr(self, 'redis_client') and self.redis_url: - self.redis_client = redis.from_url(self.redis_url) - logger.info("✅ Redis 客户端已初始化") + try: + self.redis_client = redis.from_url(self.redis_url) + logger.info("✅ Redis 客户端已成功初始化") + except Exception as e: + logger.error(f"❌ 初始化 Redis 客户端失败: {e}") + raise # 生成缓存键 cache_key = f"trend_score:{pair}:{timeframe}:{timestamp}" + logger.debug(f"[{pair}] 生成 Redis 缓存键:{cache_key} (时间戳: {timestamp})") # 尝试从 Redis 获取趋势得分 if self.redis_client: - cached_score = self.redis_client.get(cache_key) - if cached_score is not None: - logger.info(f"[{pair}] 从 Redis 缓存中获取 trend_score: {float(cached_score):.2f}") - return float(cached_score) + logger.debug(f"[{pair}] 尝试从 Redis 查询趋势得分,key={cache_key}") + try: + cached_score = self.redis_client.get(cache_key) + if cached_score is not None: + logger.info(f"[{pair}] 🟩 Redis 缓存命中:key={cache_key}, value={float(cached_score):.2f}") + return float(cached_score) + else: + logger.info(f"[{pair}] 🔴 Redis 缓存未命中:key={cache_key}") + except redis.exceptions.RedisError as e: + logger.error(f"[{pair}] Redis 查询失败,key={cache_key}, 错误: {e}") + raise # 缓存未命中,计算趋势得分 + logger.info(f"[{pair}] Redis 缓存未命中,开始计算趋势得分 (时间戳: {timestamp})") + + # 缓存未命中,计算趋势得分 + logger.info(f"[{pair}] Redis 缓存未命中,开始计算趋势得分") trend_score = self.get_market_trend(dataframe=dataframe, metadata=metadata) - logger.info(f"[{pair}] 计算 trend_score: {trend_score:.2f}") + logger.info(f"[{pair}] 成功计算趋势得分: {trend_score:.2f}") # 将趋势得分存储到 Redis,设置过期时间为 1 天 if self.redis_client: - self.redis_client.setex(cache_key, 86400, trend_score) - logger.info(f"[{pair}] 已将 trend_score 存储到 Redis,key={cache_key}, value={trend_score:.2f}") + logger.debug(f"[{pair}] 尝试将趋势得分写入 Redis,key={cache_key}, value={trend_score:.2f}") + try: + self.redis_client.setex(cache_key, 86400, trend_score) + logger.info(f"[{pair}] 成功将趋势得分存储到 Redis,key={cache_key}, value={trend_score:.2f}") + except redis.exceptions.RedisError as e: + logger.error(f"[{pair}] Redis 写入失败,key={cache_key}, 错误: {e}") + raise return trend_score @@ -1093,18 +1141,33 @@ class FreqaiPrimer(IStrategy): for i in range(-20, 0): # 获取历史数据片段 hist_df = dataframe.iloc[:i+1] if i != -1 else dataframe - if len(hist_df) > 0: - # 使用新的 get_trend_score_with_cache 方法替代直接调用 get_market_trend - # 确保索引是 datetime 类型 - if not isinstance(hist_df.index, pd.DatetimeIndex): + + # 确保索引是 DatetimeIndex 类型 + if not isinstance(hist_df.index, pd.DatetimeIndex): + try: hist_df.index = pd.to_datetime(hist_df.index) - - # 获取时间戳 - timestamp = int(hist_df.index[-1].timestamp()) - score = self.get_trend_score_with_cache(pair=pair, timeframe=self.timeframe, timestamp=timestamp, dataframe=hist_df, metadata=metadata) - trend_scores_20.append(score) - else: + logger.debug(f"[{pair}] 成功将索引转换为 DatetimeIndex") + except Exception as e: + logger.error(f"[{pair}] 无法将索引转换为 DatetimeIndex: {e}") + hist_df = pd.DataFrame() # 如果转换失败,设置为空 DataFrame + + # 检查 hist_df 是否为空 + if len(hist_df) == 0: + logger.warning(f"[{pair}] 历史数据片段为空,使用默认趋势得分 50") trend_scores_20.append(50) # 默认值 + continue + + # 获取时间戳并记录日志 + try: + timestamp = int(hist_df.index[-1].timestamp()) + logger.debug(f"[{pair}] 生成时间戳:{timestamp}, 时间:{hist_df.index[-1]}") + except Exception as e: + logger.error(f"[{pair}] 无法生成时间戳: {e}") + timestamp = 0 # 如果生成失败,使用默认时间戳 0 + + # 使用新的 get_trend_score_with_cache 方法替代直接调用 get_market_trend + score = self.get_trend_score_with_cache(pair=pair, timeframe=self.timeframe, timestamp=timestamp, dataframe=hist_df, metadata=metadata) + trend_scores_20.append(score) # 分段计算加权得分 # 第一段:最近1-3个周期 (索引-3到-1)