From 05db03e931f051ea6f80aeccd77a540a616a59c9 Mon Sep 17 00:00:00 2001 From: aaron <> Date: Sun, 27 Apr 2025 23:10:59 +0800 Subject: [PATCH] update --- .../__pycache__/crypto_agent.cpython-313.pyc | Bin 24368 -> 18277 bytes cryptoai/agents/crypto_agent.py | 390 ++++------------- .../__pycache__/deepseek_api.cpython-313.pyc | Bin 17149 -> 10097 bytes cryptoai/api/deepseek_api.py | 410 ++++-------------- cryptoai/config/config.yaml | 4 +- .../data_processor.cpython-313.pyc | Bin 11863 -> 11816 bytes cryptoai/models/data_processor.py | 6 +- cryptoai/utils/dingtalk_bot.py | 375 ++++++++++------ 8 files changed, 441 insertions(+), 744 deletions(-) diff --git a/cryptoai/agents/__pycache__/crypto_agent.cpython-313.pyc b/cryptoai/agents/__pycache__/crypto_agent.cpython-313.pyc index 6900ef4ab2e4d6f7c0324ae46210f95de4664408..6f5b755e815c5a7bf87ad69fc38637de7b1f5d0c 100644 GIT binary patch delta 6110 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 delta 10643 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 diff --git a/cryptoai/agents/crypto_agent.py b/cryptoai/agents/crypto_agent.py index 209918d..aab67de 100644 --- a/cryptoai/agents/crypto_agent.py +++ b/cryptoai/agents/crypto_agent.py @@ -2,7 +2,7 @@ import os import sys import pandas as pd import numpy as np -from typing import Dict, Any, List, Optional +from typing import Dict, Any, List, Optional, Tuple import datetime import time import json @@ -76,9 +76,6 @@ class CryptoAgent: # 支持的策略 self.strategies = self.agent_config['strategies'] - - # 分析结果缓存 - self.analysis_cache = {} def fetch_historical_data(self, symbol: str, days: int = 30) -> pd.DataFrame: """ @@ -136,151 +133,56 @@ class CryptoAgent: return processed_data - def analyze_market(self, symbol: str, data: pd.DataFrame = None) -> Dict[str, Any]: + def _format_market_data(self, market_data: Dict[str, Any]) -> str: """ - 分析市场 + 格式化市场数据为适合大模型的格式 Args: - symbol: 交易对符号,例如 'BTCUSDT' - data: 要分析的数据,如果为None,则获取最新数据 + market_data: 市场数据 Returns: - 市场分析结果 + 格式化的数据字符串 """ - print(f"分析{symbol}的市场情况...") - - if data is None: - # 尝试加载最新的处理后数据 - latest_data_file = self.data_processor.get_latest_data_file(symbol, data_type='processed') - - if latest_data_file: - data = self.data_processor.load_data(latest_data_file) - else: - # 如果没有找到处理后的数据,则获取新数据 - raw_data = self.fetch_historical_data(symbol, days=self.data_config['historical_days']) - data = self.process_data(symbol, raw_data) - - if data.empty: - print(f"没有可用的{symbol}数据进行分析") - return {} - - # 准备市场数据 - market_data = { - "symbol": symbol, - "current_price": float(data['close'].iloc[-1]), - "price_change_24h": float(data['close'].iloc[-1] - data['close'].iloc[-24]), - "price_change_percentage_24h": float((data['close'].iloc[-1] - data['close'].iloc[-24]) / data['close'].iloc[-24] * 100), - "historical_prices": data['close'].tail(100).tolist(), - "volumes": data['volume'].tail(100).tolist(), - "technical_indicators": { - "rsi": float(data['RSI'].iloc[-1]), - "macd": float(data['MACD'].iloc[-1]), - "macd_signal": float(data['MACD_Signal'].iloc[-1]), - "bollinger_upper": float(data['Bollinger_Upper'].iloc[-1]), - "bollinger_lower": float(data['Bollinger_Lower'].iloc[-1]), - "ma5": float(data['MA5'].iloc[-1]), - "ma10": float(data['MA10'].iloc[-1]), - "ma20": float(data['MA20'].iloc[-1]), - "ma50": float(data['MA50'].iloc[-1]), - "atr": float(data['ATR'].iloc[-1]) - } - } - - # 获取当前市场订单簿 - order_book = self.binance_api.get_order_book(symbol, limit=10) - - if order_book: - market_data["order_book"] = { - "bids": order_book.get('bids', [])[:5], - "asks": order_book.get('asks', [])[:5] - } - - # 使用DeepSeek进行市场分析 - analysis_result = self.deepseek_api.analyze_market_data(market_data) - - # 缓存分析结果 - self.analysis_cache[symbol] = analysis_result - - return analysis_result + # 这里可以根据实际情况调整格式化方式 + return json.dumps(market_data, indent=2) - def predict_price(self, symbol: str) -> Dict[str, Any]: + def _build_market_analysis_prompt(self, formatted_data: str) -> str: """ - 预测价格 + 构建市场分析提示词 Args: - symbol: 交易对符号,例如 'BTCUSDT' + formatted_data: 格式化的市场数据 Returns: - 价格预测结果 + 提示词 """ - print(f"预测{symbol}的价格趋势...") - - # 尝试加载最新的处理后数据 - latest_data_file = self.data_processor.get_latest_data_file(symbol, data_type='processed') - - if not latest_data_file: - # 如果没有找到处理后的数据,则获取新数据 - raw_data = self.fetch_historical_data(symbol, days=self.data_config['historical_days']) - data = self.process_data(symbol, raw_data) - else: - data = self.data_processor.load_data(latest_data_file) - - if data.empty: - print(f"没有可用的{symbol}数据进行预测") - return {} - - # 准备历史数据 - historical_data = { - "symbol": symbol, - "current_price": float(data['close'].iloc[-1]), - "price_history": data[['open', 'high', 'low', 'close']].tail(90).to_dict(orient='records'), - "volume_history": data['volume'].tail(90).tolist(), - "technical_indicators": { - "rsi_history": data['RSI'].tail(30).tolist(), - "macd_history": data['MACD'].tail(30).tolist(), - "ma5_history": data['MA5'].tail(30).tolist(), - "ma20_history": data['MA20'].tail(30).tolist(), - "ma50_history": data['MA50'].tail(30).tolist() - } - } - - # 使用DeepSeek进行价格预测 - prediction_result = self.deepseek_api.predict_price_trend(symbol, historical_data) - - return prediction_result - - def generate_strategy(self, symbol: str, analysis_result: Dict[str, Any] = None) -> Dict[str, Any]: - """ - 生成交易策略 - - Args: - symbol: 交易对符号,例如 'BTCUSDT' - analysis_result: 分析结果,如果为None,则使用缓存或重新分析 - - Returns: - 交易策略 - """ - print(f"为{symbol}生成交易策略...") - - if analysis_result is None: - # 使用缓存的分析结果或重新分析 - if symbol in self.analysis_cache: - analysis_result = self.analysis_cache[symbol] - else: - analysis_result = self.analyze_market(symbol) - - if not analysis_result: - print(f"没有可用的{symbol}分析结果来生成策略") - return {} - - # 使用DeepSeek生成交易策略 - strategy = self.deepseek_api.generate_trading_strategy( - symbol=symbol, - analysis_result=analysis_result, - risk_level=self.risk_level - ) - - return strategy + return f"""请对以下加密货币市场K线数据进行深入分析,并给出交易建议。请使用中文回复。 + +数据: +{formatted_data} + +请严格按照以下步骤分析: +1. 分析主要技术指标(包括RSI、MACD、布林带、均线等),判断当前市场趋势 +2. 基于K线数据和斐波那契回调水平,确定关键支撑位和压力位 +3. 根据技术分析给出清晰的操作建议 +4. 评估当前操作建议的紧迫性 + +请以JSON格式回复,仅包含以下字段: +- market_trend: 市场趋势 (牛市, 熊市, 震荡) +- technical_analysis: 技术指标详细分析 (重点分析RSI、MACD、布林带、均线交叉等情况) +- support_levels: 基于斐波那契回调的支撑位列表(标明各个支撑位对应的斐波那契水平,例如0.382、0.5、0.618等) +- resistance_levels: 基于斐波那契回调的阻力位列表(同样标明对应水平) +- volume_analysis: 交易量分析,重点关注量价关系 +- recommendation: 操作建议 (买入、卖出或等待) +- entry_points: 推荐入场点位 +- exit_points: 推荐出场点位 +- stop_loss: 建议止损位 +- take_profit: 建议止盈位 +- urgency_level: 操作紧迫性评级 (1-5,1为最低紧迫性,5为最高紧迫性) +- urgency_reason: 紧迫性评级的原因说明 +- summary: 分析总结(不超过50字) + +请确保回复为有效的JSON格式,分析要精准专业。""" def analyze_all_symbols(self) -> Dict[str, Dict[str, Any]]: """ @@ -300,20 +202,48 @@ class CryptoAgent: if not raw_data.empty: processed_data = self.process_data(symbol, raw_data) - # 分析市场 - analysis_result = self.analyze_market(symbol, processed_data) + # 准备市场数据 + market_data = { + "symbol": symbol, + "current_price": float(processed_data['close'].iloc[-1]), + "price_change_24h": float(processed_data['close'].iloc[-1] - processed_data['close'].iloc[-24]), + "price_change_percentage_24h": float((processed_data['close'].iloc[-1] - processed_data['close'].iloc[-24]) / processed_data['close'].iloc[-24] * 100), + "historical_prices": processed_data['close'].tail(100).tolist(), + "volumes": processed_data['volume'].tail(100).tolist(), + "technical_indicators": { + "rsi": float(processed_data['RSI'].iloc[-1]), + "macd": float(processed_data['MACD'].iloc[-1]), + "macd_signal": float(processed_data['MACD_Signal'].iloc[-1]), + "bollinger_upper": float(processed_data['Bollinger_Upper'].iloc[-1]), + "bollinger_lower": float(processed_data['Bollinger_Lower'].iloc[-1]), + "ma5": float(processed_data['MA5'].iloc[-1]), + "ma10": float(processed_data['MA10'].iloc[-1]), + "ma20": float(processed_data['MA20'].iloc[-1]), + "ma50": float(processed_data['MA50'].iloc[-1]), + "atr": float(processed_data['ATR'].iloc[-1]) + }, + "klines": processed_data[['open', 'high', 'low', 'close', 'volume']].tail(30).to_dict('records') + } - # 预测价格 - prediction_result = self.predict_price(symbol) + # 将市场数据格式化为适合大模型的格式 + formatted_data = self._format_market_data(market_data) - # 生成策略 - strategy = self.generate_strategy(symbol, analysis_result) + # 构建提示词 + prompt = self._build_market_analysis_prompt(formatted_data) + + # 调用API获取分析和交易建议 + response, usage = self.deepseek_api.call_model(prompt, task_type="交易分析", symbol=symbol) + + # 解析响应 + analysis_result = self.deepseek_api.extract_json_from_response(response) + + # 添加token使用信息 + if usage: + analysis_result["_token_usage"] = usage # 整合结果 results[symbol] = { "analysis": analysis_result, - "prediction": prediction_result, - "strategy": strategy, "timestamp": datetime.now().isoformat() } @@ -335,137 +265,35 @@ class CryptoAgent: return results - def execute_strategy(self, symbol: str, strategy: Dict[str, Any]) -> Dict[str, Any]: + def send_notifications(self, symbol: str, analysis_data: Dict[str, Any]) -> bool: """ - 执行交易策略 - - Args: - symbol: 交易对符号,例如 'BTCUSDT' - strategy: 交易策略 - - Returns: - 执行结果 - """ - if not strategy or 'position' not in strategy: - print(f"无法执行{symbol}的策略,策略数据不完整") - return {"status": "error", "message": "策略数据不完整"} - - print(f"执行{symbol}的交易策略...") - - # 获取当前价格 - current_price_info = self.binance_api.get_ticker(symbol) - - if not current_price_info: - print(f"无法获取{symbol}的当前价格") - return {"status": "error", "message": "无法获取当前价格"} - - current_price = float(current_price_info.get('price', 0)) - - # 根据策略决定操作 - position = strategy.get('position', '').upper() - - result = { - "symbol": symbol, - "strategy": strategy, - "current_price": current_price, - "timestamp": datetime.now().isoformat() - } - - # 简单策略执行逻辑 - if position == 'BUY' or '买' in position: - # 示例:下单买入 - # 在实际应用中,这里应该有更复杂的仓位管理和风险管理逻辑 - quantity = 0.01 # 示例数量,实际应用中应该基于资金和风险计算 - - order_result = self.binance_api.place_order( - symbol=symbol, - side='BUY', - type='MARKET', - quantity=quantity - ) - - result["action"] = "BUY" - result["order_result"] = order_result - - # 如果钉钉机器人已启用,发送交易通知 - if self.dingtalk_bot: - self.send_trade_notification(symbol, "买入", quantity, current_price, strategy) - - elif position == 'SELL' or '卖' in position: - # 示例:下单卖出 - quantity = 0.01 # 示例数量 - - order_result = self.binance_api.place_order( - symbol=symbol, - side='SELL', - type='MARKET', - quantity=quantity - ) - - result["action"] = "SELL" - result["order_result"] = order_result - - # 如果钉钉机器人已启用,发送交易通知 - if self.dingtalk_bot: - self.send_trade_notification(symbol, "卖出", quantity, current_price, strategy) - - else: - # 持有或其他策略 - result["action"] = "HOLD" - result["message"] = "根据策略保持当前仓位" - - print(f"执行{symbol}策略完成:{result['action']}") - return result - - def send_trade_notification(self, symbol: str, action: str, quantity: float, price: float, strategy: Dict[str, Any]) -> None: - """ - 发送交易通知到钉钉 + 发送分析结果通知 Args: symbol: 交易对符号 - action: 交易操作(买入或卖出) - quantity: 交易数量 - price: 交易价格 - strategy: 交易策略 + analysis_data: 分析数据 + + Returns: + 发送是否成功 """ if not self.dingtalk_bot: - return + print(f"钉钉通知未启用,跳过发送 {symbol} 的分析结果") + return False try: - # 设置图标 - if action == "买入": - icon = "🟢" + # 使用已初始化的钉钉机器人实例发送完整分析报告 + response = self.dingtalk_bot.send_analysis_report(symbol, analysis_data) + + if response.get('errcode') == 0: + print(f"成功发送 {symbol} 分析结果到钉钉") + return True else: - icon = "🔴" - - # 获取策略理由 - reasoning = strategy.get('reasoning', '无理由') - - # 构建通知内容 - title = f"{icon} {symbol} {action}交易执行通知" - text = f"""### {symbol} {action}交易已执行 - -**交易详情**: -- 操作: {icon} **{action}** -- 数量: {quantity} -- 价格: {price} -- 总额: {quantity * price} {self.quote_currency} - -**交易理由**: -{reasoning} - -*交易时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}* - """ - - # 发送通知 - at_mobiles = self.dingtalk_config.get('at_mobiles', []) - at_all = self.dingtalk_config.get('at_all', False) - self.dingtalk_bot.send_markdown(title, text, at_mobiles, at_all) - - print(f"{symbol} {action}交易通知已发送") - + print(f"发送 {symbol} 分析结果到钉钉失败: {response}") + return False + except Exception as e: - print(f"发送交易通知时出错: {e}") + print(f"发送钉钉通知时出错: {e}") + return False def run_analysis_cycle(self) -> Dict[str, Any]: """ @@ -562,34 +390,4 @@ class CryptoAgent: import traceback traceback.print_exc() # 发生错误时也尝试导出token使用情况 - self._export_token_usage() - - def send_notifications(self, symbol: str, analysis_data: Dict[str, Any]) -> bool: - """ - 发送分析结果通知 - - Args: - symbol: 交易对符号 - analysis_data: 分析数据 - - Returns: - 发送是否成功 - """ - if not self.dingtalk_bot: - print(f"钉钉通知未启用,跳过发送 {symbol} 的分析结果") - return False - - try: - # 使用已初始化的钉钉机器人实例发送完整分析报告 - response = self.dingtalk_bot.send_analysis_report(symbol, analysis_data) - - if response.get('errcode') == 0: - print(f"成功发送 {symbol} 分析结果到钉钉") - return True - else: - print(f"发送 {symbol} 分析结果到钉钉失败: {response}") - return False - - except Exception as e: - print(f"发送钉钉通知时出错: {e}") - return False \ No newline at end of file + self._export_token_usage() \ No newline at end of file diff --git a/cryptoai/api/__pycache__/deepseek_api.cpython-313.pyc b/cryptoai/api/__pycache__/deepseek_api.cpython-313.pyc index dcf42c5f12202da87988fae19b25f4b655b01c98..ea26e900b50a2186f40962b1d3d350023581f4f3 100644 GIT binary patch delta 2662 zcma)7eQZrf5ihxJG|tdHoB-p?G=9b~Zq)gmKUO)$+cEikRaMr0c{A^Wg-81!LlgwsRB zwciy>#DN^kacszWV66jeUb7Vvx~L4RS`-IyxfxKh0M!==La7th|94d}|;`a#u@!`VzuQSI^(SrIewW!0=C zUo5v#(P%U{T3qX~amcYi1PRhqb+SgcJft3lrrTF_7w9d-7V@!1(iZBBFOP)DnbIp-eOgtSU`^ zR62cT@#_522Pd^Pja8`?T7l2(!s5cERi7_zpD14YUg_e@qq+IPtRxnv&p*2J8wm7x z;oYU1SBq1(wJ57(j0PVqEEM0qvUqC&m<+qY_0jyPrJIG~opa<K}ay;q#S2D?kAt{102T>3RB9-n`F;dE(czBF}R+m%Tijw{(QQIey< z(##Z`e(~(3()1b4RytQ8p@@h4q$$7-lD{CnuUbYDj6|VZ~!aubn-B9ZuKT!rVG0PWD@|~xi)YEb@hvf6`UAR;*^E) z6g&s3g{p098}YyWzQd5Qtv@$yEQAW42X$R!<2oA-{KjgPkF+ zs>1BuDyyNPaw2x(O?_TTZRifOlrtmQWLg@5}j(2Ta4XHczj*0ql|RC~Vbw5t;XECGh@~IE>m23=wKIg>W|&>v9&S}haLH#%j?06>9OB-j;wblBDth@Hyr%8o zpU}0Js5Zdwrs5TTkcz!LT2>MD8Q}L(>mhC*)pDG`|3fRPJj6BVV}-~ZKZoW_w|dG9 zsJ~6#?|iTq-S56D{hjLN9@q_VNbA literal 17149 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 diff --git a/cryptoai/api/deepseek_api.py b/cryptoai/api/deepseek_api.py index ea5f75a..729211f 100644 --- a/cryptoai/api/deepseek_api.py +++ b/cryptoai/api/deepseek_api.py @@ -17,7 +17,7 @@ logging.basicConfig( ) class DeepSeekAPI: - """DeepSeek API交互类,用于进行市场分析和预测""" + """DeepSeek API交互类,用于进行大语言模型调用""" def __init__(self, api_key: str, model: str = "deepseek-moe-16b-chat"): """ @@ -46,89 +46,112 @@ class DeepSeekAPI: # 创建日志记录器 self.logger = logging.getLogger("DeepSeekAPI") - def analyze_market_data(self, market_data: Dict[str, Any]) -> Dict[str, Any]: + def call_model(self, prompt: str, system_prompt: str = None, task_type: str = "未知任务", symbol: str = "未知", temperature: float = 0.2, max_tokens: int = 2000) -> Tuple[Dict[str, Any], Dict[str, Any]]: """ - 分析市场数据 + 调用DeepSeek大语言模型 Args: - market_data: 包含市场数据的字典,例如价格、交易量等 + prompt: 用户提示词 + system_prompt: 系统提示词,如果为None则使用默认值 + task_type: 任务类型,用于记录 + symbol: 交易对符号,用于记录 + temperature: 采样温度,控制输出随机性 + max_tokens: 最大生成token数 Returns: - 分析结果 + (API响应, token使用信息) """ - # 将市场数据格式化为适合大模型的格式 - formatted_data = self._format_market_data(market_data) + if system_prompt is None: + system_prompt = "你是一个专业的加密货币分析助手,擅长分析市场趋势、预测价格走向和提供交易建议。请始终使用中文回复,并确保输出格式规范的JSON。" + + usage_info = {} - # 构建提示词 - prompt = self._build_market_analysis_prompt(formatted_data) + try: + endpoint = f"{self.base_url}/chat/completions" + + payload = { + "model": self.model, + "messages": [ + {"role": "system", "content": system_prompt}, + {"role": "user", "content": prompt} + ], + "temperature": temperature, + "max_tokens": max_tokens + } + + start_time = time.time() + response = requests.post(endpoint, headers=self.headers, json=payload) + response.raise_for_status() + response_data = response.json() + end_time = time.time() + + # 记录token使用情况 + if 'usage' in response_data: + prompt_tokens = response_data['usage'].get('prompt_tokens', 0) + completion_tokens = response_data['usage'].get('completion_tokens', 0) + total_tokens = response_data['usage'].get('total_tokens', 0) + + usage_info = { + "prompt_tokens": prompt_tokens, + "completion_tokens": completion_tokens, + "total_tokens": total_tokens, + "task_type": task_type, + "symbol": symbol, + "model": self.model, + "timestamp": datetime.datetime.now().isoformat(), + "duration_seconds": round(end_time - start_time, 2) + } + + # 更新总计 + self.token_usage["total_prompt_tokens"] += prompt_tokens + self.token_usage["total_completion_tokens"] += completion_tokens + self.token_usage["total_tokens"] += total_tokens + self.token_usage["calls"].append(usage_info) + + # 记录到日志 + self.logger.info( + f"DeepSeek API调用 - 任务: {task_type}, 符号: {symbol}, " + f"输入tokens: {prompt_tokens}, 输出tokens: {completion_tokens}, " + f"总tokens: {total_tokens}, 耗时: {round(end_time - start_time, 2)}秒" + ) + + return response_data, usage_info - # 调用API获取分析 - response, usage = self._call_api(prompt, task_type="市场分析", symbol=market_data.get("symbol", "未知")) - - # 解析响应 - result = self._parse_analysis_response(response) - - # 添加token使用信息 - if usage: - result["_token_usage"] = usage - - return result + except Exception as e: + error_msg = f"调用DeepSeek API时出错: {e}" + self.logger.error(error_msg) + return {}, usage_info - def predict_price_trend(self, symbol: str, historical_data: Dict[str, Any]) -> Dict[str, Any]: + def extract_json_from_response(self, response: Dict[str, Any]) -> Dict[str, Any]: """ - 预测价格趋势 + 从响应中提取JSON数据 Args: - symbol: 交易对符号,例如 'BTCUSDT' - historical_data: 历史数据 + response: API响应 Returns: - 预测结果 + 提取的JSON数据 """ - # 格式化历史数据 - formatted_data = self._format_historical_data(symbol, historical_data) - - # 构建提示词 - prompt = self._build_price_prediction_prompt(symbol, formatted_data) - - # 调用API获取预测 - response, usage = self._call_api(prompt, task_type="价格预测", symbol=symbol) - - # 解析响应 - result = self._parse_prediction_response(response) - - # 添加token使用信息 - if usage: - result["_token_usage"] = usage + try: + if 'choices' in response and len(response['choices']) > 0: + content = response['choices'][0]['message']['content'] + + # 尝试从响应中提取JSON + start_idx = content.find('{') + end_idx = content.rfind('}') + 1 + + if start_idx != -1 and end_idx != -1: + json_str = content[start_idx:end_idx] + return json.loads(json_str) + + return {"error": "无法从响应中提取JSON", "raw_content": content} - return result - - def generate_trading_strategy(self, symbol: str, analysis_result: Dict[str, Any], risk_level: str) -> Dict[str, Any]: - """ - 生成交易策略 + return {"error": "API响应格式不正确", "raw_response": response} - Args: - symbol: 交易对符号,例如 'BTCUSDT' - analysis_result: 分析结果 - risk_level: 风险等级,'low', 'medium', 'high' - - Returns: - 交易策略 - """ - # 构建提示词 - prompt = self._build_trading_strategy_prompt(symbol, analysis_result, risk_level) - - # 调用API获取策略 - response, usage = self._call_api(prompt, task_type="交易策略", symbol=symbol) - - # 解析响应 - result = self._parse_strategy_response(response) - - # 添加token使用信息 - if usage: - result["_token_usage"] = usage - - return result + except Exception as e: + error_msg = f"解析响应时出错: {e}" + self.logger.error(error_msg) + return {"error": str(e), "raw_response": response} def get_token_usage_stats(self) -> Dict[str, Any]: """ @@ -209,255 +232,4 @@ class DeepSeekAPI: except Exception as e: error_msg = f"导出Token使用数据时出错: {e}" self.logger.error(error_msg) - return "" - - def _call_api(self, prompt: str, task_type: str = "未知任务", symbol: str = "未知") -> Tuple[Dict[str, Any], Dict[str, Any]]: - """ - 调用DeepSeek API - - Args: - prompt: 提示词 - task_type: 任务类型 - symbol: 交易对符号 - - Returns: - (API响应, token使用信息) - """ - usage_info = {} - - try: - endpoint = f"{self.base_url}/chat/completions" - - payload = { - "model": self.model, - "messages": [ - {"role": "system", "content": "你是一个专业的加密货币分析助手,擅长分析市场趋势、预测价格走向和提供交易建议。请始终使用中文回复,并确保输出格式规范的JSON。"}, - {"role": "user", "content": prompt} - ], - "temperature": 0.2, # 低温度使输出更加确定性 - "max_tokens": 2000 - } - - start_time = time.time() - response = requests.post(endpoint, headers=self.headers, json=payload) - response.raise_for_status() - response_data = response.json() - end_time = time.time() - - # 记录token使用情况 - if 'usage' in response_data: - prompt_tokens = response_data['usage'].get('prompt_tokens', 0) - completion_tokens = response_data['usage'].get('completion_tokens', 0) - total_tokens = response_data['usage'].get('total_tokens', 0) - - usage_info = { - "prompt_tokens": prompt_tokens, - "completion_tokens": completion_tokens, - "total_tokens": total_tokens, - "task_type": task_type, - "symbol": symbol, - "model": self.model, - "timestamp": datetime.datetime.now().isoformat(), - "duration_seconds": round(end_time - start_time, 2) - } - - # 更新总计 - self.token_usage["total_prompt_tokens"] += prompt_tokens - self.token_usage["total_completion_tokens"] += completion_tokens - self.token_usage["total_tokens"] += total_tokens - self.token_usage["calls"].append(usage_info) - - # 记录到日志 - self.logger.info( - f"DeepSeek API调用 - 任务: {task_type}, 符号: {symbol}, " - f"输入tokens: {prompt_tokens}, 输出tokens: {completion_tokens}, " - f"总tokens: {total_tokens}, 耗时: {round(end_time - start_time, 2)}秒" - ) - - return response_data, usage_info - - except Exception as e: - error_msg = f"调用DeepSeek API时出错: {e}" - self.logger.error(error_msg) - return {}, usage_info - - def _format_market_data(self, market_data: Dict[str, Any]) -> str: - """ - 格式化市场数据为适合大模型的格式 - - Args: - market_data: 市场数据 - - Returns: - 格式化的数据字符串 - """ - # 这里可以根据实际情况调整格式化方式 - return json.dumps(market_data, indent=2) - - def _format_historical_data(self, symbol: str, historical_data: Dict[str, Any]) -> str: - """ - 格式化历史数据为适合大模型的格式 - - Args: - symbol: 交易对符号 - historical_data: 历史数据 - - Returns: - 格式化的数据字符串 - """ - # 可以根据实际情况调整格式化方式 - return json.dumps(historical_data, indent=2) - - def _build_market_analysis_prompt(self, formatted_data: str) -> str: - """ - 构建市场分析提示词 - - Args: - formatted_data: 格式化的市场数据 - - Returns: - 提示词 - """ - return f"""请分析以下加密货币市场数据,并提供详细的市场分析。请使用中文回复。 - -数据: -{formatted_data} - -请包括以下内容: -1. 市场总体趋势 -2. 主要支撑位和阻力位 -3. 交易量分析 -4. 市场情绪评估 -5. 关键技术指标解读(如RSI、MACD等) - -请以JSON格式回复,包含以下字段: -- market_trend: 市场趋势 (牛市, 熊市, 震荡) -- support_levels: 支撑位列表 -- resistance_levels: 阻力位列表 -- volume_analysis: 交易量分析 -- market_sentiment: 市场情绪 -- technical_indicators: 技术指标分析 -- summary: 总结 - -请确保回复为有效的JSON格式,并使用中文进行分析。""" - - def _build_price_prediction_prompt(self, symbol: str, formatted_data: str) -> str: - """ - 构建价格预测提示词 - - Args: - symbol: 交易对符号 - formatted_data: 格式化的历史数据 - - Returns: - 提示词 - """ - return f"""请基于以下{symbol}的历史数据,预测未来24小时、7天和30天的价格走势。请使用中文回复。 - -历史数据: -{formatted_data} - -请考虑市场趋势、技术指标、历史模式和当前市场情况,提供详细的预测分析。 - -请以JSON格式回复,包含以下字段: -- symbol: 交易对符号 -- current_price: 当前价格 -- prediction_24h: 24小时预测 (包含 price_range价格区间, trend趋势, confidence置信度) -- prediction_7d: 7天预测 (包含 price_range价格区间, trend趋势, confidence置信度) -- prediction_30d: 30天预测 (包含 price_range价格区间, trend趋势, confidence置信度) -- key_factors: 影响预测的关键因素 -- risk_assessment: 风险评估 - -请确保回复为有效的JSON格式,并使用中文进行分析。""" - - def _build_trading_strategy_prompt(self, symbol: str, analysis_result: Dict[str, Any], risk_level: str) -> str: - """ - 构建交易策略提示词 - - Args: - symbol: 交易对符号 - analysis_result: 分析结果 - risk_level: 风险等级 - - Returns: - 提示词 - """ - analysis_json = json.dumps(analysis_result, indent=2) - - return f"""请基于以下{symbol}的市场分析结果,生成一个风险等级为{risk_level}的交易策略。请使用中文回复。 - -分析结果: -{analysis_json} - -请考虑市场趋势、技术指标、风险等级和当前市场情况,提供详细的交易策略。 - -请以JSON格式回复,包含以下字段: -- symbol: 交易对符号 -- risk_level: 风险等级 (low低风险, medium中风险, high高风险) -- position: 建议仓位 (买入、卖出、持有) -- entry_points: 入场点列表 -- exit_points: 出场点列表 -- stop_loss: 止损位 -- take_profit: 止盈位 -- time_frame: 建议的交易时间框架 -- strategy_type: 策略类型 (例如:趋势跟踪、反转、突破等) -- reasoning: 策略推理过程 - -请确保回复为有效的JSON格式,并使用中文进行分析。""" - - def _parse_analysis_response(self, response: Dict[str, Any]) -> Dict[str, Any]: - """ - 解析分析响应 - - Args: - response: API响应 - - Returns: - 解析后的分析结果 - """ - try: - if 'choices' in response and len(response['choices']) > 0: - content = response['choices'][0]['message']['content'] - - # 尝试从响应中提取JSON - start_idx = content.find('{') - end_idx = content.rfind('}') + 1 - - if start_idx != -1 and end_idx != -1: - json_str = content[start_idx:end_idx] - return json.loads(json_str) - - return {"error": "无法从响应中提取JSON", "raw_content": content} - - return {"error": "API响应格式不正确", "raw_response": response} - - except Exception as e: - error_msg = f"解析分析响应时出错: {e}" - self.logger.error(error_msg) - return {"error": str(e), "raw_response": response} - - def _parse_prediction_response(self, response: Dict[str, Any]) -> Dict[str, Any]: - """ - 解析预测响应 - - Args: - response: API响应 - - Returns: - 解析后的预测结果 - """ - # 与_parse_analysis_response相同的实现 - return self._parse_analysis_response(response) - - def _parse_strategy_response(self, response: Dict[str, Any]) -> Dict[str, Any]: - """ - 解析策略响应 - - Args: - response: API响应 - - Returns: - 解析后的策略结果 - """ - # 与_parse_analysis_response相同的实现 - return self._parse_analysis_response(response) \ No newline at end of file + return "" \ No newline at end of file diff --git a/cryptoai/config/config.yaml b/cryptoai/config/config.yaml index 278a98b..722c953 100644 --- a/cryptoai/config/config.yaml +++ b/cryptoai/config/config.yaml @@ -12,11 +12,11 @@ deepseek: # 加密货币设置 crypto: base_currencies: - # - "BTC" + - "BTC" # - "ETH" # - "BNB" # - "SOL" - - "SUI" + # - "SUI" quote_currency: "USDT" time_interval: "4h" # 可选: 1m, 5m, 15m, 30m, 1h, 4h, 1d diff --git a/cryptoai/models/__pycache__/data_processor.cpython-313.pyc b/cryptoai/models/__pycache__/data_processor.cpython-313.pyc index af938175088c0b35fedc0dbfade329481a4127d4..6c33b705f8b3b60a056e341c869cdce0d0842ee0 100644 GIT binary patch delta 725 zcmY+CUr19?9LGKP?%rLmyVKNk4maoA)LS}4g8o4ChcJ2zx88)y(Ov82+~Vx68f9vK zObK=I!}39jh)7p2ae|;o@TK=bkSvH^g6JWrUV5wh+luHseE6R4?|07kci_AmSs&4U zXqsB%tfKBc^ZJ=4OX^!^w^DOT7$$JI)(?9nt6PYR`$-5rH}?L&;(x0!+tmUer3NCw zH|ZhSfEBq9KF9%C8XdP%DG=O?gh9bQa)jjiSNeOK$p5=c#`0gGQyb>%ncJUL+ zCzo1HjnwF2IG|-n7>e3fDCFd`P6s+EyXZwLTNaNbh7&A+mc}Ab@E#{UuFivPklL)Bi{$mmnD&j9kIqX@m!{12Kb`MO;O6z{_B;;X2B8#0|t8{~R13 zWDeRwrPh;{(5N<}dd$D*cgS>Qu-aqPrbCQQ znrs)=dJ*^!n22y8EC*%LO52Q~a;KA&F`8!=uy_-38*vx0hL92Kh^G$9I}IaiQ`;Id zsBJTAG-sPx!{EPm-y>RO2q~SLJeOw-iv3Z~3?6Zv&1TYU3EuZd$txf+AK3zb?BH)r CRJiK^ delta 781 zcmYk2O-K}B7{~XW+4*vJ)ZF|?+|hJ5n{>;BkjOp}yLE8YlQ4|#m>avZ@$Rf-NtPA5 zMJ@7FNQb^9bAyOENmK+81Rb(VGIZ!%1VNWBVehkB&>VjJpa1jl{GWH0M?Q_HKUKBD z$G+c>)QKO@R8go{XVneg5H~>JUPB}F2uW3lb8&Gm*MhDDhXS>Mf3 zb3L%6hhNK9=cx(A07TE?hYKCluS@m_anFY`m2Az0* z^HehH@rMTo=r-mI(g^x0ZHKYSqhtpZD_2Md3|DoLRd=qc$OV~>=6Eu-%!DzPozyuR zDvx|@F-TZLy?_(`RK`r`{NFCx;2vw;!izJg&p|rcB$n@iLi9*r8r@PXxSyjg-+7H0 zgY-Vy9O5AZdu}PL0gdu7sulOSev{0U4paI}$LyzO+M+S+bs!`JkMJW>3?84f9hyTW z*$I= 4: + urgency_icon = "🔴" + elif int(urgency_level) >= 2: + urgency_icon = "🟡" + else: + urgency_icon = "🟢" + + # 总结 summary = analysis_result.get('summary', '无摘要') - if isinstance(summary, str) and (summary.startswith('{') or summary.startswith('{')): - try: - # 尝试解析JSON字符串 - summary_json = json.loads(summary) - formatted_summary = "" - - # 添加概述 - if 'overview' in summary_json: - formatted_summary += f"**总体概述**:{summary_json['overview']}\n\n" - - # 添加关键点 - if 'key_points' in summary_json and isinstance(summary_json['key_points'], list): - formatted_summary += "**关键点**:\n" - for point in summary_json['key_points']: - formatted_summary += f"- {point}\n" - formatted_summary += "\n" - - # 添加交易建议 - if 'trading_suggestion' in summary_json: - formatted_summary += f"**交易建议**:{summary_json['trading_suggestion']}" - - summary = formatted_summary - except Exception as e: - # 如果解析失败,保留原始内容 - print(f"解析summary JSON时出错: {e}") - elif isinstance(summary, (dict, list)): - summary = self._format_complex_content(summary) - # 根据市场趋势设置颜色标志 + # 根据市场趋势设置图标 if '牛' in str(market_trend) or 'bull' in str(market_trend).lower(): trend_icon = "🟢" elif '熊' in str(market_trend) or 'bear' in str(market_trend).lower(): @@ -234,18 +239,33 @@ class DingTalkBot: **市场趋势**: {market_trend} -**支撑位**: {support_levels_str} - -**阻力位**: {resistance_levels_str} +**技术指标分析**: +{technical_analysis} **交易量分析**: {volume_analysis} -**市场情绪**: -{market_sentiment} +**支撑位(斐波那契)**: +{support_levels_str} -**总结**: -{summary} +**阻力位(斐波那契)**: +{resistance_levels_str} + +**操作建议**: {recommendation} + +**入场点位**: {entry_points_str} + +**出场点位**: {exit_points_str} + +**止损位**: {stop_loss} + +**止盈位**: {take_profit} + +**操作紧迫性**: {urgency_icon} {urgency_level}/5 + +**紧迫性原因**: {urgency_reason} + +**总结**: {summary} *分析时间: {time.strftime('%Y-%m-%d %H:%M:%S')}* """ @@ -273,57 +293,47 @@ class DingTalkBot: # 提取关键信息 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', {}) - # 处理关键影响因素 + # 24小时预测 + prediction_24h = prediction_result.get('prediction_24h', {}) + price_range_24h = prediction_24h.get('price_range', '未知') + trend_24h = prediction_24h.get('trend', '未知') + + # 7天预测 + prediction_7d = prediction_result.get('prediction_7d', {}) + price_range_7d = prediction_7d.get('price_range', '未知') + trend_7d = prediction_7d.get('trend', '未知') + + # 关键因素 key_factors = prediction_result.get('key_factors', []) if isinstance(key_factors, list): - key_factors_str = '\n'.join([f"- {factor}" for factor in key_factors]) + key_factors_text = '\n'.join([f"- {factor}" for factor in key_factors]) else: - key_factors_str = self._format_complex_content(key_factors) - - # 处理风险评估 - risk_assessment = prediction_result.get('risk_assessment', '未知') - if isinstance(risk_assessment, (dict, list)): - risk_assessment = self._format_complex_content(risk_assessment) + key_factors_text = str(key_factors) - # 格式化预测数据 - 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})" + # 根据24小时趋势设置图标 + if '上涨' in str(trend_24h) or 'up' in str(trend_24h).lower(): + trend_icon = "🟢" + elif '下跌' in str(trend_24h) or 'down' in str(trend_24h).lower(): + trend_icon = "🔴" + else: + trend_icon = "🟡" # 构建Markdown文本 - markdown = f"""### {symbol} 价格预测 + markdown = f"""### {trend_icon} {symbol} 价格预测 **当前价格**: {current_price} -**24小时预测**: {format_prediction(prediction_24h)} +**24小时预测**: +- 价格区间: {price_range_24h} +- 趋势: {trend_24h} -**7天预测**: {format_prediction(prediction_7d)} - -**30天预测**: {format_prediction(prediction_30d)} +**7天预测**: +- 价格区间: {price_range_7d} +- 趋势: {trend_7d} **关键影响因素**: -{key_factors_str} - -**风险评估**: -{risk_assessment} +{key_factors_text} *预测时间: {time.strftime('%Y-%m-%d %H:%M:%S')}* """ @@ -350,7 +360,6 @@ class DingTalkBot: 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', []) @@ -364,11 +373,13 @@ class DingTalkBot: 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', '未知') + + # 紧迫性评级 + urgency_level = strategy_result.get('urgency_level', 0) + reasoning = strategy_result.get('reasoning', '无理由') # 根据建议仓位设置图标 @@ -379,33 +390,29 @@ class DingTalkBot: 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 = "🟡" + # 紧迫性等级图标 + if int(urgency_level) >= 4: + urgency_icon = "🔴" + elif int(urgency_level) >= 2: + urgency_icon = "🟡" else: - risk_icon = "🔴" + urgency_icon = "🟢" # 构建Markdown文本 markdown = f"""### {symbol} 交易策略 **建议操作**: {position_icon} {position} -**风险等级**: {risk_icon} {risk_level} +**入场点位**: {entry_points_str} -**策略类型**: {strategy_type} - -**时间框架**: {time_frame} - -**入场点**: {entry_points_str} - -**出场点**: {exit_points_str} +**出场点位**: {exit_points_str} **止损位**: {stop_loss} **止盈位**: {take_profit} +**操作紧迫性**: {urgency_icon} {urgency_level}/5 + **策略理由**: {reasoning} @@ -418,21 +425,157 @@ class DingTalkBot: 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]: + def format_integrated_report(self, symbol: str, analysis_result: Dict[str, Any]) -> str: """ - 发送完整分析报告(分析+预测+策略) + 格式化整合后的分析报告 Args: symbol: 交易对符号 - analysis_data: 包含分析、预测和策略的数据 + analysis_result: 分析结果 + + Returns: + 格式化后的文本 + """ + 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', '未知') + + # 支撑位和阻力位的格式化 + def format_fibonacci_levels(levels): + formatted_lines = [] + if isinstance(levels, list): + for level in levels: + if isinstance(level, dict) and 'level' in level and 'price' in level: + formatted_lines.append(f"- {level['level']} 位: {level['price']}") + else: + formatted_lines.append(f"- {level}") + elif isinstance(levels, dict): + for level, price in levels.items(): + if level.replace('.', '', 1).isdigit(): # 检查是否是数字形式的级别 + formatted_lines.append(f"- {level} 位: {price}") + else: + formatted_lines.append(f"- {level}: {price}") + else: + formatted_lines.append(str(levels)) + return '\n'.join(formatted_lines) + + support_levels = analysis_result.get('support_levels', []) + support_levels_str = format_fibonacci_levels(support_levels) + + resistance_levels = analysis_result.get('resistance_levels', []) + resistance_levels_str = format_fibonacci_levels(resistance_levels) + + # 技术指标分析 + technical_analysis = analysis_result.get('technical_analysis', '未知') + if isinstance(technical_analysis, (dict, list)): + technical_analysis = self._format_complex_content(technical_analysis) + + # 交易量分析 + volume_analysis = analysis_result.get('volume_analysis', '未知') + if isinstance(volume_analysis, (dict, list)): + volume_analysis = self._format_complex_content(volume_analysis) + + # 操作建议 + recommendation = analysis_result.get('recommendation', '未知') + entry_points = analysis_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 = analysis_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 = analysis_result.get('stop_loss', '未知') + take_profit = analysis_result.get('take_profit', '未知') + + # 紧迫性评级 + urgency_level = analysis_result.get('urgency_level', 0) + urgency_reason = analysis_result.get('urgency_reason', '未知') + + # 紧迫性等级图标 + if int(urgency_level) >= 4: + urgency_icon = "🔴" + elif int(urgency_level) >= 2: + urgency_icon = "🟡" + else: + urgency_icon = "🟢" + + # 总结 + summary = analysis_result.get('summary', '无摘要') + + # 根据市场趋势设置图标 + if '牛' in str(market_trend) or 'bull' in str(market_trend).lower(): + trend_icon = "🟢" + elif '熊' in str(market_trend) or 'bear' in str(market_trend).lower(): + trend_icon = "🔴" + else: + trend_icon = "🟡" + + # 构建Markdown文本 + markdown = f"""### DeepSeek AI 加密货币分析报告 + +**交易对**: {symbol} + +**分析时间**: {time.strftime('%Y-%m-%d %H:%M:%S')} + +**市场趋势**: {trend_icon} {market_trend} + +**技术指标分析**: +{technical_analysis} + +**交易量分析**: +{volume_analysis} + +**支撑位(斐波那契)**: +{support_levels_str} + +**阻力位(斐波那契)**: +{resistance_levels_str} + +**操作建议**: {recommendation} + +**入场点位**: {entry_points_str} + +**出场点位**: {exit_points_str} + +**止损位**: {stop_loss} + +**止盈位**: {take_profit} + +**操作紧迫性**: {urgency_icon} {urgency_level}/5 + +**紧迫性原因**: {urgency_reason} + +**总结**: {summary} + +""" + 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 = '' @@ -447,29 +590,13 @@ class DingTalkBot: title_icon = "🟡" # 获取建议操作 - position = '未知' - if strategy_result and 'position' in strategy_result: - position = strategy_result['position'] + position = analysis_result.get('recommendation', '未知') # 构建标题 - title = f"{title_icon} {symbol} 加密货币分析报告 | 建议: {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_text = self.format_integrated_report(symbol, analysis_result) # 发送Markdown消息 return self.send_markdown(title, markdown_text)