This commit is contained in:
aaron 2026-02-24 15:31:32 +08:00
parent e6d17d1e65
commit 926296fc57
5 changed files with 102 additions and 46 deletions

View File

@ -94,7 +94,8 @@ class Settings(BaseSettings):
binance_api_secret: str = "" binance_api_secret: str = ""
# 飞书机器人配置 # 飞书机器人配置
feishu_webhook_url: str = "https://open.feishu.cn/open-apis/bot/v2/hook/8a1dcf69-6753-41e2-a393-edc4f7822db0" 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_enabled: bool = True # 是否启用飞书通知 feishu_enabled: bool = True # 是否启用飞书通知
# Telegram 机器人配置 # Telegram 机器人配置

View File

@ -155,20 +155,27 @@ class CryptoAgent:
async def _notify_breakeven_triggered(self, result: Dict[str, Any]): async def _notify_breakeven_triggered(self, result: Dict[str, Any]):
"""发送移动止损触发通知""" """发送移动止损触发通知"""
side_text = "做多" if result.get('side') == 'long' else "做空" side_text = "做多" if result.get('side') == 'long' else "做空"
side_icon = '🟢' if result.get('side') == 'long' else '🔴'
pnl_percent = result.get('current_pnl_percent', 0)
message = f"""📈 移动止损已启动 title = f"📈 移动止损已启动 - {result.get('symbol')}"
交易对: {result.get('symbol')} content_parts = [
方向: {side_text} f"{side_icon} **方向**: {side_text}",
开仓价: ${result.get('filled_price', 0):,.2f} f"",
当前盈利: {result.get('current_pnl_percent', 0):.2f}% f"💰 **开仓价**: ${result.get('filled_price', 0):,.2f}",
新止损价: ${result.get('new_stop_loss', 0):,.2f} f"📈 **当前盈利**: {pnl_percent:+.2f}%",
f"🛑 **新止损价**: ${result.get('new_stop_loss', 0):,.2f}",
f"",
f"💰 锁定利润,让利润奔跑"
]
💰 锁定利润让利润奔跑""" content = "\n".join(content_parts)
if self.settings.feishu_enabled: if self.settings.feishu_enabled:
await self.feishu.send_text(message) await self.feishu.send_card(title, content, "green")
if self.settings.telegram_enabled: if self.settings.telegram_enabled:
message = f"{title}\n\n{content}"
await self.telegram.send_message(message) await self.telegram.send_message(message)
logger.info(f"已发送移动止损通知: {result.get('order_id')}") logger.info(f"已发送移动止损通知: {result.get('order_id')}")

View File

@ -136,36 +136,53 @@ async def price_monitor_loop():
if event_type == 'stop_loss_moved': if event_type == 'stop_loss_moved':
move_type = result.get('move_type', '') move_type = result.get('move_type', '')
side_text = "做多" if result.get('side') == 'long' else "做空" side_text = "做多" if result.get('side') == 'long' else "做空"
side_icon = '🟢' if result.get('side') == 'long' else '🔴'
pnl = result.get('current_pnl_percent', 0) pnl = result.get('current_pnl_percent', 0)
symbol_display = result.get('symbol', '')
if move_type == 'trailing_first': if move_type == 'trailing_first':
message = f"""📈 移动止损已激活 title = f"📈 移动止损已激活 - {symbol_display}"
content_parts = [
交易对: {result.get('symbol')} f"{side_icon} **方向**: {side_text}",
方向: {side_text} f"",
当前盈利: {pnl:+.2f}% f"📈 **当前盈利**: {pnl:+.2f}%",
新止损价: ${result.get('new_stop_loss', 0):,.2f} f"🛑 **新止损价**: ${result.get('new_stop_loss', 0):,.2f}",
💰 锁定利润让利润奔跑""" f"",
f"💰 锁定利润,让利润奔跑"
]
color = "green"
elif move_type == 'trailing_update': elif move_type == 'trailing_update':
message = f"""📊 止损已上移 title = f"📊 止损已上移 - {symbol_display}"
content_parts = [
交易对: {result.get('symbol')} f"{side_icon} **方向**: {side_text}",
方向: {side_text} f"",
当前盈利: {pnl:+.2f}% f"📈 **当前盈利**: {pnl:+.2f}%",
新止损价: ${result.get('new_stop_loss', 0):,.2f} f"🛑 **新止损价**: ${result.get('new_stop_loss', 0):,.2f}",
🎯 继续锁定更多利润""" f"",
f"🎯 继续锁定更多利润"
]
color = "blue"
elif move_type == 'breakeven': elif move_type == 'breakeven':
message = f"""📈 移动止损已启动 title = f"📈 移动止损已启动 - {symbol_display}"
content_parts = [
f"{side_icon} **方向**: {side_text}",
f"",
f"📈 **当前盈利**: {pnl:+.2f}%",
f"🛑 **新止损价**: ${result.get('new_stop_loss', 0):,.2f}",
f"",
f"💰 锁定利润,让利润奔跑"
]
color = "green"
else:
continue
交易对: {result.get('symbol')} content = "\n".join(content_parts)
方向: {side_text}
当前盈利: {pnl:+.2f}%
止损移至: ${result.get('new_stop_loss', 0):,.2f}
💰 锁定利润让利润奔跑"""
# 发送通知 # 发送通知
await feishu.send_text(message) await feishu.send_card(title, content, color)
await telegram.send_message(message) if telegram:
message = f"{title}\n\n{content}"
await telegram.send_message(message)
logger.info(f"后台监控触发止损移动: {result.get('order_id')} | {symbol}") logger.info(f"后台监控触发止损移动: {result.get('order_id')} | {symbol}")
continue continue

