crypto.ai/cryptoai/utils/dingtalk_bot.py
2025-04-27 14:12:27 +08:00

398 lines
14 KiB
Python

import json
import requests
import time
import hmac
import hashlib
import base64
import urllib.parse
import traceback
from typing import Dict, Any, List, Optional, Union
class DingTalkBot:
"""钉钉机器人工具类,用于发送分析结果到钉钉群"""
def __init__(self, webhook_url: str, secret: Optional[str] = None):
"""
初始化钉钉机器人
Args:
webhook_url: 钉钉机器人的webhook地址
secret: 钉钉机器人的签名密钥(如果启用了安全设置)
"""
self.webhook_url = webhook_url
self.secret = secret
def _sign(self) -> str:
"""
生成钉钉机器人签名
Returns:
签名后的URL
"""
if not self.secret:
return self.webhook_url
timestamp = str(round(time.time() * 1000))
string_to_sign = f"{timestamp}\n{self.secret}"
hmac_code = hmac.new(
self.secret.encode(),
string_to_sign.encode(),
digestmod=hashlib.sha256
).digest()
sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
return f"{self.webhook_url}&timestamp={timestamp}&sign={sign}"
def send_text(self, content: str, at_mobiles: List[str] = None, at_all: bool = False) -> Dict[str, Any]:
"""
发送文本消息
Args:
content: 消息内容
at_mobiles: 要@的手机号列表
at_all: 是否@所有人
Returns:
接口返回结果
"""
data = {
"msgtype": "text",
"text": {"content": content},
"at": {
"atMobiles": at_mobiles if at_mobiles else [],
"isAtAll": at_all
}
}
return self._post(data)
def send_markdown(self, title: str, text: str, at_mobiles: List[str] = None, at_all: bool = False) -> Dict[str, Any]:
"""
发送Markdown消息
Args:
title: 消息标题
text: Markdown格式的消息内容
at_mobiles: 要@的手机号列表
at_all: 是否@所有人
Returns:
接口返回结果
"""
data = {
"msgtype": "markdown",
"markdown": {
"title": title,
"text": text
},
"at": {
"atMobiles": at_mobiles if at_mobiles else [],
"isAtAll": at_all
}
}
return self._post(data)
def _post(self, data: Dict[str, Any]) -> Dict[str, Any]:
"""
发送消息到钉钉
Args:
data: 消息数据
Returns:
接口返回结果
"""
try:
webhook = self._sign()
headers = {'Content-Type': 'application/json; charset=utf-8'}
response = requests.post(webhook, json=data, headers=headers)
return response.json()
except Exception as e:
print(f"发送钉钉消息时出错: {e}")
traceback.print_exc()
return {"errcode": -1, "errmsg": str(e)}
def format_analysis_result(self, symbol: str, analysis_result: Dict[str, Any]) -> str:
"""
格式化分析结果为Markdown格式
Args:
symbol: 交易对符号
analysis_result: 分析结果
Returns:
格式化后的Markdown文本
"""
try:
if not analysis_result or 'error' in analysis_result:
return f"### {symbol} 分析结果错误\n\n获取分析结果时出错: {analysis_result.get('error', '未知错误')}"
# 提取关键信息
market_trend = analysis_result.get('market_trend', '未知')
support_levels = analysis_result.get('support_levels', [])
if isinstance(support_levels, list):
support_levels_str = ''.join([str(level) for level in support_levels])
else:
support_levels_str = str(support_levels)
resistance_levels = analysis_result.get('resistance_levels', [])
if isinstance(resistance_levels, list):
resistance_levels_str = ''.join([str(level) for level in resistance_levels])
else:
resistance_levels_str = str(resistance_levels)
volume_analysis = analysis_result.get('volume_analysis', '未知')
market_sentiment = analysis_result.get('market_sentiment', '未知')
summary = analysis_result.get('summary', '无摘要')
# 根据市场趋势设置颜色标志
if '' in market_trend or 'bull' in str(market_trend).lower():
trend_icon = "🟢"
elif '' in market_trend or 'bear' in str(market_trend).lower():
trend_icon = "🔴"
else:
trend_icon = "🟡"
# 构建Markdown文本
markdown = f"""### {trend_icon} {symbol} 市场分析
**市场趋势**: {market_trend}
**支撑位**: {support_levels_str}
**阻力位**: {resistance_levels_str}
**交易量分析**: {volume_analysis}
**市场情绪**: {market_sentiment}
**总结**: {summary}
*分析时间: {time.strftime('%Y-%m-%d %H:%M:%S')}*
"""
return markdown
except Exception as e:
print(f"格式化分析结果时出错: {e}")
traceback.print_exc()
return f"### {symbol} 格式化分析结果出错\n\n{str(e)}"
def format_prediction_result(self, symbol: str, prediction_result: Dict[str, Any]) -> str:
"""
格式化预测结果为Markdown格式
Args:
symbol: 交易对符号
prediction_result: 预测结果
Returns:
格式化后的Markdown文本
"""
try:
if not prediction_result or 'error' in prediction_result:
return f"### {symbol} 预测结果错误\n\n获取预测结果时出错: {prediction_result.get('error', '未知错误')}"
# 提取关键信息
current_price = prediction_result.get('current_price', '未知')
prediction_24h = prediction_result.get('prediction_24h', {})
prediction_7d = prediction_result.get('prediction_7d', {})
prediction_30d = prediction_result.get('prediction_30d', {})
key_factors = prediction_result.get('key_factors', [])
if isinstance(key_factors, list):
key_factors_str = '\n'.join([f"- {factor}" for factor in key_factors])
else:
key_factors_str = str(key_factors)
risk_assessment = prediction_result.get('risk_assessment', '未知')
# 格式化预测数据
def format_prediction(pred_data):
if not pred_data:
return "无数据"
price_range = pred_data.get('price_range', '未知')
trend = pred_data.get('trend', '未知')
confidence = pred_data.get('confidence', '未知')
# 根据趋势设置图标
if '上升' in str(trend) or '增长' in str(trend) or 'up' in str(trend).lower():
trend_icon = "📈"
elif '下降' in str(trend) or '下跌' in str(trend) or 'down' in str(trend).lower():
trend_icon = "📉"
else:
trend_icon = "📊"
return f"{trend_icon} **{trend}** (价格区间: {price_range}, 置信度: {confidence})"
# 构建Markdown文本
markdown = f"""### {symbol} 价格预测
**当前价格**: {current_price}
**24小时预测**: {format_prediction(prediction_24h)}
**7天预测**: {format_prediction(prediction_7d)}
**30天预测**: {format_prediction(prediction_30d)}
**关键影响因素**:
{key_factors_str}
**风险评估**: {risk_assessment}
*预测时间: {time.strftime('%Y-%m-%d %H:%M:%S')}*
"""
return markdown
except Exception as e:
print(f"格式化预测结果时出错: {e}")
traceback.print_exc()
return f"### {symbol} 格式化预测结果出错\n\n{str(e)}"
def format_strategy_result(self, symbol: str, strategy_result: Dict[str, Any]) -> str:
"""
格式化策略结果为Markdown格式
Args:
symbol: 交易对符号
strategy_result: 策略结果
Returns:
格式化后的Markdown文本
"""
try:
if not strategy_result or 'error' in strategy_result:
return f"### {symbol} 策略结果错误\n\n获取策略结果时出错: {strategy_result.get('error', '未知错误')}"
# 提取关键信息
risk_level = strategy_result.get('risk_level', '未知')
position = strategy_result.get('position', '未知')
entry_points = strategy_result.get('entry_points', [])
if isinstance(entry_points, list):
entry_points_str = ''.join([str(point) for point in entry_points])
else:
entry_points_str = str(entry_points)
exit_points = strategy_result.get('exit_points', [])
if isinstance(exit_points, list):
exit_points_str = ''.join([str(point) for point in exit_points])
else:
exit_points_str = str(exit_points)
stop_loss = strategy_result.get('stop_loss', '未知')
take_profit = strategy_result.get('take_profit', '未知')
time_frame = strategy_result.get('time_frame', '未知')
strategy_type = strategy_result.get('strategy_type', '未知')
reasoning = strategy_result.get('reasoning', '无理由')
# 根据建议仓位设置图标
if '' in position or 'buy' in str(position).lower():
position_icon = "🟢"
elif '' in position or 'sell' in str(position).lower():
position_icon = "🔴"
else:
position_icon = ""
# 根据风险等级设置图标
if 'low' in str(risk_level).lower() or '' in str(risk_level):
risk_icon = "🟢"
elif 'medium' in str(risk_level).lower() or '' in str(risk_level):
risk_icon = "🟡"
else:
risk_icon = "🔴"
# 构建Markdown文本
markdown = f"""### {symbol} 交易策略
**建议操作**: {position_icon} {position}
**风险等级**: {risk_icon} {risk_level}
**策略类型**: {strategy_type}
**时间框架**: {time_frame}
**入场点**: {entry_points_str}
**出场点**: {exit_points_str}
**止损位**: {stop_loss}
**止盈位**: {take_profit}
**策略理由**:
{reasoning}
*策略生成时间: {time.strftime('%Y-%m-%d %H:%M:%S')}*
"""
return markdown
except Exception as e:
print(f"格式化策略结果时出错: {e}")
traceback.print_exc()
return f"### {symbol} 格式化策略结果出错\n\n{str(e)}"
def send_analysis_report(self, symbol: str, analysis_data: Dict[str, Any]) -> Dict[str, Any]:
"""
发送完整分析报告(分析+预测+策略)
Args:
symbol: 交易对符号
analysis_data: 包含分析、预测和策略的数据
Returns:
接口返回结果
"""
try:
analysis_result = analysis_data.get('analysis', {})
prediction_result = analysis_data.get('prediction', {})
strategy_result = analysis_data.get('strategy', {})
# 获取市场趋势,用于设置标题图标
market_trend = ''
if analysis_result and 'market_trend' in analysis_result:
market_trend = analysis_result['market_trend']
if '' in str(market_trend) or 'bull' in str(market_trend).lower():
title_icon = "🟢"
elif '' in str(market_trend) or 'bear' in str(market_trend).lower():
title_icon = "🔴"
else:
title_icon = "🟡"
# 获取建议操作
position = '未知'
if strategy_result and 'position' in strategy_result:
position = strategy_result['position']
# 构建标题
title = f"{title_icon} {symbol} 加密货币分析报告 | 建议: {position}"
# 构建完整报告内容
markdown_text = f"# {symbol} 加密货币AI分析报告\n\n"
# 添加分析结果
markdown_text += "## 一、市场分析\n\n"
markdown_text += self.format_analysis_result(symbol, analysis_result)
markdown_text += "\n\n"
# 添加预测结果
markdown_text += "## 二、价格预测\n\n"
markdown_text += self.format_prediction_result(symbol, prediction_result)
markdown_text += "\n\n"
# 添加策略结果
markdown_text += "## 三、交易策略\n\n"
markdown_text += self.format_strategy_result(symbol, strategy_result)
# 发送Markdown消息
return self.send_markdown(title, markdown_text)
except Exception as e:
print(f"发送分析报告时出错: {e}")
traceback.print_exc()
error_msg = f"### {symbol} 分析报告生成错误\n\n{str(e)}"
return self.send_markdown(f"⚠️ {symbol} 分析报告错误", error_msg)