This commit is contained in:
aaron 2026-03-01 00:42:00 +08:00
parent 0a637053fc
commit 1a9bf9f74b
3 changed files with 46 additions and 37 deletions

View File

@ -97,6 +97,7 @@ class Settings(BaseSettings):
feishu_crypto_webhook_url: str = "https://open.feishu.cn/open-apis/bot/v2/hook/8a1dcf69-6753-41e2-a393-edc4f7822db0" # 加密货币通知
feishu_stock_webhook_url: str = "https://open.feishu.cn/open-apis/bot/v2/hook/408ab727-0dcd-4c7a-bde7-4aad38cbf807" # 股票通知
feishu_news_webhook_url: str = "https://open.feishu.cn/open-apis/bot/v2/hook/c7fd0db7-d295-451c-b943-130278a6cd9d" # 新闻智能体通知
feishu_paper_trading_webhook_url: str = "https://open.feishu.cn/open-apis/bot/v2/hook/3f5642e7-420b-45f7-8f88-fff92bb98c69" # 模拟交易通知(交易信号+决策+执行)
feishu_error_webhook_url: str = "https://open.feishu.cn/open-apis/bot/v2/hook/ba6952c9-3b0c-4bc1-8a43-ceaacb27b043" # 系统异常通知
feishu_enabled: bool = True # 是否启用飞书通知

View File