View File

@ -1,5 +1,6 @@
""" """
飞书通知服务 - 通过 Webhook 发送交易信号通知 飞书通知服务 - 通过 Webhook 发送交易信号通知
支持加密货币和股票两个独立的 webhook
""" """
import json import json
import httpx import httpx
@ -11,25 +12,40 @@ from app.config import get_settings
class FeishuService: class FeishuService:
"""飞书机器人通知服务""" """飞书机器人通知服务"""
def __init__(self, webhook_url: str = ""): def __init__(self, webhook_url: str = "", service_type: str = "crypto"):
""" """
初始化飞书服务 初始化飞书服务
Args: Args:
webhook_url: 飞书机器人 Webhook URL webhook_url: 飞书机器人 Webhook URL如果为空则根据 service_type 从配置读取
service_type: 服务类型 ("crypto" "stock")
""" """
settings = get_settings() settings = get_settings()
self.webhook_url = webhook_url or getattr(settings, 'feishu_webhook_url', '')
# 如果传入了 webhook_url直接使用
if webhook_url:
self.webhook_url = webhook_url
else:
# 否则根据服务类型从配置读取
if service_type == "crypto":
self.webhook_url = getattr(settings, 'feishu_crypto_webhook_url', '')
elif service_type == "stock":
self.webhook_url = getattr(settings, 'feishu_stock_webhook_url', '')
else:
# 兼容旧配置
self.webhook_url = getattr(settings, 'feishu_webhook_url', '')
# 检查配置开关和 webhook_url 是否都有效 # 检查配置开关和 webhook_url 是否都有效
config_enabled = getattr(settings, 'feishu_enabled', True) config_enabled = getattr(settings, 'feishu_enabled', True)
self.enabled = config_enabled and bool(self.webhook_url) self.enabled = config_enabled and bool(self.webhook_url)
self.service_type = service_type
if not config_enabled: if not config_enabled:
logger.info("飞书通知已通过配置禁用") logger.info(f"飞书通知已通过配置禁用")
elif self.enabled: elif self.enabled:
logger.info("飞书通知服务初始化完成") logger.info(f"飞书通知服务初始化完成 ({service_type})")
else: else:
logger.warning("飞书 Webhook URL 未配置,通知功能已禁用") logger.warning(f"飞书 Webhook URL 未配置 ({service_type}),通知功能已禁用")
async def send_text(self, message: str) -> bool: async def send_text(self, message: str) -> bool:
""" """
@ -266,13 +282,28 @@ class FeishuService:
return False return False
# 全局实例(延迟初始化)
_feishu_service: Optional[FeishuService] = None # 全局实例(延迟初始化)- 分别用于加密货币和股票
_feishu_crypto_service: Optional[FeishuService] = None
_feishu_stock_service: Optional[FeishuService] = None
def get_feishu_service() -> FeishuService: def get_feishu_service() -> FeishuService:
"""获取飞书服务实例""" """获取飞书服务实例(默认 crypto保持向后兼容"""
global _feishu_service return get_feishu_crypto_service()
if _feishu_service is None:
_feishu_service = FeishuService()
return _feishu_service def get_feishu_crypto_service() -> FeishuService:
"""获取加密货币飞书服务实例"""
global _feishu_crypto_service
if _feishu_crypto_service is None:
_feishu_crypto_service = FeishuService(service_type="crypto")
return _feishu_crypto_service
def get_feishu_stock_service() -> FeishuService:
"""获取股票飞书服务实例"""
global _feishu_stock_service
if _feishu_stock_service is None:
_feishu_stock_service = FeishuService(service_type="stock")
return _feishu_stock_service

View File

@ -10,7 +10,7 @@ import pandas as pd
from app.utils.logger import logger from app.utils.logger import logger
from app.config import get_settings from app.config import get_settings
from app.services.yfinance_service import get_yfinance_service from app.services.yfinance_service import get_yfinance_service
from app.services.feishu_service import get_feishu_service from app.services.feishu_service import get_feishu_stock_service
from app.services.telegram_service import get_telegram_service from app.services.telegram_service import get_telegram_service
from app.services.signal_database_service import get_signal_db_service from app.services.signal_database_service import get_signal_db_service
from app.services.fundamental_service import get_fundamental_service from app.services.fundamental_service import get_fundamental_service
@ -86,7 +86,7 @@ class StockAgent:
"""初始化智能体""" """初始化智能体"""
self.settings = get_settings() self.settings = get_settings()
self.yfinance = get_yfinance_service() self.yfinance = get_yfinance_service()
self.feishu = get_feishu_service() self.feishu = get_feishu_stock_service()
self.telegram = get_telegram_service() self.telegram = get_telegram_service()
self.market_analyzer = StockMarketSignalAnalyzer() # 使用新的市场信号分析器 self.market_analyzer = StockMarketSignalAnalyzer() # 使用新的市场信号分析器
self.signal_db = get_signal_db_service() # 信号数据库服务 self.signal_db = get_signal_db_service() # 信号数据库服务