diff --git a/backend/app/crypto_agent/crypto_agent.py b/backend/app/crypto_agent/crypto_agent.py index 18c5c70..1fd68bb 100644 --- a/backend/app/crypto_agent/crypto_agent.py +++ b/backend/app/crypto_agent/crypto_agent.py @@ -264,11 +264,16 @@ class CryptoAgent: logger.info(f"\n📤 【发送通知】") # 构建通知消息 - message = self.llm_analyzer.format_signal_message(best_signal, symbol) + telegram_message = self.llm_analyzer.format_signal_message(best_signal, symbol) + feishu_card = self.llm_analyzer.format_feishu_card(best_signal, symbol) - # 发送通知 - await self.feishu.send_text(message) - await self.telegram.send_message(message) + # 发送通知 - 飞书使用卡片格式,Telegram 使用文本格式 + await self.feishu.send_card( + feishu_card['title'], + feishu_card['content'], + feishu_card['color'] + ) + await self.telegram.send_message(telegram_message) logger.info(f" ✅ 已发送信号通知") diff --git a/backend/app/crypto_agent/llm_signal_analyzer.py b/backend/app/crypto_agent/llm_signal_analyzer.py index f65cf1d..4fe1bcb 100644 --- a/backend/app/crypto_agent/llm_signal_analyzer.py +++ b/backend/app/crypto_agent/llm_signal_analyzer.py @@ -397,7 +397,7 @@ class LLMSignalAnalyzer: def format_signal_message(self, signal: Dict[str, Any], symbol: str) -> str: """ - 格式化信号消息(用于通知) + 格式化信号消息(用于 Telegram 通知) Args: signal: 信号数据 @@ -424,20 +424,95 @@ class LLMSignalAnalyzer: # 等级图标 grade_icon = {'A': '⭐⭐⭐', 'B': '⭐⭐', 'C': '⭐', 'D': ''}.get(grade, '') + # 方向图标 + action_icon = '🟢' if signal['action'] == 'buy' else '🔴' + + # 计算风险收益比 + entry = signal.get('entry_price', 0) + sl = signal.get('stop_loss', 0) + tp = signal.get('take_profit', 0) + sl_percent = ((sl - entry) / entry * 100) if entry else 0 + tp_percent = ((tp - entry) / entry * 100) if entry else 0 + message = f"""📊 {symbol} {signal_type}信号 -方向: {action} -等级: {grade} {grade_icon} -置信度: {confidence}% +{action_icon} **方向**: {action} +⭐ **等级**: {grade} {grade_icon} +📈 **置信度**: {confidence}% -入场价: ${signal.get('entry_price', 0):,.2f} -止损价: ${signal.get('stop_loss', 0):,.2f} -止盈价: ${signal.get('take_profit', 0):,.2f} +💰 **入场价**: ${entry:,.2f} +🛑 **止损价**: ${sl:,.2f} ({sl_percent:+.1f}%) +🎯 **止盈价**: ${tp:,.2f} ({tp_percent:+.1f}%) -📝 分析理由: +📝 **分析理由**: {signal.get('reason', '无')} -⚠️ 风险提示: +⚠️ **风险提示**: {signal.get('risk_warning', '请注意风险控制')}""" return message + + def format_feishu_card(self, signal: Dict[str, Any], symbol: str) -> Dict[str, Any]: + """ + 格式化飞书卡片消息 + + Args: + signal: 信号数据 + symbol: 交易对 + + Returns: + 包含 title, content, color 的字典 + """ + type_map = { + 'short_term': '短线', + 'medium_term': '中线', + 'long_term': '长线' + } + action_map = { + 'buy': '做多', + 'sell': '做空' + } + + signal_type = type_map.get(signal['type'], signal['type']) + action = action_map.get(signal['action'], signal['action']) + grade = signal.get('grade', 'C') + confidence = signal.get('confidence', 0) + + # 等级图标 + grade_icon = {'A': '⭐⭐⭐', 'B': '⭐⭐', 'C': '⭐', 'D': ''}.get(grade, '') + + # 标题和颜色 + if signal['action'] == 'buy': + title = f"🟢 {symbol} {signal_type}做多信号" + color = "green" + else: + title = f"🔴 {symbol} {signal_type}做空信号" + color = "red" + + # 计算风险收益比 + entry = signal.get('entry_price', 0) + sl = signal.get('stop_loss', 0) + tp = signal.get('take_profit', 0) + sl_percent = ((sl - entry) / entry * 100) if entry else 0 + tp_percent = ((tp - entry) / entry * 100) if entry else 0 + + # 构建 Markdown 内容 + content_parts = [ + f"**{signal_type}** | **{grade}**{grade_icon} | **{confidence}%** 置信度", + "", + f"💰 **入场**: ${entry:,.2f}", + f"🛑 **止损**: ${sl:,.2f} ({sl_percent:+.1f}%)", + f"🎯 **止盈**: ${tp:,.2f} ({tp_percent:+.1f}%)", + "", + f"📝 **分析理由**:", + f"{signal.get('reason', '无')}", + "", + f"⚠️ **风险提示**:", + f"{signal.get('risk_warning', '请注意风险控制')}", + ] + + return { + 'title': title, + 'content': '\n'.join(content_parts), + 'color': color + }