diff --git a/.gitignore b/.gitignore index d4f7977..b432af3 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,8 @@ wheels/ .installed.cfg *.egg + + # 虚拟环境 venv/ ENV/ diff --git a/README.md b/README.md index f12f385..fd01315 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ - 利用DeepSeek大模型进行市场分析和预测 - 提供市场趋势、价格预测和交易建议 - 支持多种加密货币分析 -- 通过钉钉机器人发送分析结果 +- 通过钉钉机器人和Discord Webhook发送分析结果 ## 项目结构 @@ -98,6 +98,10 @@ OKX_PASSPHRASE=OKX密码 DINGTALK_ENABLED=true/false DINGTALK_WEBHOOK_URL=钉钉Webhook地址 DINGTALK_SECRET=钉钉密钥 + +# Discord机器人 +DISCORD_ENABLED=true/false +DISCORD_WEBHOOK_URL=Discord Webhook地址 ``` 在Docker中可以通过`-e`参数或`.env`文件传递环境变量。 @@ -175,4 +179,39 @@ curl -X POST "http://localhost:8000/api/analyze" \ "symbol": "BTC", "task_type": "市场分析" }' +``` + +## 消息通知 + +项目支持多种消息通知方式,可以将分析结果发送到不同的平台。 + +### 钉钉机器人 + +在配置文件中设置钉钉机器人的Webhook URL和密钥,启用后会将分析结果发送到钉钉群聊。 + +```yaml +dingtalk: + enabled: true + webhook_url: your_dingtalk_webhook_url + secret: your_dingtalk_secret +``` + +### Discord机器人 + +在配置文件中设置Discord Webhook URL,启用后会将分析结果以精美的嵌入式消息发送到Discord频道。 + +```yaml +discord: + enabled: true + webhook_url: your_discord_webhook_url + username: CryptoAI分析机器人 + avatar_url: https://cdn-icons-png.flaticon.com/512/2878/2878497.png +``` + +#### 测试Discord机器人 + +可以使用以下命令测试Discord机器人的功能: + +```bash +python -m cryptoai.tests.test_discord_bot --webhook your_webhook_url ``` \ No newline at end of file diff --git a/cryptoai/__pycache__/main.cpython-313.pyc b/cryptoai/__pycache__/main.cpython-313.pyc index b6f962b..895eaca 100644 Binary files a/cryptoai/__pycache__/main.cpython-313.pyc and b/cryptoai/__pycache__/main.cpython-313.pyc differ diff --git a/cryptoai/agents/__pycache__/crypto_agent.cpython-313.pyc b/cryptoai/agents/__pycache__/crypto_agent.cpython-313.pyc index 5717230..f4e3e69 100644 Binary files a/cryptoai/agents/__pycache__/crypto_agent.cpython-313.pyc and b/cryptoai/agents/__pycache__/crypto_agent.cpython-313.pyc differ diff --git a/cryptoai/agents/crypto_agent.py b/cryptoai/agents/crypto_agent.py index 6b0106c..f7cef35 100644 --- a/cryptoai/agents/crypto_agent.py +++ b/cryptoai/agents/crypto_agent.py @@ -18,7 +18,7 @@ from models.data_processor import DataProcessor from utils.config_loader import ConfigLoader from utils.dingtalk_bot import DingTalkBot from utils.db_manager import get_db_manager - +from utils.discord_bot import DiscordBot class CryptoAgent: """加密货币智能体,用于分析市场数据并生成交易策略""" @@ -40,6 +40,7 @@ class CryptoAgent: self.crypto_config = self.config_loader.get_crypto_config() self.data_config = self.config_loader.get_data_config() self.dingtalk_config = self.config_loader.get_dingtalk_config() + self.discord_config = self.config_loader.get_discord_config() # 初始化API客户端 self.binance_api = BinanceAPI( @@ -70,6 +71,14 @@ class CryptoAgent: ) print("钉钉机器人已启用") + # 初始化Discord机器人(如果启用) + self.discord_bot = None + if self.discord_config.get('enabled', False): + self.discord_bot = DiscordBot( + webhook_url=self.discord_config['crypto_webhook_url'] + ) + print("Discord机器人已启用") + # 初始化数据库管理器 self.db_manager = get_db_manager() @@ -345,6 +354,9 @@ class CryptoAgent: print(f"交易建议: {message}") if self.dingtalk_bot: self.dingtalk_bot.send_markdown(title="加密货币交易建议", text=message) + + if self.discord_bot: + self.discord_bot.send_message(content=message) # 导出 DeepSeek API token 使用情况 self._export_token_usage() diff --git a/cryptoai/agents/gold_agent.py b/cryptoai/agents/gold_agent.py index f40a25c..6157fea 100644 --- a/cryptoai/agents/gold_agent.py +++ b/cryptoai/agents/gold_agent.py @@ -17,7 +17,7 @@ from api.deepseek_api import DeepSeekAPI from models.data_processor import DataProcessor from utils.config_loader import ConfigLoader from utils.dingtalk_bot import DingTalkBot - +from utils.discord_bot import DiscordBot class GoldAgent: """黄金分析智能体,用于分析黄金市场数据并生成交易策略""" @@ -39,6 +39,7 @@ class GoldAgent: self.gold_config = self.config_loader.get_gold_config() # 黄金特定配置 self.data_config = self.config_loader.get_data_config() self.dingtalk_config = self.config_loader.get_dingtalk_config() + self.discord_config = self.config_loader.get_discord_config() # 初始化API客户端 self.binance_api = BinanceAPI( @@ -65,6 +66,14 @@ class GoldAgent: secret=self.dingtalk_config.get('secret') ) print("钉钉机器人已启用") + + # 初始化Discord机器人(如果启用) + self.discord_bot = None + if self.discord_config.get('enabled', False): + self.discord_bot = DiscordBot( + webhook_url=self.discord_config['gold_webhook_url'] + ) + print("Discord机器人已启用") # 设置黄金交易对 self.gold_symbols = self.gold_config.get('symbols', ["XAUUSD"]) # 默认黄金/美元 @@ -336,6 +345,9 @@ class GoldAgent: if self.dingtalk_bot: self.dingtalk_bot.send_markdown(title="黄金交易建议", text=trading_suggestions) + if self.discord_bot: + self.discord_bot.send_message(content=trading_suggestions) + return results, trading_suggestions def convert_analysis_to_trading_suggestions(self, results: Dict[str, Any]) -> str: diff --git a/cryptoai/config/config.yaml b/cryptoai/config/config.yaml index ed5f027..fef88a9 100644 --- a/cryptoai/config/config.yaml +++ b/cryptoai/config/config.yaml @@ -27,8 +27,10 @@ crypto: base_currencies: - "BTC" - "ETH" - # - "SOL" - # - "SUI" + - "SOL" + - "SUI" + - "XRP" + - “DOGE” quote_currency: "USDT" time_interval: "4h" # 可选: 1m, 5m, 15m, 30m, 1h, 4h, 1d historical_days: 90 @@ -38,7 +40,7 @@ gold: # 黄金交易对 symbols: ["GOLD"] # 历史数据天数 - historical_days: 30 + historical_days: 90 # 时间间隔 time_interval: "4h" @@ -60,6 +62,13 @@ dingtalk: at_mobiles: [] # 需要@的手机号列表 at_all: false # 是否@所有人 +# Discord机器人配置 +discord: + enabled: true + crypto_webhook_url: "https://discord.com/api/webhooks/1286585288986198048/iQ-yr26ViW45GM48ql8rPu70Iumqcmn_XXAmxAcKGeiQBmTQoDPeq-TmlChvIHkw_HJ-" + gold_webhook_url: "https://discord.com/api/webhooks/1367341235987021914/XVcjs6ZAZad3ZezzuudyiK_KqNUowqz2o2NJPdvwWY_EvwZVJcnVHq5M0-RQhkKV-FEQ" + + # 数据库配置 database: host: "gz-cynosdbmysql-grp-2j1cnopr.sql.tencentcdb.com" diff --git a/cryptoai/main.py b/cryptoai/main.py index 5709046..351558e 100644 --- a/cryptoai/main.py +++ b/cryptoai/main.py @@ -26,13 +26,18 @@ def main(): print("定时程序启动") CryptoAgent().start_agent() # 设置 08:00, 20:00 运行一次 + schedule.every().day.at("00:00").do(CryptoAgent().start_agent) schedule.every().day.at("08:00").do(CryptoAgent().start_agent) + schedule.every().day.at("12:00").do(CryptoAgent().start_agent) + schedule.every().day.at("16:00").do(CryptoAgent().start_agent) schedule.every().day.at("20:00").do(CryptoAgent().start_agent) + schedule.every().day.at("00:00").do(GoldAgent().start_agent) schedule.every().day.at("08:00").do(GoldAgent().start_agent) + schedule.every().day.at("12:00").do(GoldAgent().start_agent) + schedule.every().day.at("16:00").do(GoldAgent().start_agent) schedule.every().day.at("20:00").do(GoldAgent().start_agent) - # 启动定时任务 while True: schedule.run_pending() time.sleep(1) @@ -46,5 +51,5 @@ def main(): traceback.print_exc() -if __name__ == "__main__": +if __name__ == "__main__": main() \ No newline at end of file diff --git a/cryptoai/utils/__init__.py b/cryptoai/utils/__init__.py index 6ec6832..8cb6549 100644 --- a/cryptoai/utils/__init__.py +++ b/cryptoai/utils/__init__.py @@ -1,4 +1,8 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -"""工具模块,提供各种辅助功能。""" \ No newline at end of file +"""工具模块,提供各种辅助功能。""" + +from cryptoai.utils.dingtalk_bot import DingTalkBot +from cryptoai.utils.discord_bot import DiscordBot +from cryptoai.utils.config_loader import ConfigLoader \ No newline at end of file diff --git a/cryptoai/utils/__pycache__/__init__.cpython-313.pyc b/cryptoai/utils/__pycache__/__init__.cpython-313.pyc index fcca2b9..e512409 100644 Binary files a/cryptoai/utils/__pycache__/__init__.cpython-313.pyc and b/cryptoai/utils/__pycache__/__init__.cpython-313.pyc differ diff --git a/cryptoai/utils/__pycache__/config_loader.cpython-313.pyc b/cryptoai/utils/__pycache__/config_loader.cpython-313.pyc index 14e4a5a..051b2c0 100644 Binary files a/cryptoai/utils/__pycache__/config_loader.cpython-313.pyc and b/cryptoai/utils/__pycache__/config_loader.cpython-313.pyc differ diff --git a/cryptoai/utils/config_loader.py b/cryptoai/utils/config_loader.py index 0a6522d..2ce1782 100644 --- a/cryptoai/utils/config_loader.py +++ b/cryptoai/utils/config_loader.py @@ -96,35 +96,11 @@ class ConfigLoader: """获取钉钉机器人配置""" return self.get_config('dingtalk') + def get_discord_config(self) -> Dict[str, Any]: + """获取Discord机器人配置""" + return self.get_config('discord') + def get_database_config(self) -> Dict[str, Any]: """获取数据库配置""" - # 首先从配置文件获取 - db_config = self.get_config('database') - # 使用环境变量覆盖(如果存在) - if os.environ.get('DB_HOST'): - db_config['host'] = os.environ.get('DB_HOST') - if os.environ.get('DB_PORT'): - db_config['port'] = int(os.environ.get('DB_PORT')) - if os.environ.get('DB_USER'): - db_config['user'] = os.environ.get('DB_USER') - if os.environ.get('DB_PASSWORD'): - db_config['password'] = os.environ.get('DB_PASSWORD') - if os.environ.get('DB_NAME'): - db_config['db_name'] = os.environ.get('DB_NAME') - - # 确保返回默认值(如果配置不存在) - default_config = { - 'host': 'gz-cynosdbmysql-grp-2j1cnopr.sql.tencentcdb.com', - 'port': 27469, - 'user': 'root', - 'password': 'Aa#223388', - 'db_name': 'cryptoai' - } - - # 合并默认配置和实际配置 - for key, value in default_config.items(): - if key not in db_config: - db_config[key] = value - - return db_config \ No newline at end of file + return self.get_config('database') \ No newline at end of file diff --git a/cryptoai/utils/discord_bot.py b/cryptoai/utils/discord_bot.py new file mode 100644 index 0000000..25aa3e5 --- /dev/null +++ b/cryptoai/utils/discord_bot.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import json +import requests +import traceback +import datetime +from typing import Dict, Any, List, Optional, Union + +class DiscordBot: + """Discord Webhook机器人,用于发送分析结果到Discord频道""" + + def __init__(self, webhook_url: str): + """ + 初始化Discord Webhook机器人 + + Args: + webhook_url: Discord Webhook的URL + """ + self.webhook_url = webhook_url + + def send_message(self, content: str, username: str = None, avatar_url: str = None) -> Dict[str, Any]: + """ + 发送普通消息 + + Args: + content: 消息内容 + username: 自定义机器人名称 + avatar_url: 自定义机器人头像URL + + Returns: + 接口返回结果 + """ + data = {"content": content} + + if username: + data["username"] = username + + if avatar_url: + data["avatar_url"] = avatar_url + + return self._post(data) + + def _post(self, data: Dict[str, Any]) -> Dict[str, Any]: + """ + 发送数据到Discord Webhook + + Args: + data: 要发送的数据 + + Returns: + 接口返回结果 + """ + try: + headers = {'Content-Type': 'application/json'} + response = requests.post(self.webhook_url, json=data, headers=headers) + if response.status_code == 204: # Discord返回成功时无内容 + return {"success": True} + return response.json() + except Exception as e: + print(f"发送Discord消息时出错: {e}") + traceback.print_exc() + return {"success": False, "error": str(e)} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index f6a168e..7b61d30 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,7 @@ services: cryptoai: build: . container_name: cryptoai-task - image: cryptoai:0.0.9 + image: cryptoai:0.0.10 restart: always volumes: - ./cryptoai/data:/app/cryptoai/data