@ -9,7 +9,7 @@ import pandas as pd
from app.utils.logger import logger
from app.config import get_settings
from app.services.bitget_service import bitget_service
from app.services.feishu_service import get_feishu_service
from app.services.feishu_service import get_feishu_service, get_feishu_paper_trading_service
from app.services.telegram_service import get_telegram_service
from app.services.dingtalk_service import get_dingtalk_service
from app.services.paper_trading_service import get_paper_trading_service
@ -40,7 +40,8 @@ class CryptoAgent:
CryptoAgent._initialized = True
self.settings = get_settings()
self.exchange = bitget_service # 交易所服务
self.feishu = get_feishu_service()
self.feishu = get_feishu_service() # 通用飞书服务crypto等
self.feishu_paper = get_feishu_paper_trading_service() # 模拟交易专用飞书服务
self.telegram = get_telegram_service()
self.dingtalk = get_dingtalk_service() # 添加钉钉服务
@ -138,7 +139,7 @@ class CryptoAgent:
content = "\n".join(content_parts)
if self.settings.feishu_enabled:
await self.feishu.send_card(title, content, "green")
await self.feishu_paper.send_card(title, content, "green")
if self.settings.telegram_enabled:
message = f"{title}\n\n{content}"
await self.telegram.send_message(message)
@ -164,7 +165,7 @@ class CryptoAgent:
content = "\n".join(content_parts)
if self.settings.feishu_enabled:
await self.feishu.send_card(title, content, "orange")
await self.feishu_paper.send_card(title, content, "orange")
if self.settings.telegram_enabled:
message = f"{title}\n\n{content}"
await self.telegram.send_message(message)
@ -193,7 +194,7 @@ class CryptoAgent:
content = "\n".join(content_parts)
if self.settings.feishu_enabled:
await self.feishu.send_card(title, content, "green")
await self.feishu_paper.send_card(title, content, "green")
if self.settings.telegram_enabled:
message = f"{title}\n\n{content}"
await self.telegram.send_message(message)
@ -246,7 +247,7 @@ class CryptoAgent:
content = "\n".join(content_parts)
if self.settings.feishu_enabled:
await self.feishu.send_card(title, content, color)
await self.feishu_paper.send_card(title, content, color)
if self.settings.telegram_enabled:
message = f"{title}\n\n{content}"
await self.telegram.send_message(message)
@ -787,8 +788,7 @@ class CryptoAgent:
if decision_type == 'HOLD':
reasoning = paper_decision.get('reasoning', '观望')
logger.info(f"\n📊 交易决策: {reasoning}")
# 有信号但决策为 HOLD发送未执行通知
await self._notify_signal_not_executed(market_signal, paper_decision, current_price, is_paper=True)
# HOLD决策的理由已在交易决策通知中说明无需单独通知
else:
logger.info(f"\n📊 【执行交易】")
@ -810,14 +810,11 @@ class CryptoAgent:
paper_executed = True
else:
logger.error(f" ❌ 订单对象无效: 缺少order_id属性")
reason = "订单对象无效: 缺少order_id"
await self._notify_signal_not_executed(market_signal, paper_decision, current_price, is_paper=True, reason=reason)
# 订单创建失败,理由已在日志中记录,无需单独通知
else:
# 有信号但订单创建失败,发送未执行通知
# 订单创建失败,理由已在日志中记录,无需单独通知
reason = result.get('message', '订单创建失败') if result else '订单创建失败'
logger.warning(f" ⚠️ 交易未执行: {reason}")
await self._notify_signal_not_executed(market_signal, paper_decision, current_price, is_paper=True, reason=reason)
logger.warning(f" ⚠️ 交易未执行: {reason}")
elif decision_type == 'CLOSE':
await self._execute_close(paper_decision, paper_trading=True)
# CLOSE 操作也发送执行通知
@ -845,8 +842,7 @@ class CryptoAgent:
if decision_type == 'HOLD':
reasoning = real_decision.get('reasoning', '观望')
logger.info(f"\n💰 实盘交易: {reasoning}")
# 有信号但决策为 HOLD发送未执行通知
await self._notify_signal_not_executed(market_signal, real_decision, current_price, is_paper=False)
# HOLD决策的理由已在交易决策通知中说明无需单独通知
else:
logger.info(f"\n💰 【执行实盘交易】")
@ -859,10 +855,9 @@ class CryptoAgent:
await self._send_signal_notification(market_signal, real_decision, current_price, is_paper=False)
real_executed = True
else:
# 有信号但订单创建失败,发送未执行通知
# 订单创建失败,理由已在日志中记录,无需单独通知
reason = result.get('message', '订单创建失败') if result else '订单创建失败'
await self._notify_signal_not_executed(market_signal, real_decision, current_price, is_paper=False, reason=reason)
logger.warning(f" ⚠️ 实盘交易未执行,已发送通知")
logger.warning(f" ⚠️ 实盘交易未执行: {reason}")
elif decision_type == 'CLOSE':
await self._execute_close(real_decision, paper_trading=False)
# CLOSE 操作也发送执行通知
@ -1008,12 +1003,12 @@ class CryptoAgent:
sl_display = "N/A"
tp_display = "N/A"
# 构建卡片标题和颜色
# 构建卡片标题和颜色 - 添加 [信号] 前缀区分
if sig_action == 'buy':
title = f"🟢 {symbol} {timeframe_text}做多信号"
title = f"[信号] 🟢 {symbol} {timeframe_text}做多信号"
color = "green"
else:
title = f"🔴 {symbol} {timeframe_text}做空信号"
title = f"[信号] 🔴 {symbol} {timeframe_text}做空信号"
color = "red"
# 构建卡片内容
@ -1046,7 +1041,7 @@ class CryptoAgent:
content = "\n".join(content_parts)
# 根据配置发送通知
# 根据配置发送通知 - [信号] 发送到 crypto webhook
if self.settings.feishu_enabled:
await self.feishu.send_card(title, content, color)
if self.settings.telegram_enabled:
@ -1098,8 +1093,8 @@ class CryptoAgent:
}
color = color_map.get(decision_type, 'blue')
# 构建标题
title = f"{account_type} {symbol} 交易决策: {decision_text}"
# 构建标题 - 添加 [决策] 前缀区分
title = f"[决策] {account_type} {symbol} 交易决策: {decision_text}"
# 获取最佳信号用于显示
best_signal = self._get_best_signal_from_market(market_signal)
@ -1181,7 +1176,7 @@ class CryptoAgent:
content = "\n".join(content_parts)
# 发送通知
# 发送通知 - [决策] 发送到 crypto webhook
if self.settings.feishu_enabled:
await self.feishu.send_card(title, content, color)
if self.settings.telegram_enabled:
@ -1253,26 +1248,26 @@ class CryptoAgent:
position_map = {'heavy': '🔥 重仓', 'medium': '📊 中仓', 'light': '🌱 轻仓'}
position_display = position_map.get(position_size, '🌱 轻仓')
# 构建卡片标题和颜色 - 考虑入场方式
# 构建卡片标题和颜色 - 考虑入场方式,添加 [执行] 前缀区分
# 挂单时标题显示"挂单",现价单时显示"开仓"/"平仓"等
if decision_type == 'OPEN':
decision_title = '挂单' if entry_type == 'limit' else '开仓'
title = f"{account_type} {symbol} {decision_title}"
title = f"[执行] {account_type} {symbol} {decision_title}"
color = "green"
elif decision_type == 'CLOSE':
decision_title = '挂单' if entry_type == 'limit' else '平仓'
title = f"{account_type} {symbol} {decision_title}"
title = f"[执行] {account_type} {symbol} {decision_title}"
color = "orange"
elif decision_type == 'ADD':
decision_title = '挂单' if entry_type == 'limit' else '加仓'
title = f"{account_type} {symbol} {decision_title}"
title = f"[执行] {account_type} {symbol} {decision_title}"
color = "green"
elif decision_type == 'REDUCE':
decision_title = '挂单' if entry_type == 'limit' else '减仓'
title = f"{account_type} {symbol} {decision_title}"
title = f"[执行] {account_type} {symbol} {decision_title}"
color = "orange"
else:
title = f"{account_type} {symbol} 交易执行"
title = f"[执行] {account_type} {symbol} 交易执行"
color = "blue"
# 构建卡片内容
@ -1315,9 +1310,9 @@ class CryptoAgent:
content = "\n".join(content_parts)
# 根据配置发送通知
# 根据配置发送通知 - 所有订单执行都发送到 paper trading webhook
if self.settings.feishu_enabled:
await self.feishu.send_card(title, content, color)
await self.feishu_paper.send_card(title, content, color)
if self.settings.telegram_enabled:
# Telegram 使用文本格式
message = f"{title}\n\n{content}"
@ -1806,7 +1801,7 @@ class CryptoAgent:
content = "\n".join(content_parts)
if self.settings.feishu_enabled:
await self.feishu.send_card(title, content, "red")
await self.feishu_paper.send_card(title, content, "red")
if self.settings.telegram_enabled:
message = f"{title}\n\n{content}"
await self.telegram.send_message(message)
@ -1859,7 +1854,7 @@ class CryptoAgent:
content = "\n".join(content_parts)
if self.settings.feishu_enabled:
await self.feishu.send_card(title, content, "blue")
await self.feishu_paper.send_card(title, content, "blue")
if self.settings.telegram_enabled:
message = f"{title}\n\n{content}"
await self.telegram.send_message(message)

