From 9f989ce9bb3b5a003fad7c0d9ff7860ff4ac6edb Mon Sep 17 00:00:00 2001 From: aaron <> Date: Mon, 28 Apr 2025 14:53:05 +0800 Subject: [PATCH] update --- crontab_setup.txt | 24 ++ cryptoai/__pycache__/main.cpython-313.pyc | Bin 8109 -> 8931 bytes .../__pycache__/crypto_agent.cpython-313.pyc | Bin 18277 -> 20431 bytes cryptoai/agents/crypto_agent.py | 20 ++ cryptoai/config/config.example.yaml | 49 +++- cryptoai/config/config.yaml | 21 +- .../__pycache__/config_loader.cpython-313.pyc | Bin 4938 -> 5173 bytes cryptoai/utils/db_manager.py | 263 ++++++++++++++++++ requirements.txt | 4 +- schedule_task.py | 140 ++++++++++ schedule_task.sh | 137 +++++++++ 11 files changed, 636 insertions(+), 22 deletions(-) create mode 100644 crontab_setup.txt create mode 100644 cryptoai/utils/db_manager.py create mode 100644 schedule_task.py create mode 100755 schedule_task.sh diff --git a/crontab_setup.txt b/crontab_setup.txt new file mode 100644 index 0000000..c2ac82d --- /dev/null +++ b/crontab_setup.txt @@ -0,0 +1,24 @@ +# 加密货币智能体 crontab 配置示例 +# 将以下内容添加到crontab中: crontab -e + +# 设置环境变量 +SHELL=/bin/bash +PATH=/usr/local/bin:/usr/bin:/bin +PYTHONPATH=/path/to/your/cryptoai + +# 日志文件 +LOGFILE=/path/to/your/cryptoai/logs/cron.log + +# 每天早上8:30运行加密货币智能体 +30 8 * * * cd /path/to/your/cryptoai && python run.py --agent crypto --run-once >> $LOGFILE 2>&1 + +# 每天晚上20:30运行黄金智能体 +30 20 * * * cd /path/to/your/cryptoai && python run.py --agent gold --run-once >> $LOGFILE 2>&1 + +# 每6小时运行一次加密货币智能体 +0 */6 * * * cd /path/to/your/cryptoai && python run.py --agent crypto --run-once >> $LOGFILE 2>&1 + +# 每周一早上9点运行完整分析 +0 9 * * 1 cd /path/to/your/cryptoai && python run.py --agent crypto --symbol BTCUSDT --days 90 >> $LOGFILE 2>&1 + +# 注意:使用前请将路径替换为您实际的项目路径 \ No newline at end of file diff --git a/cryptoai/__pycache__/main.cpython-313.pyc b/cryptoai/__pycache__/main.cpython-313.pyc index a802706143ca53662538693742f03681fc55b949..f0d19d4a5215240ad3d4eb99b40421716d340ea0 100644 GIT binary patch delta 1063 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 t_4vOOg6NC$GGP? zZd0!Ge)rsS&OPVebI(2Zz4to(+Y+M}irNG&jRs)I?tlr~ zpwGL`B$Jy=3a;CNrtlqGRgEkQUd+}n#Yv|8zG5pp=Lpr=O_`&g3Rz`I7E{Ei3Qj1E z(&0{c##d=^#$50xyPtLmW=L|&@HM4&UDjO|p~Z(H`=bua9a=>TzrY()E45F?+ zSaJQr>rQD}o@?5vgqlw?H$3BR>+_hF@+_UzSv^j}1sHa|I5(BcaMp;d5JHoHu*I-) zEi=t3V9l-D0)oZM;bd7ie821>b;HY^Wf<{(Q@+|#dq9E@y)7=gP_c;b-V%lP0@cvv zW3XnchD3RfV(YhL<+yy<2iGIPZncGw$@OCpXKjyD4~aRpS?-6OOjZa(W;uODfEo?wA z42Ot-#-36$hQf7~=?Sj0dAE?R6ab!RX(hOEuy^+iL< zrwnDUs;m2$I;XK-6e(PNN=u{!Gi+xO!7&{%bZIuejFKA)HBMMdfJ?k$gBD+ z$LKW`8|yMr{s!R1#8{J47Gh>iHFZg@l2y`dZ4$aQbzW@YV7 zf9(x_+jW22&Favao%pt|5v$L6*1F~l##s$FTNOj>_;IowOhR$H8Z5s-D;drpVVoZ=>dBeuW;kn>8+6O-gc2Wj^4`w8G zsBo;#LMzP89~1f<3q?~C>w~%aetH(ZUEfF#6|U3=ZAG0E59xfod4isY$D2FoAvo1s z>pUvrah~*&EQRvz)wW79YS}*r-)(-{Dv~x1>P~-QxFslC#pT_>2r|C2qvV_Pq4Y$L)oln;c z3pa+G%;dOs_fyf*9}2jef+x3LtD6xrc2dAyGY#!bOXgULhaGGHc6Yr(2jF&BJN&SF ziAG^}&rp30dkklo=NCmPj4+CD6khFVcZsbLmPF`*)t*PRy@E89G|x@v*qo}fM{r!l zwQMS(X4T9hPxA!R@;RonM@`j{g`}3()46QeZ6<{w*2L#CI$ytErPO9e&>{c2#BFKUslxe!+^&S<;5T2>xymRFnQXnSEL(k{_+@XNlh?!=uH1M?D6 zxEuDefQOR%4dlLtuq=RMwJxpe8$0@_yYTBB-?NDFyD%72o)p4;qApLu2ZND4X2>0a z#W1AoMT8ZE5dnsj7Lg<8wv6fwE+)#9;CbcOw zdCE}CM=YT&BufXkipuXJEF=6@z(WUjdMr$53oBy^O_j4wR54$`ZlszK@K1!bA(#Q_ zMG6DKS`o~==|T$M%m=Sz@uuOm4AW?svM(bgu|a4UpE$Ea3=9jtw)=6?0R;0t9z_ak z3$r3TxQ>`BhIJ~J%dj_5@*oa3P~uOR!A>U=s;;y2)V!|oM1oDBD!vZIaQcuEFi8A@ z;{O%!74m!Q!H=xl<$>irpAgY~l&4K{)rCE4M0A(9+5K$y)$yN?e}bH~z0fuhrw8GS z6Sek(RIXW@lHj$8BO%iZItVwJd1P4lA~$S#HJeg7+Yi2I#P=KYe;h$UxD4^=FuWP9 z=yQpo;Wz(ecsIU*i9E|CHO_O4VGS@U=k;`kcPDe%>GVt@lT%X~6aO^-j0UfhX4Qo delta 192 zcmdn0aY~KvGcPX}0}$-H&X+NZdm>-2gbE`A!&HVCh9bsbh9ah5#v None: + """初始化数据库连接和表""" + try: + # 创建数据库连接 + connection_string = f"mysql+pymysql://{self.user}:{self.password}@{self.host}:{self.port}/{self.db_name}?charset=utf8mb4" + + # 创建引擎,设置连接池 + self.engine = create_engine( + connection_string, + echo=False, # 设置为True可以输出SQL语句(调试用) + pool_size=5, # 连接池大小 + max_overflow=10, # 最大溢出连接数 + pool_timeout=30, # 连接超时时间 + pool_recycle=1800, # 连接回收时间(秒) + pool_pre_ping=True # 在使用连接前先ping一下,确保连接有效 + ) + + # 创建会话工厂 + self.Session = sessionmaker(bind=self.engine) + + # 创建表(如果不存在) + Base.metadata.create_all(self.engine) + + logger.info(f"成功连接到数据库 {self.db_name}") + + except Exception as e: + logger.error(f"数据库初始化失败: {e}") + self.engine = None + + def save_analysis_result(self, agent: str, symbol: str, time_interval: str, + analysis_result: Dict[str, Any]) -> bool: + """ + 保存分析结果到数据库 + + Args: + agent: 智能体类型,例如 'crypto' 或 'gold' + symbol: 交易对符号,例如 'BTCUSDT' + time_interval: 时间间隔,例如 '1h', '4h', '1d' + analysis_result: 分析结果数据 + + Returns: + 保存是否成功 + """ + if not self.engine: + try: + self._init_db() + except Exception as e: + logger.error(f"重新连接数据库失败: {e}") + return False + + try: + # 创建会话 + session = self.Session() + + try: + # 创建新记录 + new_result = AnalysisResult( + agent=agent, + symbol=symbol, + time_interval=time_interval, + completion_result=analysis_result, + created_at=datetime.now(), + updated_at=datetime.now() + ) + + # 添加并提交 + session.add(new_result) + session.commit() + + logger.info(f"成功保存 {agent} 分析结果,交易对: {symbol}, 时间间隔: {time_interval}") + return True + + except Exception as e: + session.rollback() + logger.error(f"保存分析结果失败: {e}") + return False + + finally: + session.close() + + except Exception as e: + logger.error(f"创建数据库会话失败: {e}") + # 如果是连接错误,尝试重新初始化 + try: + self._init_db() + except: + pass + return False + + def get_latest_result(self, agent: str, symbol: str, time_interval: str) -> Optional[Dict[str, Any]]: + """ + 获取最新的分析结果 + + Args: + agent: 智能体类型,例如 'crypto' 或 'gold' + symbol: 交易对符号,例如 'BTCUSDT' + time_interval: 时间间隔,例如 '1h', '4h', '1d' + + Returns: + 最新分析结果,如果查询失败则返回None + """ + if not self.engine: + try: + self._init_db() + except Exception as e: + logger.error(f"重新连接数据库失败: {e}") + return None + + try: + # 创建会话 + session = self.Session() + + try: + # 查询最新的结果 + result = session.query(AnalysisResult).filter( + AnalysisResult.agent == agent, + AnalysisResult.symbol == symbol, + AnalysisResult.time_interval == time_interval + ).order_by(AnalysisResult.created_at.desc()).first() + + if result: + # 转换为字典 + return { + 'id': result.id, + 'agent': result.agent, + 'symbol': result.symbol, + 'time_interval': result.time_interval, + 'completion_result': result.completion_result, + 'created_at': result.created_at + } + else: + return None + + finally: + session.close() + + except Exception as e: + logger.error(f"获取最新分析结果失败: {e}") + return None + + def close(self) -> None: + """关闭数据库连接""" + if self.engine: + self.engine.dispose() + self.engine = None + logger.info("数据库连接已关闭") + + +# 单例模式 +_db_instance = None + +def get_db_manager(host: Optional[str] = None, + port: Optional[int] = None, + user: Optional[str] = None, + password: Optional[str] = None, + db_name: Optional[str] = None) -> DBManager: + """ + 获取数据库管理器实例(单例模式) + + Args: + host: 数据库主机地址 + port: 数据库端口 + user: 用户名 + password: 密码 + db_name: 数据库名 + + Returns: + 数据库管理器实例 + """ + global _db_instance + + # 如果已经初始化过,直接返回 + if _db_instance is not None: + return _db_instance + + # 从环境变量获取配置 + db_host = host or os.environ.get('DB_HOST', 'gz-cynosdbmysql-grp-2j1cnopr.sql.tencentcdb.com') + db_port = port or int(os.environ.get('DB_PORT', '27469')) + db_user = user or os.environ.get('DB_USER', 'root') + db_password = password or os.environ.get('DB_PASSWORD', 'Aa#223388') + db_name = db_name or os.environ.get('DB_NAME', 'cryptoai') + + # 创建实例 + _db_instance = DBManager( + host=db_host, + port=db_port, + user=db_user, + password=db_password, + db_name=db_name + ) + + return _db_instance \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index edf2fb7..c2aba77 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,4 +12,6 @@ aiohttp>=3.8.5 langchain>=0.0.267 pydantic>=2.3.0 fastapi>=0.103.1 -uvicorn>=0.23.2 \ No newline at end of file +uvicorn>=0.23.2 +alltick-api==0.0.1 +okx-api==0.0.1 \ No newline at end of file diff --git a/schedule_task.py b/schedule_task.py new file mode 100644 index 0000000..18f18f9 --- /dev/null +++ b/schedule_task.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +加密货币分析智能体定时任务 +支持以下配置: +- 定时执行:设置每天指定时间执行分析任务 +- 周期执行:设置每隔一定时间执行一次分析任务 +- 同时支持多个智能体:crypto和gold + +使用方法: +python schedule_task.py # 使用默认配置执行 +python schedule_task.py --agent crypto # 指定执行加密货币智能体 +python schedule_task.py --agent gold # 指定执行黄金智能体 +python schedule_task.py --both # 同时执行两种智能体 +python schedule_task.py --time "12:00" # 设置每天执行的时间 +python schedule_task.py --interval 240 # 设置执行间隔(分钟) +""" + +import os +import sys +import time +import argparse +import schedule +import subprocess +from datetime import datetime + +def parse_arguments(): + """解析命令行参数""" + parser = argparse.ArgumentParser(description='加密货币分析智能体定时任务') + + parser.add_argument('--agent', type=str, default='crypto', + choices=['crypto', 'gold'], + help='要执行的智能体类型,默认为加密货币智能体') + + parser.add_argument('--both', action='store_true', + help='同时执行两种智能体') + + parser.add_argument('--time', type=str, default=None, + help='每天执行任务的时间,格式为HH:MM,例如 "08:30"') + + parser.add_argument('--interval', type=int, default=360, + help='自动执行间隔(分钟),默认为360分钟(6小时)') + + return parser.parse_args() + +def run_agent(agent_type='crypto'): + """ + 执行智能体 + + Args: + agent_type: 智能体类型,可选 'crypto' 或 'gold' + """ + current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + print(f"[{current_time}] 执行{agent_type}智能体...") + + try: + # 构建命令 + cmd = ["python", "run.py", f"--agent={agent_type}", "--run-once"] + + # 执行命令 + process = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True + ) + + # 实时输出日志 + while True: + output = process.stdout.readline() + if output == '' and process.poll() is not None: + break + if output: + print(output.strip()) + + # 获取执行结果 + _, stderr = process.communicate() + + # 检查是否有错误 + if process.returncode != 0: + print(f"执行{agent_type}智能体时出错: {stderr}") + else: + print(f"[{current_time}] {agent_type}智能体执行完成") + + except Exception as e: + print(f"执行{agent_type}智能体时出错: {e}") + +def run_both_agents(): + """执行两种智能体""" + run_agent('crypto') + run_agent('gold') + +def main(): + """主函数""" + args = parse_arguments() + + # 定义任务函数 + if args.both: + job_func = run_both_agents + agent_desc = "加密货币和黄金" + else: + job_func = lambda: run_agent(args.agent) + agent_desc = f"{args.agent}分析" + + # 根据参数设置定时任务 + if args.time: + # 设置每天固定时间执行 + schedule.every().day.at(args.time).do(job_func) + print(f"已设置每天 {args.time} 执行{agent_desc}智能体") + else: + # 设置定时间隔执行 + schedule.every(args.interval).minutes.do(job_func) + print(f"已设置每 {args.interval} 分钟执行一次{agent_desc}智能体") + + # 立即执行一次 + print("立即执行一次任务...") + job_func() + + # 循环等待下次执行 + while True: + # 检查是否有定时任务需要执行 + schedule.run_pending() + + # 打印下次执行时间 + next_run = schedule.next_run().strftime("%Y-%m-%d %H:%M:%S") + print(f"下次执行时间: {next_run}") + + # 等待一段时间再检查 + time.sleep(60) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + print("\n定时任务已停止") + except Exception as e: + print(f"定时任务出错: {e}") + import traceback + traceback.print_exc() \ No newline at end of file diff --git a/schedule_task.sh b/schedule_task.sh new file mode 100755 index 0000000..6f7cceb --- /dev/null +++ b/schedule_task.sh @@ -0,0 +1,137 @@ +#!/bin/bash + +# 加密货币分析智能体定时任务启动脚本 +# 该脚本用于在后台启动智能体定时任务 + +# 使用说明: +# ./schedule_task.sh start crypto 360 # 以360分钟为间隔启动加密货币智能体 +# ./schedule_task.sh start gold "08:30" # 每天08:30运行黄金智能体 +# ./schedule_task.sh start both 240 # 以240分钟为间隔同时启动两种智能体 +# ./schedule_task.sh stop # 停止所有运行中的定时任务 +# ./schedule_task.sh status # 查看运行状态 + +# 获取当前脚本所在目录 +SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) +LOG_DIR="${SCRIPT_DIR}/logs" +SCHEDULE_LOG="${LOG_DIR}/schedule_task.log" + +# 确保日志目录存在 +mkdir -p "${LOG_DIR}" + +# 激活虚拟环境(如果使用了虚拟环境) +VENV_PATH="${SCRIPT_DIR}/venv" +if [ -d "${VENV_PATH}" ]; then + source "${VENV_PATH}/bin/activate" + echo "已激活虚拟环境: ${VENV_PATH}" +fi + +# 定义启动定时任务的函数 +start_schedule_task() { + local agent_type=$1 + local time_or_interval=$2 + local cmd="python ${SCRIPT_DIR}/schedule_task.py" + + # 如果同时执行两种智能体 + if [ "${agent_type}" == "both" ]; then + cmd="${cmd} --both" + else + cmd="${cmd} --agent ${agent_type}" + fi + + # 判断第二个参数是时间点还是间隔 + if [[ "${time_or_interval}" =~ ^[0-9]+$ ]]; then + # 如果是纯数字,则认为是间隔 + cmd="${cmd} --interval ${time_or_interval}" + else + # 否则认为是时间点 + cmd="${cmd} --time \"${time_or_interval}\"" + fi + + # 使用nohup在后台运行 + echo "启动定时任务: ${cmd}" + nohup ${cmd} > "${SCHEDULE_LOG}" 2>&1 & + + # 保存PID + echo $! > "${SCRIPT_DIR}/.schedule_task.pid" + echo "定时任务已在后台启动,PID: $!" + echo "日志文件: ${SCHEDULE_LOG}" +} + +# 定义停止定时任务的函数 +stop_schedule_task() { + if [ -f "${SCRIPT_DIR}/.schedule_task.pid" ]; then + local pid=$(cat "${SCRIPT_DIR}/.schedule_task.pid") + echo "正在停止定时任务 (PID: ${pid})..." + kill -15 ${pid} 2>/dev/null || echo "进程 ${pid} 不存在" + rm -f "${SCRIPT_DIR}/.schedule_task.pid" + else + echo "没有找到运行中的定时任务" + fi +} + +# 定义查看状态的函数 +check_status() { + if [ -f "${SCRIPT_DIR}/.schedule_task.pid" ]; then + local pid=$(cat "${SCRIPT_DIR}/.schedule_task.pid") + if ps -p ${pid} > /dev/null; then + echo "定时任务正在运行 (PID: ${pid})" + echo "最近的日志:" + tail -n 20 "${SCHEDULE_LOG}" + else + echo "定时任务已停止 (上次PID: ${pid})" + rm -f "${SCRIPT_DIR}/.schedule_task.pid" + fi + else + echo "没有找到运行中的定时任务" + fi +} + +# 主逻辑 +case "$1" in + start) + if [ -f "${SCRIPT_DIR}/.schedule_task.pid" ]; then + pid=$(cat "${SCRIPT_DIR}/.schedule_task.pid") + if ps -p ${pid} > /dev/null; then + echo "定时任务已在运行中 (PID: ${pid})" + echo "如需重启,请先执行: $0 stop" + exit 1 + else + rm -f "${SCRIPT_DIR}/.schedule_task.pid" + fi + fi + + # 检查必要的参数 + if [ -z "$2" ]; then + echo "缺少参数: agent_type (crypto, gold 或 both)" + echo "用法: $0 start [agent_type] [time_or_interval]" + exit 1 + fi + + if [ -z "$3" ]; then + # 使用默认间隔 + start_schedule_task "$2" "360" + else + start_schedule_task "$2" "$3" + fi + ;; + + stop) + stop_schedule_task + ;; + + status) + check_status + ;; + + *) + echo "用法: $0 {start|stop|status}" + echo " start [agent_type] [time_or_interval] - 启动定时任务" + echo " agent_type: crypto, gold 或 both" + echo " time_or_interval: 时间点(HH:MM)或间隔(分钟)" + echo " stop - 停止定时任务" + echo " status - 查看运行状态" + exit 1 + ;; +esac + +exit 0 \ No newline at end of file