View File

@ -18,7 +18,7 @@ class FeishuService:
Args:
webhook_url: 飞书机器人 Webhook URL如果为空则根据 service_type 从配置读取
service_type: 服务类型 ("crypto" "stock")
service_type: 服务类型 ("crypto", "stock", "news", "paper_trading", "error")
"""
settings = get_settings()
@ -33,6 +33,10 @@ class FeishuService:
self.webhook_url = getattr(settings, 'feishu_stock_webhook_url', '')
elif service_type == "news":
self.webhook_url = getattr(settings, 'feishu_news_webhook_url', '')
elif service_type == "paper_trading":
self.webhook_url = getattr(settings, 'feishu_paper_trading_webhook_url', '')
elif service_type == "error":
self.webhook_url = getattr(settings, 'feishu_error_webhook_url', '')
else:
# 兼容旧配置
self.webhook_url = getattr(settings, 'feishu_webhook_url', '')
@ -285,10 +289,11 @@ class FeishuService:
# 全局实例(延迟初始化)- 分别用于加密货币、股票和新闻
# 全局实例(延迟初始化)- 分别用于加密货币、股票、新闻和模拟交易
_feishu_crypto_service: Optional[FeishuService] = None
_feishu_stock_service: Optional[FeishuService] = None
_feishu_news_service: Optional[FeishuService] = None
_feishu_paper_trading_service: Optional[FeishuService] = None
def get_feishu_service() -> FeishuService:
@ -318,3 +323,11 @@ def get_feishu_news_service() -> FeishuService:
if _feishu_news_service is None:
_feishu_news_service = FeishuService(service_type="news")
return _feishu_news_service
def get_feishu_paper_trading_service() -> FeishuService:
"""获取模拟交易飞书服务实例"""
global _feishu_paper_trading_service
if _feishu_paper_trading_service is None:
_feishu_paper_trading_service = FeishuService(service_type="paper_trading")
return _feishu_paper_trading_service