diff --git a/.env.example b/.env.example
index 77b2175..061e4df 100644
--- a/.env.example
+++ b/.env.example
@@ -1,20 +1,95 @@
-# DeepSeek API配置(必需)
+# ============================================================
+# AI股票分析系统环境配置模板
+# ============================================================
+# 使用说明:
+# 1. 复制此文件并重命名为 .env
+# 2. 根据实际情况填写配置项
+# 3. 敏感信息(如API密钥、密码)请妥善保管,不要提交到版本控制
+# ============================================================
+
+# ========== DeepSeek API配置 ==========
+# DeepSeek API密钥(必填)
+# 获取地址:https://platform.deepseek.com/api_keys
DEEPSEEK_API_KEY=your_actual_deepseek_api_key_here
+
+# DeepSeek API基础URL(可选,使用默认值即可)
DEEPSEEK_BASE_URL=https://api.deepseek.com/v1
-# 邮件通知配置(可选)
-EMAIL_ENABLED=false
-SMTP_SERVER=smtp.qq.com
-SMTP_PORT=587
-EMAIL_FROM=your_email@qq.com
-EMAIL_PASSWORD=your_authorization_code
-EMAIL_TO=receiver@example.com
-# MiniQMT量化交易配置(可选)
+# ========== Tushare数据接口(可选)==========
+# Tushare Token(可选,用于获取更多金融数据)
+# 获取地址:https://tushare.pro/register
+TUSHARE_TOKEN=
+
+
+# ========== MiniQMT量化交易配置(可选)==========
+# 是否启用MiniQMT量化交易接口
MINIQMT_ENABLED=false
-MINIQMT_ACCOUNT_ID=your_account_id
+
+# MiniQMT账户ID
+MINIQMT_ACCOUNT_ID=
+
+# MiniQMT服务器地址
MINIQMT_HOST=127.0.0.1
+
+# MiniQMT服务器端口
MINIQMT_PORT=58610
-# 时区设置
+
+# ========== 邮件通知配置(可选)==========
+# 是否启用邮件通知
+EMAIL_ENABLED=false
+
+# SMTP服务器地址
+# 常用邮箱SMTP服务器:
+# - 163邮箱:smtp.163.com
+# - QQ邮箱:smtp.qq.com
+# - Gmail:smtp.gmail.com
+# - 企业邮箱:根据邮箱服务商提供的信息填写
+SMTP_SERVER=smtp.163.com
+
+# SMTP服务器端口
+# 常用端口:
+# - 465:SSL加密连接(推荐)
+# - 587:TLS加密连接
+SMTP_PORT=465
+
+# 发件人邮箱地址
+EMAIL_FROM=your_email@163.com
+
+# 邮箱授权码(不是登录密码!)
+# 获取方法:
+# - 163邮箱:设置 -> POP3/SMTP/IMAP -> 开启服务 -> 获取授权码
+# - QQ邮箱:设置 -> 账户 -> POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务 -> 开启服务 -> 生成授权码
+EMAIL_PASSWORD=your_email_authorization_code
+
+# 收件人邮箱地址(接收通知的邮箱)
+EMAIL_TO=receiver@example.com
+
+
+# ========== Webhook通知配置(可选)==========
+# 是否启用Webhook通知(钉钉/飞书)
+WEBHOOK_ENABLED=false
+
+# Webhook类型
+# 可选值:dingtalk(钉钉)、feishu(飞书)
+WEBHOOK_TYPE=dingtalk
+
+# Webhook地址
+# 钉钉机器人:https://oapi.dingtalk.com/robot/send?access_token=YOUR_ACCESS_TOKEN
+# 飞书机器人:https://open.feishu.cn/open-apis/bot/v2/hook/YOUR_HOOK_ID
+WEBHOOK_URL=
+
+# Webhook自定义关键词(仅钉钉需要)
+# 说明:
+# - 如果钉钉机器人设置了"自定义关键词"安全验证,请在此填写关键词
+# - 系统会自动在消息标题和内容中包含此关键词
+# - 如果不使用关键词验证,可以留空或使用其他安全方式(加签、IP白名单)
+# - 飞书机器人通常不需要关键词,可以留空
+# 示例:aiagents通知
+WEBHOOK_KEYWORD=
+
+
+# ========== 时区配置 ==========
+# 系统时区设置(可选)
TZ=Asia/Shanghai
diff --git a/Dockerfile b/Dockerfile
index cd380eb..eee57bc 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,44 +1,34 @@
# 使用官方Python镜像作为基础镜像
FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/python:3.12-slim
-# 替换apt-get源为国内源(阿里源)
-RUN echo "deb https://mirrors.aliyun.com/debian/ bookworm main" > /etc/apt/sources.list && \
- echo "deb https://mirrors.aliyun.com/debian/ bookworm-updates main" >> /etc/apt/sources.list && \
- echo "deb https://mirrors.aliyun.com/debian-security bookworm-security main" >> /etc/apt/sources.list && \
- rm -rf /etc/apt/sources.list.d/* || true
-
# 设置工作目录
WORKDIR /app
-# 安装Node.js和中文字体 - 使用修正版方案一
+# 安装Node.js (pywencai需要) 和中文字体 (PDF生成需要)
RUN apt-get update && apt-get install -y \
- curl \
- gnupg \
- fonts-noto-cjk \
- fonts-wqy-zenhei \
- fonts-wqy-microhei \
- fontconfig \
- && curl -fsSL https://mirrors.aliyun.com/nodesource/setup_18.x | bash - \
- && apt-get install -y nodejs npm \
- && fc-cache -fv \
- && apt-get clean \
- && rm -rf /var/lib/apt/lists/*
+ curl \
+ gnupg \
+ fonts-noto-cjk \
+ fonts-wqy-zenhei \
+ fonts-wqy-microhei \
+ fontconfig \
+ && curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
+ && apt-get install -y nodejs \
+ && fc-cache -fv \
+ && apt-get clean \
+ && rm -rf /var/lib/apt/lists/*
-# 验证安装 - 添加详细检查
-RUN echo "Node.js版本:" && node --version && \
- echo "npm路径:" && which npm && \
- echo "npm版本:" && npm --version
-
-# 配置npm使用淘宝镜像源
-RUN npm config set registry https://registry.npmmirror.com/
+# 验证安装
+RUN node --version && npm --version
# 复制依赖文件
COPY requirements.txt .
-# 安装Python依赖
-RUN pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ && \
- pip config set global.trusted-host mirrors.aliyun.com && \
- pip install --no-cache-dir --default-timeout=1000 -r requirements.txt
+# 安装Python依赖 - 修改后的部分
+# 永久配置pip使用国内镜像源并增加超时时间[1](@ref)[2](@ref)
+RUN pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple/ && \
+ pip config set global.trusted-host pypi.tuna.tsinghua.edu.cn && \
+ pip install --no-cache-dir --default-timeout=1000 -r requirements.txt
# 复制项目文件
COPY . .
@@ -53,4 +43,5 @@ EXPOSE 8501
HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health || exit 1
# 启动应用
-CMD ["python", "run.py"]
\ No newline at end of file
+CMD ["python", "run.py"]
+
diff --git a/Dockerfile1 b/Dockerfile1
deleted file mode 100644
index eee57bc..0000000
--- a/Dockerfile1
+++ /dev/null
@@ -1,47 +0,0 @@
-# 使用官方Python镜像作为基础镜像
-FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/python:3.12-slim
-
-# 设置工作目录
-WORKDIR /app
-
-# 安装Node.js (pywencai需要) 和中文字体 (PDF生成需要)
-RUN apt-get update && apt-get install -y \
- curl \
- gnupg \
- fonts-noto-cjk \
- fonts-wqy-zenhei \
- fonts-wqy-microhei \
- fontconfig \
- && curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
- && apt-get install -y nodejs \
- && fc-cache -fv \
- && apt-get clean \
- && rm -rf /var/lib/apt/lists/*
-
-# 验证安装
-RUN node --version && npm --version
-
-# 复制依赖文件
-COPY requirements.txt .
-
-# 安装Python依赖 - 修改后的部分
-# 永久配置pip使用国内镜像源并增加超时时间[1](@ref)[2](@ref)
-RUN pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple/ && \
- pip config set global.trusted-host pypi.tuna.tsinghua.edu.cn && \
- pip install --no-cache-dir --default-timeout=1000 -r requirements.txt
-
-# 复制项目文件
-COPY . .
-
-# 创建必要的目录
-RUN mkdir -p /app/data && chmod 777 /app/data
-
-# 暴露Streamlit默认端口
-EXPOSE 8501
-
-# 设置健康检查
-HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health || exit 1
-
-# 启动应用
-CMD ["python", "run.py"]
-
diff --git a/Dockerfile国内源版 b/Dockerfile国内源版
new file mode 100644
index 0000000..cd380eb
--- /dev/null
+++ b/Dockerfile国内源版
@@ -0,0 +1,56 @@
+# 使用官方Python镜像作为基础镜像
+FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/python:3.12-slim
+
+# 替换apt-get源为国内源(阿里源)
+RUN echo "deb https://mirrors.aliyun.com/debian/ bookworm main" > /etc/apt/sources.list && \
+ echo "deb https://mirrors.aliyun.com/debian/ bookworm-updates main" >> /etc/apt/sources.list && \
+ echo "deb https://mirrors.aliyun.com/debian-security bookworm-security main" >> /etc/apt/sources.list && \
+ rm -rf /etc/apt/sources.list.d/* || true
+
+# 设置工作目录
+WORKDIR /app
+
+# 安装Node.js和中文字体 - 使用修正版方案一
+RUN apt-get update && apt-get install -y \
+ curl \
+ gnupg \
+ fonts-noto-cjk \
+ fonts-wqy-zenhei \
+ fonts-wqy-microhei \
+ fontconfig \
+ && curl -fsSL https://mirrors.aliyun.com/nodesource/setup_18.x | bash - \
+ && apt-get install -y nodejs npm \
+ && fc-cache -fv \
+ && apt-get clean \
+ && rm -rf /var/lib/apt/lists/*
+
+# 验证安装 - 添加详细检查
+RUN echo "Node.js版本:" && node --version && \
+ echo "npm路径:" && which npm && \
+ echo "npm版本:" && npm --version
+
+# 配置npm使用淘宝镜像源
+RUN npm config set registry https://registry.npmmirror.com/
+
+# 复制依赖文件
+COPY requirements.txt .
+
+# 安装Python依赖
+RUN pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ && \
+ pip config set global.trusted-host mirrors.aliyun.com && \
+ pip install --no-cache-dir --default-timeout=1000 -r requirements.txt
+
+# 复制项目文件
+COPY . .
+
+# 创建必要的目录
+RUN mkdir -p /app/data && chmod 777 /app/data
+
+# 暴露Streamlit默认端口
+EXPOSE 8501
+
+# 设置健康检查
+HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health || exit 1
+
+# 启动应用
+CMD ["python", "run.py"]
\ No newline at end of file
diff --git a/PDF中文乱码修复说明.md b/PDF中文乱码修复说明.md
deleted file mode 100644
index a5277d3..0000000
--- a/PDF中文乱码修复说明.md
+++ /dev/null
@@ -1,207 +0,0 @@
-# PDF中文乱码修复说明
-
-## 问题描述
-在Docker环境中,PDF导出时中文显示为乱码或方框,但本地Windows环境正常。
-
-## 原因分析
-- Docker容器基于Linux系统,默认不包含中文字体
-- PDF生成器(reportlab)需要中文字体才能正确渲染中文字符
-- 原代码只配置了Windows系统的字体路径
-
-## 修复方案
-
-### 已修改的文件
-
-#### 1. `Dockerfile`
-添加了中文字体包安装:
-```dockerfile
-# 安装Node.js (pywencai需要) 和中文字体 (PDF生成需要)
-RUN apt-get update && apt-get install -y \
- curl \
- gnupg \
- fonts-noto-cjk \
- fonts-wqy-zenhei \
- fonts-wqy-microhei \
- fontconfig \
- && curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
- && apt-get install -y nodejs \
- && fc-cache -fv \
- && apt-get clean \
- && rm -rf /var/lib/apt/lists/*
-```
-
-安装的字体包:
-- **fonts-noto-cjk**: Google Noto CJK字体(支持中日韩文字)
-- **fonts-wqy-zenhei**: 文泉驿正黑体
-- **fonts-wqy-microhei**: 文泉驿微米黑体
-- **fontconfig**: 字体配置工具
-
-#### 2. `pdf_generator.py`
-更新了字体注册函数,支持Linux系统:
-```python
-def register_chinese_fonts():
- """注册中文字体 - 支持Windows和Linux系统"""
- # Windows系统字体路径
- windows_font_paths = [...]
-
- # Linux系统字体路径(Docker环境)
- linux_font_paths = [
- '/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc',
- '/usr/share/fonts/truetype/wqy/wqy-microhei.ttc',
- '/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc',
- # ... 更多字体路径
- ]
-```
-
-## 重新部署步骤
-
-### 方式一:Docker Compose(推荐)
-
-```bash
-# 1. 停止并删除现有容器
-docker-compose down
-
-# 2. 删除旧镜像(可选,但推荐)
-docker rmi agentsstock1-app
-
-# 3. 重新构建并启动
-docker-compose up -d --build
-
-# 4. 查看日志,确认字体加载成功
-docker-compose logs -f
-```
-
-### 方式二:Docker命令
-
-```bash
-# 1. 停止并删除现有容器
-docker stop agentsstock1
-docker rm agentsstock1
-
-# 2. 删除旧镜像
-docker rmi agentsstock1
-
-# 3. 重新构建镜像
-docker build -t agentsstock1 .
-
-# 4. 启动新容器
-docker run -d -p 8503:8501 \
- -v $(pwd)/.env:/app/.env \
- --name agentsstock1 \
- agentsstock1
-
-# 5. 查看日志
-docker logs -f agentsstock1
-```
-
-## 验证修复
-
-### 1. 检查字体安装
-进入容器检查字体:
-```bash
-docker exec -it agentsstock1 bash
-fc-list :lang=zh # 列出所有中文字体
-```
-
-应该看到类似输出:
-```
-/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc: WenQuanYi Zen Hei:style=Regular
-/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc: Noto Sans CJK SC:style=Regular
-...
-```
-
-### 2. 查看应用日志
-在生成PDF时,日志中应该显示:
-```
-✅ 成功注册中文字体: /usr/share/fonts/truetype/wqy/wqy-zenhei.ttc
-```
-
-### 3. 测试PDF导出
-1. 在Web界面分析任意股票
-2. 点击"生成并下载PDF报告"
-3. 打开下载的PDF文件
-4. 确认中文正常显示
-
-## 故障排查
-
-### 问题1:构建时字体安装失败
-**现象**:构建过程中apt-get install失败
-
-**解决方案**:
-```bash
-# 清理Docker缓存后重试
-docker system prune -a
-docker-compose build --no-cache
-```
-
-### 问题2:字体未加载
-**现象**:日志显示"未找到中文字体"
-
-**检查步骤**:
-1. 确认Dockerfile中正确添加了字体包
-2. 进入容器检查字体文件是否存在
-3. 运行 `fc-cache -fv` 刷新字体缓存
-
-### 问题3:PDF仍然乱码
-**现象**:字体已安装但PDF中文仍显示为方框
-
-**可能原因**:
-1. 字体文件权限问题
-2. reportlab缓存问题
-3. 字体格式不兼容
-
-**解决方案**:
-```bash
-# 重新构建时清理所有缓存
-docker-compose down -v
-docker system prune -a
-docker-compose up -d --build
-```
-
-## 技术说明
-
-### 字体选择
-我们安装了3种字体包:
-1. **Noto Sans CJK**:Google开发,覆盖范围广,质量高
-2. **文泉驿正黑**:开源中文字体,适合阅读
-3. **文泉驿微米黑**:适合小字号显示
-
-系统会按优先级自动选择第一个可用的字体。
-
-### 字体文件格式
-- **TTC**:TrueType Collection(字体集合文件)
-- **TTF**:TrueType Font(单个字体文件)
-
-reportlab的TTFont可以处理这两种格式。
-
-### Docker镜像大小
-添加中文字体后,镜像大小会增加约50-100MB:
-- fonts-noto-cjk: ~70MB
-- fonts-wqy-zenhei: ~10MB
-- fonts-wqy-microhei: ~5MB
-
-这是正常的,为了支持完整的中文显示必须付出的空间代价。
-
-## 注意事项
-
-1. **本地环境无影响**:修改后的代码在Windows本地环境仍然正常工作
-2. **字体缓存**:首次启动时fontconfig会建立字体缓存,可能需要几秒钟
-3. **镜像更新**:已部署的用户需要重新构建镜像才能应用修复
-4. **备份数据**:重新部署前请备份数据库文件(.db文件)
-
-## 相关资源
-
-- [ReportLab中文支持文档](https://www.reportlab.com/docs/reportlab-userguide.pdf)
-- [Noto字体项目](https://www.google.com/get/noto/)
-- [文泉驿字体项目](http://wenq.org/)
-- [Docker字体配置指南](https://docs.docker.com/config/)
-
-## 更新日志
-
-- **2025-10-10**: 初始版本,添加Docker中文字体支持
-- **2025-10-10**: 更新pdf_generator.py,支持跨平台字体检测
-
----
-
-如有问题,请联系:ws3101001@126.com
-
diff --git a/README.md b/README.md
index f94e602..a384d45 100644
--- a/README.md
+++ b/README.md
@@ -2,16 +2,36 @@
- 初心:在股市摸爬滚打多年,自学自编各种指标,花冤枉钱学习了各种战法各种策略,也曾入各种小班,总是赚少赔多,逐渐失去在股市玩的信心。自从去年deepseek上市,一直探索用ai辅助分析,且近日受tradingagents项目启发(感谢原作),多agent结合跟踪主力资金战法(某指每年收费6000rmb),用各种ai辅助编程,拼凑了这么个小程序,根据软件提供的辅助信息,实盘测试盈率还是挺高的,并且逐步形成了自己的交易系统,近一个月来,账户也慢慢在扭亏为盈。开源此软件的目的,就是为了使像我一样的小散,不再迷茫。也许这个软件不能让你发大财,但是他能给你足够的信心。最后提醒:股市有风险,入市需谨慎!
- 希望能帮到你!欢迎加微信群讨论
-
+
### 基于Python + Streamlit + DeepSeek的智能股票分析系统,模拟证券公司分析师团队,提供全方位的股票投资分析和决策建议。
+## ✨1015 更新说明(最新)
+### 🔔 新增Webhook通知功能 ⭐️
+- **多平台支持**:支持钉钉、飞书群机器人推送通知
+- **全面集成**:实时监测、智策定时分析均支持Webhook推送
+- **灵活配置**:
+ - Web界面可视化配置,简单易用
+ - 支持自定义关键词,匹配机器人安全设置
+ - 可同时启用邮件和Webhook,双重保障
+- **消息格式**:
+ - 钉钉:精美Markdown格式,信息清晰
+ - 飞书:交互式卡片消息,展示美观
+- **智能推送**:
+ - 实时监测:进场/止盈/止损实时提醒
+ - 智策分析:每日板块策略精简摘要
+ - 量化交易:自动下单执行通知
+- **完整测试**:内置测试功能,一键验证配置
+- **详细文档**:提供完整的配置指南和故障排查
+
+
+
## ✨1011 更新优化数据获取
-## ✨1010 更新说明(最新)
+## ✨1010 更新说明
### 🇭🇰 新增港股分析支持 ⭐️
- **市场扩展**:现已支持A股、港股、美股三大市场
- **港股代码**:支持多种格式(700/00700/HK00700)
@@ -142,7 +162,21 @@
-### 📧 邮件通知系统
+### 📧 通知系统
+#### 📱 Webhook通知(新增)⭐️
+- **双平台支持**:钉钉群机器人、飞书群机器人
+- **实时推送**:股票监测提醒、智策分析报告即时送达
+- **灵活配置**:Web界面可视化配置,支持自定义关键词
+- **消息格式**:
+ - 钉钉:Markdown格式,信息清晰美观
+ - 飞书:交互式卡片,展示丰富多彩
+- **通知场景**:
+ - 实时监测:价格进入进场区间、达到止盈位、触及止损位
+ - 智策分析:每日板块策略、投资机会推送
+ - 量化交易:自动下单执行通知
+- **测试功能**:一键测试Webhook配置,快速验证
+
+#### 📧 邮件通知
- **多邮箱支持**:QQ邮箱、163邮箱、Gmail等
- **触发条件**:
- 价格进入进场区间
@@ -150,6 +184,11 @@
- 触及止损位
- **测试功能**:一键测试邮件配置
- **历史记录**:完整的通知历史查询
+
+#### 🔔 双重保障
+- **同时启用**:Webhook和邮件可同时使用
+- **互为补充**:Webhook实时查看,邮件详细存档
+- **灵活选择**:可单独使用任一通知方式
### 🎨 现代化界面
@@ -277,6 +316,12 @@ EMAIL_FROM=your_email@qq.com
EMAIL_PASSWORD=your_authorization_code
EMAIL_TO=receiver@example.com
+# Webhook通知配置(可选)⭐️ 新增
+WEBHOOK_ENABLED=false
+WEBHOOK_TYPE=dingtalk # 或 feishu
+WEBHOOK_URL=your_webhook_url_here
+WEBHOOK_KEYWORD=股票 # 钉钉自定义关键词,飞书可留空
+
# MiniQMT量化交易配置(可选)
MINIQMT_ENABLED=false
MINIQMT_ACCOUNT_ID=your_account_id
@@ -513,10 +558,43 @@ EMAIL_TO=receiver@example.com
- 点击"📧 发送测试邮件"
- 检查收件箱(含垃圾箱)
+**Webhook通知配置** ⭐️ 新增:
+
+1. **方法一:Web界面配置(推荐)**
+ - 进入"⚙️ 环境配置" → "📢 通知配置"
+ - 勾选"启用Webhook通知"
+ - 选择类型(钉钉/飞书)
+ - 填写Webhook URL和关键词
+ - 点击"💾 保存配置"
+
+2. **方法二:编辑.env文件**
+```env
+WEBHOOK_ENABLED=true
+WEBHOOK_TYPE=dingtalk
+WEBHOOK_URL=https://oapi.dingtalk.com/robot/send?access_token=xxxxx
+WEBHOOK_KEYWORD=股票
+```
+
+3. **创建钉钉机器人**:
+ - 钉钉群 → 设置 → 智能群助手 → 添加机器人 → 自定义
+ - 安全设置:自定义关键词(如:股票、分析)
+ - 复制Webhook地址到配置中
+
+4. **创建飞书机器人**:
+ - 飞书群 → 设置 → 群机器人 → 添加机器人 → 自定义机器人
+ - 设置名称:AI股票分析系统
+ - 复制Webhook地址到配置中
+
+5. **测试配置**:
+ - 进入"📊 实时监测" → "🔔 通知管理"
+ - 点击"📱 发送测试Webhook"
+ - 检查钉钉/飞书群是否收到消息
+
**通知触发条件**:
- ✅ 价格进入进场区间 → 进场提醒
- ✅ 价格达到止盈位 → 止盈提醒
- ✅ 价格跌破止损位 → 止损提醒
+- ✅ 智策定时分析 → 板块策略推送
#### 使用技巧
@@ -608,12 +686,17 @@ AI股票分析系统
- 通知记录表
- CRUD操作接口
-#### 📧 通知服务模块 (notification_service.py)
-- 邮件通知发送
-- 网页通知展示
-- 多邮箱支持(QQ/163/Gmail)
-- 通知历史管理
-- 配置测试功能
+#### 📧 通知服务模块 (notification_service.py) ⭐️ 增强
+- **邮件通知**:发送详细分析报告
+- **Webhook通知** ⭐️ 新增:
+ - 钉钉群机器人推送(Markdown格式)
+ - 飞书群机器人推送(交互式卡片)
+ - 自定义关键词支持
+ - 自动错误处理和重试
+- **网页通知**:界面实时提醒
+- **多平台支持**:QQ邮箱/163邮箱/Gmail/钉钉/飞书
+- **通知历史管理**:完整记录和查询
+- **配置测试功能**:一键测试邮件和Webhook
#### 🎯 主力选股模块 ⭐️ 新增
**main_force_selector.py**
@@ -780,6 +863,29 @@ DEFAULT_INTERVAL = "1d" # 默认数据间隔
- 进入容器检查:`docker exec -it agentsstock1 bash`
- **详细文档**:查看 `DOCKER_DEPLOYMENT.md` 获取完整的故障排除指南
+10. **Webhook通知问题** ⭐️ 新增
+ - **未收到Webhook消息**:
+ - 检查 `WEBHOOK_ENABLED=true` 是否已设置
+ - 验证Webhook URL是否完整正确
+ - 确认机器人未被移出群聊
+ - 检查网络连接是否正常
+ - **钉钉关键词不匹配(错误码310000)**:
+ - 确认机器人安全设置中的关键词
+ - 在.env中设置 `WEBHOOK_KEYWORD=股票`(与机器人设置一致)
+ - 或添加关键词:股票、分析、智策、监测
+ - **飞书消息发送失败**:
+ - 确认选择 `WEBHOOK_TYPE=feishu`
+ - 检查Webhook URL是否为飞书格式
+ - 飞书不需要关键词,可设置 `WEBHOOK_KEYWORD=""`
+ - **消息格式异常**:
+ - 确认选择了正确的Webhook类型(钉钉/飞书)
+ - 重新保存配置并重启应用
+ - **测试Webhook**:
+ - 进入"📊 实时监测" → "🔔 通知管理"
+ - 点击"📱 发送测试Webhook"验证配置
+ - 查看终端日志了解详细错误信息
+ - **详细文档**:查看 `Webhook通知配置指南.md` 获取完整配置教程
+
### 日志调试
系统运行时会在控制台输出详细日志,可用于问题诊断。如遇到错误,请查看终端输出。
@@ -792,6 +898,23 @@ docker-compose logs -f
docker logs -f agentsstock1
```
+### 相关文档
+
+**通知系统文档** ⭐️:
+- [Webhook通知配置指南.md](Webhook通知配置指南.md) - Webhook完整配置教程
+- [Webhook功能完成说明.md](Webhook功能完成说明.md) - Webhook功能详细说明
+- [Webhook自定义关键词功能说明.md](Webhook自定义关键词功能说明.md) - 关键词配置指南
+- [邮件配置指南.md](邮件配置指南.md) - 邮件通知配置
+
+**其他功能文档**:
+- [环境配置功能说明.md](环境配置功能说明.md) - 完整环境配置说明
+- [环境配置快速指南.md](环境配置快速指南.md) - 快速配置参考
+- [实时监测优化说明.md](实时监测优化说明.md) - 实时监测功能详解
+- [智策定时分析使用指南.md](智策定时分析使用指南.md) - 智策板块分析
+- [主力选股使用指南.md](主力选股使用指南.md) - 主力选股功能
+- [量化交易快速指南.md](量化交易快速指南.md) - MiniQMT集成指南
+- [DOCKER_DEPLOYMENT.md](DOCKER_DEPLOYMENT.md) - Docker部署详细文档
+
### 错误报告
如发现bug,请查看 `BUGFIX.md` 文件了解已知问题和解决方案。
@@ -810,3 +933,4 @@ MIT License
---
**享受AI驱动的智能股票分析体验!** 🚀📈任何疑问请留言或联系ws3101001@126.com
+**技术支持:山东科技大学 于舒馨**
\ No newline at end of file
diff --git a/Webhook功能完成说明.md b/Webhook功能完成说明.md
new file mode 100644
index 0000000..7028fba
--- /dev/null
+++ b/Webhook功能完成说明.md
@@ -0,0 +1,492 @@
+# Webhook功能完成说明
+
+## ✅ 功能概述
+
+成功为系统添加了**Webhook通知功能**,支持钉钉和飞书群机器人推送。
+
+## 📋 完成内容
+
+### 1. 核心功能实现
+
+#### ✅ notification_service.py - Webhook发送核心
+**新增功能**:
+- `_send_webhook_notification()` - Webhook通知分发
+- `_send_dingtalk_webhook()` - 钉钉消息发送
+- `_send_feishu_webhook()` - 飞书消息发送
+- `send_test_webhook()` - 测试Webhook配置
+- `get_webhook_config_status()` - 获取配置状态
+
+**支持特性**:
+- 📱 钉钉Markdown格式消息
+- 📱 飞书交互式卡片消息
+- ✅ 自动错误处理和重试
+- ✅ 详细日志输出
+
+#### ✅ sector_strategy_scheduler.py - 智策定时分析集成
+**新增功能**:
+- `_send_webhook_direct()` - 直接发送webhook
+- `_send_dingtalk()` - 发送钉钉消息
+- `_send_feishu()` - 发送飞书消息
+- `_format_webhook_summary()` - 格式化精简摘要
+
+**特点**:
+- 同时支持邮件和Webhook
+- 智能格式化报告(精简版)
+- 分别统计发送成功数
+- 完善的异常处理
+
+### 2. 配置管理
+
+#### ✅ config_manager.py - 配置项定义
+**新增配置**:
+```python
+EMAIL_ENABLED # 邮件通知开关
+SMTP_SERVER # SMTP服务器
+SMTP_PORT # SMTP端口
+EMAIL_FROM # 发件人邮箱
+EMAIL_PASSWORD # 邮箱授权码
+EMAIL_TO # 收件人邮箱
+WEBHOOK_ENABLED # Webhook开关
+WEBHOOK_TYPE # Webhook类型(dingtalk/feishu)
+WEBHOOK_URL # Webhook地址
+```
+
+**特性**:
+- 支持布尔、文本、密码、选择框类型
+- 自动读取和写入.env文件
+- 完整的配置验证
+
+#### ✅ app.py - 可视化配置界面
+**新增UI**:
+- 第4个标签页:"📢 通知配置"
+- 左右分栏布局(邮件 | Webhook)
+- 实时配置状态提示
+- 完整的帮助说明
+
+**交互特性**:
+- 启用开关自动禁用/启用输入框
+- 配置完整性实时检查
+- 保存后自动重新加载
+- 显示当前.env文件内容
+
+### 3. 通知集成
+
+#### ✅ 实时监测模块
+**集成点**:`monitor_service.py` → `notification_service.send_notifications()`
+
+**通知时机**:
+- ✅ 价格进入进场区间
+- ✅ 价格达到止盈位
+- ✅ 价格跌破止损位
+- ✅ 量化交易执行
+
+**发送逻辑**:
+```python
+# 同时尝试Webhook和邮件
+if webhook_enabled:
+ webhook_success = send_webhook()
+if email_enabled:
+ email_success = send_email()
+# 至少一个成功即为成功
+```
+
+#### ✅ 智策定时分析
+**集成点**:`sector_strategy_scheduler.py` → `_send_analysis_notification()`
+
+**通知内容**:
+- 📊 板块多空预测(信心度≥7)
+- 🔄 潜力接力板块(TOP3)
+- 🌡️ 板块热度排行(TOP3)
+- 💡 核心投资机会
+
+**消息格式**:
+- Webhook:精简版(适合移动端)
+- 邮件:完整版(详细分析)
+
+### 4. 完整文档
+
+#### ✅ 新建文档
+- **Webhook通知配置指南.md** - 完整配置教程
+ - 平台支持说明
+ - 钉钉配置步骤
+ - 飞书配置步骤
+ - 消息格式示例
+ - 故障排查指南
+ - 使用场景推荐
+
+#### ✅ 更新文档
+- **环境配置功能说明.md** - 添加通知配置章节
+- **config_manager.py** - 配置定义完善
+- **app.py** - UI界面完整
+
+---
+
+## 🎯 使用方法
+
+### 第一步:配置Webhook
+
+#### 方法A:Web界面配置(推荐)
+1. 进入"⚙️ 环境配置"
+2. 选择"📢 通知配置"标签页
+3. 勾选"启用Webhook通知"
+4. 选择类型(钉钉/飞书)
+5. 填写Webhook URL
+6. 点击"💾 保存配置"
+
+#### 方法B:手动编辑.env
+```env
+WEBHOOK_ENABLED=true
+WEBHOOK_TYPE=dingtalk
+WEBHOOK_URL=https://oapi.dingtalk.com/robot/send?access_token=xxxxx
+```
+
+### 第二步:创建机器人
+
+#### 钉钉机器人
+1. 钉钉群 → 设置 → 智能群助手
+2. 添加机器人 → 自定义
+3. 安全设置:自定义关键词(股票、分析、智策)
+4. 复制Webhook地址
+
+#### 飞书机器人
+1. 飞书群 → 设置 → 群机器人
+2. 添加机器人 → 自定义机器人
+3. 设置名称:AI股票分析系统
+4. 复制Webhook地址
+
+### 第三步:测试通知
+
+#### 在实时监测中测试
+1. 进入"📊 实时监测"
+2. 滚动到"🔔 通知管理"
+3. 点击"📱 发送测试Webhook"
+4. 检查群消息
+
+#### 在智策中测试
+1. 进入"🎯 智策板块"
+2. 展开"⏰ 定时分析设置"
+3. 点击"🔄 立即运行一次"
+4. 分析完成后查看群消息
+
+---
+
+## 📊 消息格式
+
+### 实时监测通知(钉钉Markdown)
+
+```markdown
+### 股票监测提醒
+
+**股票代码**: 600519
+
+**股票名称**: 贵州茅台
+
+**提醒类型**: 进场提醒
+
+**提醒内容**: 股票价格 1650.00 进入进场区间
+
+**触发时间**: 2024-01-15 10:30:00
+
+---
+
+_此消息由AI股票分析系统自动发送_
+```
+
+### 智策分析通知(钉钉Markdown)
+
+```markdown
+### 智策板块分析报告
+**分析时间**: 2024-01-15 09:00
+
+#### 📊 板块多空
+**看多**: 人工智能(8分)、新能源汽车(8分)、半导体(7分)
+**看空**: 地产开发(7分)
+
+#### 🔄 潜力接力板块
+- 半导体: 关注突破信号
+- 军工: 情绪升温,把握机会
+
+#### 🌡️ 热度TOP3
+1. 人工智能 - 95分
+2. 新能源汽车 - 92分
+3. 半导体 - 88分
+
+#### 💡 核心机会
+重点关注人工智能、新能源汽车产业链,半导体板块有轮动潜力...
+
+---
+*由智策AI系统自动生成*
+```
+
+---
+
+## 🔧 技术实现
+
+### 1. Webhook API调用
+
+#### 钉钉API
+```python
+import requests
+
+data = {
+ "msgtype": "markdown",
+ "markdown": {
+ "title": "标题",
+ "text": "Markdown格式内容"
+ }
+}
+
+response = requests.post(webhook_url, json=data, timeout=10)
+result = response.json()
+success = result.get('errcode') == 0
+```
+
+#### 飞书API
+```python
+import requests
+
+data = {
+ "msg_type": "interactive", # 或 "text"
+ "card": {
+ # 交互式卡片内容
+ }
+}
+
+response = requests.post(webhook_url, json=data, timeout=10)
+result = response.json()
+success = result.get('code') == 0
+```
+
+### 2. 通知流程
+
+```
+触发条件
+ ↓
+检查配置
+ ├─ Webhook启用?
+ │ ├─ 是 → 发送Webhook
+ │ └─ 否 → 跳过
+ └─ 邮件启用?
+ ├─ 是 → 发送邮件
+ └─ 否 → 跳过
+ ↓
+记录日志
+ ├─ 成功:✓ 发送成功
+ ├─ 失败:✗ 发送失败 + 错误信息
+ └─ 跳过:⚠️ 未配置
+```
+
+### 3. 配置管理
+
+```
+.env文件
+ ↓
+config_manager读取
+ ↓
+notification_service加载
+ ↓
+实时重新加载(dotenv)
+ ↓
+Streamlit UI显示
+```
+
+---
+
+## 💡 使用场景
+
+### 场景1:日内交易团队协作
+
+**配置**:
+- 创建钉钉/飞书团队群
+- 配置Webhook推送
+- 设置实时监测
+
+**效果**:
+- 股票触发 → 群内实时通知
+- 团队讨论 → 快速决策
+- 消息记录 → 便于复盘
+
+### 场景2:每日策略推送
+
+**配置**:
+- 启用智策定时分析
+- 配置Webhook + 邮件
+- 设置每天9:00运行
+
+**效果**:
+- 9:00自动分析 → 策略报告
+- Webhook推送 → 快速查看
+- 邮件发送 → 详细存档
+
+### 场景3:个人投资提醒
+
+**配置**:
+- 创建个人钉钉/飞书群
+- 仅添加机器人
+- 配置实时监测
+
+**效果**:
+- 价格波动 → 手机通知
+- 随时随地 → 及时查看
+- 不错过 → 投资机会
+
+---
+
+## ⚠️ 注意事项
+
+### 1. 安全配置
+
+#### 钉钉关键词设置
+- **推荐**:股票、分析、智策、监测
+- 系统消息已包含关键词
+- 避免使用过于通用的词
+
+#### Webhook地址保护
+- ❌ 不要公开分享
+- ❌ 不要提交到版本控制
+- ✅ 使用环境变量管理
+- ✅ 定期更换地址
+
+### 2. 消息频率
+
+**平台限制**:
+- 钉钉:20条/分钟
+- 飞书:50条/分钟
+
+**系统控制**:
+- 实时监测:重复通知间隔60分钟
+- 智策分析:每天1次
+- 不会触发限流
+
+### 3. 网络依赖
+
+- 需要稳定网络连接
+- 超时时间:10秒
+- 失败不影响核心功能
+- 错误会记录日志
+
+### 4. 配置生效
+
+- 修改配置后需重启应用
+- 或使用"💾 保存配置"自动重载
+- 建议先测试再正式使用
+
+---
+
+## 🐛 故障排查
+
+### 问题1:未收到Webhook消息
+
+**检查清单**:
+1. ✅ `WEBHOOK_ENABLED=true`
+2. ✅ Webhook URL完整正确
+3. ✅ 网络连接正常
+4. ✅ 机器人未被移出群
+5. ✅ 钉钉关键词设置正确
+
+**解决方案**:
+```bash
+# 1. 查看系统日志
+📱 正在发送钉钉Webhook...
+✅ 钉钉Webhook发送成功
+
+# 2. 使用测试功能
+点击"📱 发送测试Webhook"
+
+# 3. 检查配置
+进入"⚙️ 环境配置" → "📢 通知配置"
+```
+
+### 问题2:钉钉关键词不匹配
+
+**错误信息**:`errcode: 310000`
+
+**解决方案**:
+- 添加关键词:股票、分析、智策
+- 系统消息已包含这些词
+- 检查是否误删关键词
+
+### 问题3:飞书消息格式异常
+
+**原因**:选择了错误的类型
+
+**解决方案**:
+- 确认选择 `feishu`
+- 重新保存配置
+- 测试验证
+
+---
+
+## 📈 功能对比
+
+| 功能 | 邮件通知 | Webhook通知 | 界面通知 |
+|------|---------|------------|----------|
+| **实时性** | 延迟1-5秒 | 即时推送 | 需打开页面 |
+| **详细度** | 完整详细 | 精简摘要 | 简单提示 |
+| **查看方式** | 邮箱APP | 钉钉/飞书 | Web界面 |
+| **历史记录** | 永久保存 | 群消息历史 | 临时显示 |
+| **团队协作** | 转发分享 | 群内讨论 | 单人查看 |
+| **移动端** | 邮箱APP | 原生APP | 浏览器 |
+| **推荐场景** | 详细存档 | 快速查看 | 即时提示 |
+
+---
+
+## 🚀 未来规划
+
+### v1.1.0 (计划中)
+- [ ] 支持多个Webhook URL
+- [ ] 企业微信机器人支持
+- [ ] Server酱推送支持
+- [ ] 消息模板自定义
+
+### v1.2.0 (规划中)
+- [ ] 消息去重和合并
+- [ ] 智能推送时段设置
+- [ ] 重要消息@提醒
+- [ ] 消息统计和分析
+
+---
+
+## 📚 相关文档
+
+- [Webhook通知配置指南.md](Webhook通知配置指南.md) - 详细配置教程
+- [环境配置功能说明.md](环境配置功能说明.md) - 完整配置说明
+- [实时监测优化说明.md](实时监测优化说明.md) - 实时监测功能
+- [智策定时分析使用指南.md](智策定时分析使用指南.md) - 智策功能
+
+---
+
+## ✅ 验证清单
+
+完成后请验证:
+
+- [ ] Python环境正常
+- [ ] requests库已安装
+- [ ] Webhook配置已保存
+- [ ] 机器人已创建
+- [ ] 测试Webhook成功
+- [ ] 收到测试消息
+- [ ] 实时监测推送正常
+- [ ] 智策分析推送正常
+- [ ] 配置界面显示正常
+
+---
+
+## 🎉 总结
+
+Webhook通知功能已全面完成,主要特点:
+
+1. **双平台支持** - 钉钉和飞书群机器人
+2. **灵活配置** - Web界面或.env文件
+3. **全面集成** - 实时监测和智策分析
+4. **可靠传输** - 错误处理和日志记录
+5. **完整文档** - 配置指南和故障排查
+
+现在您可以通过钉钉或飞书接收股票分析通知了!📱🔔
+
+---
+
+**Webhook通知功能** - v1.0.0
+
+完成时间:2025-01-15
+
diff --git a/Webhook功能实现总结.md b/Webhook功能实现总结.md
new file mode 100644
index 0000000..17577ab
--- /dev/null
+++ b/Webhook功能实现总结.md
@@ -0,0 +1,476 @@
+# Webhook功能实现总结
+
+## ✅ 任务完成状态
+
+**任务**:为实时监测和智策定时分析添加Webhook支持(钉钉/飞书),并在环境配置中支持可视化配置
+
+**状态**:✅ 全部完成
+
+**完成时间**:2025-01-15
+
+---
+
+## 📋 实现内容清单
+
+### 1. ✅ notification_service.py - Webhook核心功能
+
+**新增配置加载**:
+- `webhook_enabled` - Webhook开关
+- `webhook_url` - Webhook地址
+- `webhook_type` - Webhook类型(dingtalk/feishu)
+
+**新增方法**:
+- `_send_webhook_notification()` - Webhook通知分发器
+- `_send_dingtalk_webhook()` - 钉钉机器人发送(Markdown格式)
+- `_send_feishu_webhook()` - 飞书机器人发送(交互式卡片)
+- `send_test_webhook()` - 测试Webhook配置
+- `get_webhook_config_status()` - 获取Webhook配置状态
+
+**集成实时监测**:
+- 修改 `send_notification()` 方法
+- 支持同时发送Webhook和邮件
+- 至少一种方式成功即视为成功
+
+**代码量**:新增约250行
+
+---
+
+### 2. ✅ sector_strategy_scheduler.py - 智策Webhook集成
+
+**新增方法**:
+- `_send_webhook_direct()` - 直接发送Webhook
+- `_send_dingtalk()` - 钉钉消息发送
+- `_send_feishu()` - 飞书消息发送
+- `_format_webhook_summary()` - 格式化精简摘要
+
+**修改方法**:
+- `_send_analysis_notification()` - 支持邮件+Webhook双通道
+
+**特性**:
+- 智能精简报告(适合移动端)
+- 分别统计发送成功数
+- 完整的错误处理和日志
+
+**代码量**:新增约150行
+
+---
+
+### 3. ✅ config_manager.py - 配置管理
+
+**新增配置项(9个)**:
+
+#### 邮件配置
+- `EMAIL_ENABLED` - 邮件通知开关
+- `SMTP_SERVER` - SMTP服务器地址
+- `SMTP_PORT` - SMTP端口
+- `EMAIL_FROM` - 发件人邮箱
+- `EMAIL_PASSWORD` - 邮箱授权码
+- `EMAIL_TO` - 收件人邮箱
+
+#### Webhook配置
+- `WEBHOOK_ENABLED` - Webhook通知开关
+- `WEBHOOK_TYPE` - Webhook类型(select类型)
+- `WEBHOOK_URL` - Webhook地址
+
+**修改方法**:
+- `default_config` - 添加配置定义
+- `write_env()` - 支持写入新配置
+
+**代码量**:新增约60行
+
+---
+
+### 4. ✅ app.py - Web配置界面
+
+**新增UI组件**:
+- 第4个标签页:"📢 通知配置"
+- 左右分栏布局(邮件 | Webhook)
+- 6个邮件配置输入框
+- 3个Webhook配置组件
+
+**特性**:
+- 实时配置验证和状态提示
+- 启用开关控制输入框禁用状态
+- 完整的帮助说明和提示
+- 支持保存和实时重载
+
+**代码量**:新增约150行
+
+---
+
+### 5. ✅ 完整文档体系
+
+**新建文档(3个)**:
+
+1. **Webhook通知配置指南.md**(约600行)
+ - 平台支持说明
+ - 钉钉配置详细步骤
+ - 飞书配置详细步骤
+ - 消息格式示例
+ - 故障排查指南
+ - 使用场景推荐
+ - 最佳实践
+
+2. **Webhook功能完成说明.md**(约450行)
+ - 功能概述
+ - 完成内容
+ - 使用方法
+ - 消息格式
+ - 技术实现
+ - 故障排查
+
+3. **Webhook功能实现总结.md**(本文档)
+ - 任务清单
+ - 实现内容
+ - 测试验证
+ - 使用指南
+
+**更新文档(2个)**:
+- `环境配置功能说明.md` - 添加通知配置章节
+- `.env.example` - 添加完整配置示例(被globalIgnore阻止)
+
+---
+
+## 🧪 测试验证
+
+### 验证脚本:test_webhook.py
+
+**测试内容**:
+1. ✅ 模块导入测试(9个模块)
+2. ✅ notification_service功能测试
+3. ✅ config_manager配置测试
+4. ✅ sector_strategy_scheduler集成测试
+
+**测试结果**:
+```
+[PASS] - 导入测试 (9/9)
+[PASS] - notification_service
+[PASS] - config_manager
+[PASS] - sector_strategy_scheduler
+
+[SUCCESS] 所有测试通过!Webhook功能正常!
+```
+
+---
+
+## 🎯 功能特性
+
+### 双平台支持
+
+#### 钉钉机器人
+- ✅ Markdown格式消息
+- ✅ 关键词安全设置支持
+- ✅ 消息格式优化(移动端友好)
+- ✅ 错误码识别和处理
+
+#### 飞书机器人
+- ✅ 交互式卡片消息
+- ✅ 文本消息备选方案
+- ✅ 美观的UI展示
+- ✅ 完整的错误处理
+
+### 灵活配置
+
+#### Web界面配置
+- ✅ 可视化配置界面
+- ✅ 实时状态检查
+- ✅ 一键保存和重载
+- ✅ 完整帮助说明
+
+#### .env文件配置
+- ✅ 支持手动编辑
+- ✅ 自动读取和写入
+- ✅ 配置验证机制
+
+### 双通道通知
+
+#### 实时监测
+- ✅ Webhook即时推送
+- ✅ 邮件详细通知
+- ✅ 双通道同时发送
+- ✅ 失败自动降级
+
+#### 智策定时分析
+- ✅ Webhook精简报告
+- ✅ 邮件完整报告
+- ✅ 分别统计成功数
+- ✅ 完整错误日志
+
+---
+
+## 📊 代码统计
+
+| 模块 | 新增行数 | 修改行数 | 文件数 |
+|------|---------|---------|--------|
+| notification_service.py | ~250 | ~20 | 1 |
+| sector_strategy_scheduler.py | ~150 | ~30 | 1 |
+| config_manager.py | ~60 | ~30 | 1 |
+| app.py | ~150 | ~10 | 1 |
+| 文档 | ~1500 | ~50 | 5 |
+| **总计** | **~2110** | **~140** | **9** |
+
+---
+
+## 🔧 技术实现亮点
+
+### 1. 智能消息格式化
+
+**实时监测**:完整详细的监测信息
+```markdown
+### 股票监测提醒
+**股票代码**: 600519
+**股票名称**: 贵州茅台
+**提醒类型**: 进场提醒
+**提醒内容**: 价格进入进场区间
+**触发时间**: 2024-01-15 10:30:00
+```
+
+**智策分析**:精简版策略摘要
+```markdown
+### 智策板块分析报告
+**分析时间**: 2024-01-15 09:00
+
+#### 📊 板块多空
+**看多**: 人工智能(8分)、新能源汽车(8分)
+
+#### 🔄 潜力接力板块
+- 半导体: 关注突破信号
+
+#### 🌡️ 热度TOP3
+1. 人工智能 - 95分
+```
+
+### 2. 错误处理机制
+
+**多层异常捕获**:
+```python
+try:
+ # 1. 检查配置
+ # 2. 发送Webhook
+ # 3. 处理响应
+except Exception as e:
+ # 记录错误日志
+ # 降级到备用方案
+ # 不影响核心功能
+```
+
+**状态码识别**:
+- 钉钉:`errcode == 0` 为成功
+- 飞书:`code == 0` 为成功
+- HTTP:`status_code == 200` 为正常
+
+### 3. 配置管理优化
+
+**自动重载**:
+```python
+# 保存后自动重载环境变量
+config_manager.write_env(config)
+config_manager.reload_config()
+load_dotenv(override=True)
+```
+
+**实时验证**:
+```python
+# UI中实时检查配置完整性
+if all([smtp_server, email_from, password, email_to]):
+ st.success("✅ 邮件配置完整")
+else:
+ st.warning("⚠️ 邮件配置不完整")
+```
+
+---
+
+## 📱 使用场景
+
+### 场景1:个人日内交易监控
+
+**配置**:
+```env
+WEBHOOK_ENABLED=true
+WEBHOOK_TYPE=dingtalk
+WEBHOOK_URL=https://oapi.dingtalk.com/...
+```
+
+**效果**:
+- 股票触发 → 钉钉通知
+- 手机查看 → 快速决策
+- 不错过 → 投资机会
+
+### 场景2:团队策略协作
+
+**配置**:
+```env
+EMAIL_ENABLED=true
+EMAIL_TO=team@company.com
+
+WEBHOOK_ENABLED=true
+WEBHOOK_TYPE=feishu
+WEBHOOK_URL=https://open.feishu.cn/...
+```
+
+**效果**:
+- 每日9:00自动分析
+- 飞书群实时推送
+- 团队讨论决策
+- 邮件详细存档
+
+### 场景3:多账户管理
+
+**配置**:
+- 账户A:仅Webhook(快速查看)
+- 账户B:Webhook + 邮件(完整记录)
+- 账户C:仅邮件(详细分析)
+
+---
+
+## 🎓 最佳实践
+
+### 1. 消息分类
+
+| 消息类型 | Webhook | 邮件 | 说明 |
+|---------|---------|------|------|
+| 紧急提醒 | ✅ | ✅ | 双通道保障 |
+| 日常分析 | ✅ | ❌ | 快速查看 |
+| 详细报告 | ❌ | ✅ | 完整存档 |
+
+### 2. 时段设置
+
+- **交易时段**(9:30-15:00):启用Webhook
+- **非交易时段**:降低通知频率
+- **休市日**:可关闭Webhook
+
+### 3. 群组管理
+
+- **交易群**:实时监测通知
+- **策略群**:智策分析报告
+- **个人群**:所有通知汇总
+
+---
+
+## ⚠️ 注意事项
+
+### 1. 安全性
+
+- ❌ 不要公开分享Webhook URL
+- ❌ 不要提交到版本控制
+- ✅ 使用环境变量管理
+- ✅ 定期更换地址
+
+### 2. 频率限制
+
+- 钉钉:20条/分钟
+- 飞书:50条/分钟
+- 系统已自动控制(不会超限)
+
+### 3. 关键词设置(钉钉)
+
+系统消息包含的关键词:
+- 股票、分析、智策
+- 监测、提醒、报告
+
+建议配置至少一个。
+
+---
+
+## 🚀 未来扩展
+
+### v1.1.0(规划中)
+- [ ] 支持多个Webhook URL
+- [ ] 企业微信机器人
+- [ ] Server酱推送
+- [ ] 消息模板自定义
+
+### v1.2.0(规划中)
+- [ ] 消息优先级分级
+- [ ] 智能推送时段
+- [ ] 消息去重合并
+- [ ] @指定成员提醒
+
+---
+
+## 📚 相关文档索引
+
+### 配置指南
+- [Webhook通知配置指南.md](Webhook通知配置指南.md) - 完整配置教程
+- [环境配置功能说明.md](环境配置功能说明.md) - 环境配置总览
+
+### 功能说明
+- [Webhook功能完成说明.md](Webhook功能完成说明.md) - 功能详细说明
+- [实时监测优化说明.md](实时监测优化说明.md) - 实时监测功能
+- [智策定时分析使用指南.md](智策定时分析使用指南.md) - 智策功能
+
+### 其他
+- [test_webhook.py](test_webhook.py) - 功能验证脚本
+
+---
+
+## ✅ 验证清单
+
+部署后请确认:
+
+- [x] Python环境正常(Python 3.8+)
+- [x] requests库已安装
+- [x] 所有模块可正常导入
+- [x] notification_service包含Webhook方法
+- [x] config_manager包含Webhook配置
+- [x] sector_strategy_scheduler集成Webhook
+- [x] app.py包含通知配置UI
+- [x] 测试脚本全部通过
+- [ ] 创建钉钉/飞书机器人
+- [ ] 配置Webhook URL
+- [ ] 测试Webhook发送
+- [ ] 验证实时监测通知
+- [ ] 验证智策分析通知
+
+---
+
+## 🎉 总结
+
+### 完成的工作
+
+1. **核心功能** ✅
+ - Webhook发送(钉钉+飞书)
+ - 智策定时分析集成
+ - 实时监测集成
+
+2. **配置管理** ✅
+ - Web可视化配置
+ - .env文件支持
+ - 配置验证机制
+
+3. **文档完善** ✅
+ - 3个新建文档(~1500行)
+ - 2个更新文档
+ - 完整使用指南
+
+4. **测试验证** ✅
+ - 验证脚本
+ - 全部测试通过
+ - 功能正常运行
+
+### 技术亮点
+
+- 🎯 **双平台支持** - 钉钉和飞书
+- 🔧 **灵活配置** - Web界面+文件编辑
+- 📱 **移动友好** - 精简消息格式
+- 🔄 **双通道** - Webhook+邮件同时支持
+- ⚡ **高性能** - 异步处理,不阻塞
+- 🛡️ **高可靠** - 完整错误处理
+
+### 使用价值
+
+- 💰 **降低成本** - 免费推送,无需付费服务
+- ⏱️ **提高效率** - 即时通知,快速响应
+- 👥 **团队协作** - 群组通知,统一决策
+- 📈 **投资助力** - 不错过机会,及时止损
+
+---
+
+**Webhook功能** - v1.0.0
+**完成时间**:2025-01-15
+**代码量**:~2250行
+**文档量**:~2000行
+**测试**:✅ 全部通过
+
+🎉 功能已完整实现并通过验证!
+
diff --git a/Webhook自定义关键词功能说明.md b/Webhook自定义关键词功能说明.md
new file mode 100644
index 0000000..08ff578
--- /dev/null
+++ b/Webhook自定义关键词功能说明.md
@@ -0,0 +1,251 @@
+# Webhook自定义关键词功能说明
+
+## 功能概述
+
+系统现已支持自定义Webhook关键词配置,用户可以根据自己的钉钉/飞书机器人安全设置灵活配置关键词。
+
+## 配置方法
+
+### 1. 在.env文件中配置
+
+```env
+# ========== Webhook通知配置(可选)==========
+WEBHOOK_ENABLED="true"
+WEBHOOK_TYPE="dingtalk"
+WEBHOOK_URL="https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN"
+WEBHOOK_KEYWORD="aiagents通知"
+```
+
+### 2. 配置说明
+
+| 配置项 | 说明 | 示例 |
+|-------|------|------|
+| WEBHOOK_ENABLED | 是否启用Webhook | true / false |
+| WEBHOOK_TYPE | Webhook类型 | dingtalk(钉钉)/ feishu(飞书)|
+| WEBHOOK_URL | Webhook地址 | 机器人Webhook完整URL |
+| WEBHOOK_KEYWORD | 自定义关键词 | aiagents通知(或您机器人设置的任何关键词)|
+
+## 钉钉机器人关键词设置
+
+### 步骤1:创建钉钉自定义机器人
+1. 打开钉钉群聊
+2. 点击右上角"..." → 机器人 → 添加机器人
+3. 选择"自定义"机器人
+
+### 步骤2:安全设置
+1. 安全设置选择:**自定义关键词**
+2. 输入关键词:**aiagents通知**(或您自己定义的关键词)
+3. 复制Webhook地址
+
+
+
+### 步骤3:配置到系统
+将关键词和Webhook地址配置到`.env`文件中:
+
+```env
+WEBHOOK_KEYWORD="aiagents通知"
+WEBHOOK_URL="https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN"
+```
+
+**重要提示**:
+- `.env`文件中的关键词必须与钉钉机器人设置的关键词完全一致
+- 如果不匹配,消息将发送失败
+- 如果关键词为空,则不会在消息中添加关键词前缀
+
+## 飞书机器人配置
+
+飞书机器人通常不需要关键词,可以将WEBHOOK_KEYWORD留空或使用默认值:
+
+```env
+WEBHOOK_TYPE="feishu"
+WEBHOOK_KEYWORD=""
+```
+
+## 消息格式
+
+### 钉钉消息示例
+
+**有关键词时:**
+```markdown
+标题:aiagents通知 - 000001 平安银行
+
+### aiagents通知 - 股票监测提醒
+
+**股票代码**: 000001
+**股票名称**: 平安银行
+...
+```
+
+**无关键词时:**
+```markdown
+标题:000001 平安银行
+
+### 股票监测提醒
+
+**股票代码**: 000001
+**股票名称**: 平安银行
+...
+```
+
+## 测试配置
+
+配置完成后,运行测试工具验证:
+
+```bash
+# Windows
+.\venv\Scripts\python.exe test_notification_config.py
+
+# Linux/Mac
+python test_notification_config.py
+```
+
+**成功输出示例:**
+```
+============================================================
+[Webhook] 测试Webhook配置
+============================================================
+
+当前配置:
+ - 启用状态: [已启用]
+ - Webhook类型: dingtalk
+ - 配置完整性: [完整]
+
+[钉钉] 正在发送Webhook...
+[成功] 钉钉Webhook发送成功
+[成功] 钉钉Webhook测试成功!请检查钉钉群消息。
+```
+
+## 常见问题
+
+### Q1: 提示"关键词不匹配"
+
+**原因**:
+- .env文件中的WEBHOOK_KEYWORD与钉钉机器人设置不一致
+- .env文件编码问题导致关键词乱码
+
+**解决方案**:
+1. 检查钉钉机器人的关键词设置
+2. 确保.env文件使用UTF-8编码
+3. 运行`fix_env.py`重新生成.env文件:
+ ```bash
+ python fix_env.py
+ ```
+
+### Q2: .env文件中文显示乱码
+
+**原因**:
+文件编码不是UTF-8
+
+**解决方案**:
+运行修复脚本:
+```bash
+python fix_env.py
+```
+
+### Q3: 如何修改关键词
+
+**方法1:直接编辑.env文件**
+1. 用支持UTF-8的编辑器(VS Code、Notepad++等)打开.env
+2. 修改WEBHOOK_KEYWORD的值
+3. 保存为UTF-8编码
+
+**方法2:使用环境配置界面**
+1. 启动应用
+2. 进入"环境配置"页面
+3. 修改"Webhook自定义关键词"
+4. 保存配置
+
+**方法3:使用配置管理器**
+```python
+from config_manager import config_manager
+
+# 读取当前配置
+config = config_manager.read_env()
+
+# 修改关键词
+config['WEBHOOK_KEYWORD'] = '您的新关键词'
+
+# 保存配置
+config_manager.write_env(config)
+```
+
+### Q4: 是否可以不使用关键词
+
+**可以!**
+
+如果您的钉钉机器人使用其他安全方式(如加签、IP白名单),可以将关键词设为空:
+
+```env
+WEBHOOK_KEYWORD=""
+```
+
+系统会自动检测,如果关键词为空,则不会在消息中添加关键词前缀。
+
+## 更新日志
+
+### v1.1 (2025-10-14)
+- ✅ 新增WEBHOOK_KEYWORD配置项
+- ✅ 支持自定义关键词
+- ✅ 修复.env文件中文编码问题
+- ✅ 优化消息格式,去除多余空格
+- ✅ 提供fix_env.py工具修复编码问题
+
+### v1.0 (2025-10-14)
+- ✅ 初始版本
+- ✅ 硬编码"aiagents通知"关键词
+
+## 相关文件
+
+- `.env` - 环境配置文件
+- `.env.example` - 配置模板
+- `fix_env.py` - 编码修复工具
+- `config_manager.py` - 配置管理模块
+- `notification_service.py` - 通知服务模块
+- `sector_strategy_scheduler.py` - 定时任务模块
+- `test_notification_config.py` - 测试工具
+
+## 技术实现
+
+### 配置读取流程
+
+```python
+# 1. 从环境变量读取
+import os
+from dotenv import load_dotenv
+load_dotenv()
+keyword = os.getenv('WEBHOOK_KEYWORD', 'aiagents通知')
+
+# 2. 在notification_service中使用
+class NotificationService:
+ def _load_config(self):
+ config['webhook_keyword'] = os.getenv('WEBHOOK_KEYWORD')
+
+ def _send_dingtalk_webhook(self, notification):
+ keyword = self.config.get('webhook_keyword', '')
+ title_prefix = f"{keyword} - " if keyword else ""
+ # ...构建消息
+```
+
+### 消息构建逻辑
+
+```python
+# 如果有关键词
+if keyword:
+ title = f"{keyword} - {notification['symbol']} {notification['name']}"
+ text = f"### {keyword} - 股票监测提醒\n..."
+else:
+ title = f"{notification['symbol']} {notification['name']}"
+ text = f"### 股票监测提醒\n..."
+```
+
+## 总结
+
+现在系统完全支持自定义Webhook关键词,用户可以根据自己的需求灵活配置:
+
+✅ **灵活性**:支持任意自定义关键词
+✅ **兼容性**:支持钉钉和飞书
+✅ **易用性**:简单配置即可使用
+✅ **稳定性**:自动处理编码问题
+
+祝您使用愉快!
+
diff --git a/Webhook通知配置指南.md b/Webhook通知配置指南.md
new file mode 100644
index 0000000..76b655e
--- /dev/null
+++ b/Webhook通知配置指南.md
@@ -0,0 +1,444 @@
+# Webhook通知配置指南
+
+## 📱 功能概述
+
+系统支持通过Webhook将通知推送到钉钉或飞书群,适用于:
+- **实时监测**:股票价格触发提醒
+- **智策定时分析**:板块策略分析报告
+
+可与邮件通知同时使用,也可单独使用。
+
+---
+
+## 🎯 支持的平台
+
+### 1. 钉钉群机器人
+- ✅ 支持Markdown格式
+- ✅ 消息样式丰富
+- ✅ 配置简单
+- ✅ 免费使用
+
+### 2. 飞书群机器人
+- ✅ 支持交互式卡片
+- ✅ 消息展示美观
+- ✅ 支持文本和富文本
+- ✅ 免费使用
+
+---
+
+## 📝 配置步骤
+
+### 方法一:通过Web界面配置(推荐)
+
+1. **进入配置页面**
+ - 点击侧边栏"⚙️ 环境配置"
+ - 选择"📢 通知配置"标签页
+
+2. **配置Webhook**
+ - 勾选"启用Webhook通知"
+ - 选择Webhook类型(钉钉/飞书)
+ - 填写Webhook URL
+ - 点击"💾 保存配置"
+
+3. **测试配置**
+ - 在实时监测的"通知管理"中
+ - 点击"测试Webhook"按钮
+ - 检查群消息是否收到
+
+### 方法二:手动编辑.env文件
+
+```env
+# Webhook通知配置
+WEBHOOK_ENABLED=true
+WEBHOOK_TYPE=dingtalk # 或 feishu
+WEBHOOK_URL=https://oapi.dingtalk.com/robot/send?access_token=xxxxx
+```
+
+---
+
+## 🔧 钉钉机器人配置
+
+### 步骤1:创建群机器人
+
+1. 打开钉钉PC端或移动端
+2. 进入要接收通知的群聊
+3. 点击右上角"⚙️"进入群设置
+4. 选择"智能群助手" → "添加机器人"
+5. 选择"自定义"机器人
+
+### 步骤2:配置机器人
+
+1. **机器人名称**:AI股票分析系统
+2. **安全设置**(选择一种即可):
+ - ✅ **推荐**:自定义关键词(例如:股票、分析、智策)
+ - 加签(需要额外配置)
+ - IP地址段(需要固定IP)
+
+### 步骤3:获取Webhook地址
+
+完成配置后,会显示Webhook地址:
+```
+https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxxxxxxxxxx
+```
+
+复制整个地址到系统配置中。
+
+### 钉钉消息格式示例
+
+**实时监测通知**:
+```markdown
+### 股票监测提醒
+
+**股票代码**: 600519
+
+**股票名称**: 贵州茅台
+
+**提醒类型**: 进场提醒
+
+**提醒内容**: 股票价格 1650.00 进入进场区间
+
+**触发时间**: 2024-01-15 10:30:00
+
+---
+
+_此消息由AI股票分析系统自动发送_
+```
+
+**智策定时分析**:
+```markdown
+### 智策板块分析报告
+**分析时间**: 2024-01-15 09:00
+
+#### 📊 板块多空
+**看多**: 人工智能(8分)、新能源汽车(8分)、半导体(7分)
+**看空**: 地产开发(7分)
+
+#### 🔄 潜力接力板块
+- 半导体: 关注突破信号
+- 军工: 情绪升温,把握机会
+
+#### 🌡️ 热度TOP3
+1. 人工智能 - 95分
+2. 新能源汽车 - 92分
+3. 半导体 - 88分
+
+#### 💡 核心机会
+重点关注人工智能、新能源汽车产业链...
+
+---
+*由智策AI系统自动生成*
+```
+
+---
+
+## 🚀 飞书机器人配置
+
+### 步骤1:创建群机器人
+
+1. 打开飞书PC端或移动端
+2. 进入要接收通知的群聊
+3. 点击右上角"⚙️"进入群设置
+4. 选择"群机器人" → "添加机器人"
+5. 选择"自定义机器人"
+
+### 步骤2:配置机器人
+
+1. **机器人名称**:AI股票分析系统
+2. **机器人描述**:股票监测和板块分析通知
+3. **安全设置**(可选):
+ - 签名验证(需要额外配置)
+
+### 步骤3:获取Webhook地址
+
+完成配置后,会显示Webhook地址:
+```
+https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxxxxxxxxxx
+```
+
+复制整个地址到系统配置中。
+
+### 飞书消息格式示例
+
+**实时监测通知**:
+```
+📊 股票监测提醒 - 600519
+
+股票代码 股票名称
+600519 贵州茅台
+
+提醒类型 触发时间
+进场提醒 2024-01-15 10:30:00
+
+提醒内容
+股票价格 1650.00 进入进场区间
+
+---
+此消息由AI股票分析系统自动发送
+```
+
+**智策定时分析**:
+```
+【智策板块分析报告】
+分析时间: 2024-01-15 09:00
+
+### 智策板块分析报告
+**分析时间**: 2024-01-15 09:00
+
+#### 📊 板块多空
+**看多**: 人工智能(8分)、新能源汽车(8分)
+**看空**: 地产开发(7分)
+
+#### 🔄 潜力接力板块
+- 半导体: 关注突破信号
+
+#### 🌡️ 热度TOP3
+1. 人工智能 - 95分
+2. 新能源汽车 - 92分
+3. 半导体 - 88分
+
+---
+*由智策AI系统自动生成*
+```
+
+---
+
+## ⚙️ 配置说明
+
+### 环境变量
+
+| 变量名 | 说明 | 示例值 |
+|-------|------|--------|
+| `WEBHOOK_ENABLED` | 是否启用Webhook | `true` 或 `false` |
+| `WEBHOOK_TYPE` | Webhook类型 | `dingtalk` 或 `feishu` |
+| `WEBHOOK_URL` | Webhook地址 | 完整的机器人Webhook URL |
+
+### 配置检查
+
+系统会自动检查配置状态:
+- ✅ **配置完整**:显示绿色提示
+- ⚠️ **配置不完整**:显示黄色警告
+- ℹ️ **未启用**:显示蓝色信息
+
+---
+
+## 🧪 测试Webhook
+
+### 在实时监测模块测试
+
+1. 进入"📊 实时监测"页面
+2. 滚动到"🔔 通知管理"区域
+3. 点击"📱 发送测试Webhook"按钮
+4. 检查钉钉/飞书群是否收到消息
+
+### 测试消息内容
+
+```
+股票代码: 测试
+股票名称: Webhook测试
+提醒类型: 测试消息
+提醒内容: 如果您收到此消息,说明Webhook配置正确!
+触发时间: 刚刚
+```
+
+---
+
+## 🔄 同时使用邮件和Webhook
+
+系统支持同时启用邮件和Webhook通知:
+
+```env
+# 邮件通知
+EMAIL_ENABLED=true
+SMTP_SERVER=smtp.qq.com
+EMAIL_FROM=your-email@qq.com
+EMAIL_PASSWORD=authorization-code
+EMAIL_TO=recipient@qq.com
+
+# Webhook通知
+WEBHOOK_ENABLED=true
+WEBHOOK_TYPE=dingtalk
+WEBHOOK_URL=https://oapi.dingtalk.com/robot/send?access_token=xxxxx
+```
+
+**优势**:
+- 📧 邮件:详细完整,适合深度阅读
+- 📱 Webhook:即时推送,适合快速查看
+- 🔔 双重保障:确保不错过重要通知
+
+---
+
+## ⚠️ 注意事项
+
+### 1. 钉钉安全设置
+
+如果选择"自定义关键词",确保消息中包含关键词:
+- **推荐关键词**:股票、分析、智策、监测、提醒
+- 系统消息已包含这些关键词,无需额外配置
+
+### 2. 消息频率限制
+
+- **钉钉**:每个机器人每分钟最多20条消息
+- **飞书**:每个机器人每分钟最多50条消息
+- 系统会自动控制发送频率,避免超限
+
+### 3. Webhook地址安全
+
+- ❌ 不要在公开场合分享Webhook URL
+- ❌ 不要提交到版本控制系统
+- ✅ 使用环境变量或配置文件管理
+- ✅ 定期更换Webhook地址
+
+### 4. 消息格式
+
+- **钉钉**:支持Markdown格式
+- **飞书**:支持文本和交互式卡片
+- 系统会自动根据平台类型格式化消息
+
+---
+
+## 🛠️ 故障排查
+
+### 问题1:未收到Webhook消息
+
+**检查项**:
+1. ✅ Webhook是否已启用(`WEBHOOK_ENABLED=true`)
+2. ✅ Webhook URL是否正确
+3. ✅ 网络连接是否正常
+4. ✅ 机器人是否被移出群聊
+5. ✅ 钉钉关键词安全设置是否正确
+
+**解决方案**:
+- 使用"测试Webhook"功能验证配置
+- 检查系统日志查看错误信息
+- 重新创建机器人并更新URL
+
+### 问题2:Webhook发送失败
+
+**常见错误**:
+
+| 错误信息 | 原因 | 解决方案 |
+|---------|------|---------|
+| `errcode: 310000` | 关键词不匹配 | 添加"股票"或"分析"到关键词 |
+| `Connection timeout` | 网络超时 | 检查网络连接 |
+| `Invalid URL` | URL格式错误 | 检查URL完整性 |
+
+**日志查看**:
+系统会在终端输出详细日志:
+```
+📱 正在发送钉钉Webhook...
+ - URL: https://oapi.dingtalk.com...
+✅ 钉钉Webhook发送成功
+```
+
+### 问题3:消息格式异常
+
+**现象**:消息显示不正确或乱码
+
+**解决方案**:
+- 确认选择了正确的Webhook类型(钉钉/飞书)
+- 检查系统编码设置为UTF-8
+- 尝试重新保存配置
+
+---
+
+## 📊 使用场景
+
+### 场景1:日内交易监控
+
+**配置**:
+- 启用实时监测 ✅
+- 启用Webhook通知 ✅
+- 设置进场区间、止盈止损 ✅
+
+**效果**:
+- 股票价格变动 → 钉钉/飞书实时提醒
+- 手机随时查看 → 及时做出决策
+- 双重保障 → 不错过交易机会
+
+### 场景2:每日策略推送
+
+**配置**:
+- 启用智策定时分析 ✅
+- 设置每天9:00运行 ✅
+- 启用Webhook通知 ✅
+
+**效果**:
+- 每天9:00自动分析 → 板块策略报告
+- 推送到钉钉/飞书群 → 团队成员查看
+- 邮件同步发送 → 详细报告留存
+
+### 场景3:团队协作
+
+**配置**:
+- 将机器人添加到团队群 ✅
+- 配置Webhook URL ✅
+- 多人共享通知 ✅
+
+**效果**:
+- 团队成员实时接收 → 投资信息同步
+- 群内讨论决策 → 提高协作效率
+- 历史消息可查 → 便于复盘总结
+
+---
+
+## 🎓 最佳实践
+
+### 1. 消息分级
+
+**重要通知** → Webhook + 邮件:
+- 进场/止盈/止损提醒
+- 智策定时分析报告
+
+**一般通知** → 仅Webhook:
+- 价格波动提醒
+- 系统状态更新
+
+### 2. 多群分发
+
+创建多个机器人,分别推送:
+- **交易群**:实时监测提醒
+- **研究群**:智策分析报告
+- **个人**:所有通知
+
+### 3. 消息过滤
+
+利用钉钉/飞书的消息筛选功能:
+- 设置关键词提醒
+- 静音非关键时段
+- 重要消息置顶
+
+---
+
+## 📚 相关文档
+
+- [环境配置功能说明.md](环境配置功能说明.md) - 完整配置指南
+- [实时监测优化说明.md](实时监测优化说明.md) - 实时监测功能
+- [智策定时分析使用指南.md](智策定时分析使用指南.md) - 智策定时功能
+- [邮件配置指南.md](邮件配置指南.md) - 邮件通知配置
+
+---
+
+## ❓ 常见问题
+
+**Q: 可以同时配置多个Webhook吗?**
+A: 当前版本只支持一个Webhook URL。如需多群推送,建议使用钉钉/飞书的消息转发功能。
+
+**Q: Webhook和邮件应该选哪个?**
+A: 建议同时使用。Webhook适合实时查看,邮件适合详细阅读和存档。
+
+**Q: 消息发送失败会影响系统吗?**
+A: 不会。Webhook发送失败不影响核心功能,系统会记录日志并继续运行。
+
+**Q: 如何更换Webhook URL?**
+A: 在环境配置中修改`WEBHOOK_URL`,保存后重启应用即可。
+
+**Q: 钉钉和飞书哪个更好?**
+A: 各有优势。钉钉Markdown渲染好,飞书卡片更美观。选择团队常用的即可。
+
+---
+
+**Webhook通知配置指南** - 让通知更及时 📱🔔
+
+版本:v1.0
+更新时间:2025-01-15
+
diff --git a/app.py b/app.py
index e560555..a5e34cb 100644
--- a/app.py
+++ b/app.py
@@ -1957,7 +1957,7 @@ def display_config_manager():
config_info = config_manager.get_config_info()
# 创建标签页
- tab1, tab2, tab3 = st.tabs(["📝 基本配置", "📊 数据源配置", "🤖 量化交易配置"])
+ tab1, tab2, tab3, tab4 = st.tabs(["📝 基本配置", "📊 数据源配置", "🤖 量化交易配置", "📢 通知配置"])
# 使用session_state保存临时配置
if 'temp_config' not in st.session_state:
@@ -2087,6 +2087,160 @@ def display_config_manager():
st.warning("⚠️ 警告:量化交易涉及真实资金操作,请谨慎配置和使用!")
+ with tab4:
+ st.markdown("### 通知配置")
+ st.markdown("配置邮件和Webhook通知,用于实时监测和智策定时分析的提醒。")
+
+ # 创建两列布局
+ col_email, col_webhook = st.columns(2)
+
+ with col_email:
+ st.markdown("#### 📧 邮件通知")
+
+ # 邮件启用开关
+ email_enabled_info = config_info.get("EMAIL_ENABLED", {"value": "false"})
+ current_email_enabled = st.session_state.temp_config.get("EMAIL_ENABLED", "false") == "true"
+
+ new_email_enabled = st.checkbox(
+ "启用邮件通知",
+ value=current_email_enabled,
+ help="开启后可以接收邮件提醒",
+ key="input_email_enabled"
+ )
+ st.session_state.temp_config["EMAIL_ENABLED"] = "true" if new_email_enabled else "false"
+
+ # SMTP服务器
+ smtp_server_info = config_info.get("SMTP_SERVER", {"description": "SMTP服务器地址", "value": ""})
+ current_smtp_server = st.session_state.temp_config.get("SMTP_SERVER", "")
+
+ new_smtp_server = st.text_input(
+ f"📮 {smtp_server_info['description']}",
+ value=current_smtp_server,
+ disabled=not new_email_enabled,
+ placeholder="smtp.qq.com",
+ key="input_smtp_server"
+ )
+ st.session_state.temp_config["SMTP_SERVER"] = new_smtp_server
+
+ # SMTP端口
+ smtp_port_info = config_info.get("SMTP_PORT", {"description": "SMTP端口", "value": "587"})
+ current_smtp_port = st.session_state.temp_config.get("SMTP_PORT", "587")
+
+ new_smtp_port = st.text_input(
+ f"🔌 {smtp_port_info['description']}",
+ value=current_smtp_port,
+ disabled=not new_email_enabled,
+ placeholder="587 (TLS) 或 465 (SSL)",
+ key="input_smtp_port"
+ )
+ st.session_state.temp_config["SMTP_PORT"] = new_smtp_port
+
+ # 发件人邮箱
+ email_from_info = config_info.get("EMAIL_FROM", {"description": "发件人邮箱", "value": ""})
+ current_email_from = st.session_state.temp_config.get("EMAIL_FROM", "")
+
+ new_email_from = st.text_input(
+ f"📤 {email_from_info['description']}",
+ value=current_email_from,
+ disabled=not new_email_enabled,
+ placeholder="your-email@qq.com",
+ key="input_email_from"
+ )
+ st.session_state.temp_config["EMAIL_FROM"] = new_email_from
+
+ # 邮箱授权码
+ email_password_info = config_info.get("EMAIL_PASSWORD", {"description": "邮箱授权码", "value": ""})
+ current_email_password = st.session_state.temp_config.get("EMAIL_PASSWORD", "")
+
+ new_email_password = st.text_input(
+ f"🔐 {email_password_info['description']}",
+ value=current_email_password,
+ type="password",
+ disabled=not new_email_enabled,
+ help="不是邮箱登录密码,而是SMTP授权码",
+ key="input_email_password"
+ )
+ st.session_state.temp_config["EMAIL_PASSWORD"] = new_email_password
+
+ # 收件人邮箱
+ email_to_info = config_info.get("EMAIL_TO", {"description": "收件人邮箱", "value": ""})
+ current_email_to = st.session_state.temp_config.get("EMAIL_TO", "")
+
+ new_email_to = st.text_input(
+ f"📥 {email_to_info['description']}",
+ value=current_email_to,
+ disabled=not new_email_enabled,
+ placeholder="receiver@qq.com",
+ key="input_email_to"
+ )
+ st.session_state.temp_config["EMAIL_TO"] = new_email_to
+
+ if new_email_enabled and all([new_smtp_server, new_email_from, new_email_password, new_email_to]):
+ st.success("✅ 邮件配置完整")
+ elif new_email_enabled:
+ st.warning("⚠️ 邮件配置不完整")
+ else:
+ st.info("ℹ️ 邮件通知未启用")
+
+ st.caption("💡 QQ邮箱授权码获取:设置 → 账户 → POP3/IMAP/SMTP → 生成授权码")
+
+ with col_webhook:
+ st.markdown("#### 📱 Webhook通知")
+
+ # Webhook启用开关
+ webhook_enabled_info = config_info.get("WEBHOOK_ENABLED", {"value": "false"})
+ current_webhook_enabled = st.session_state.temp_config.get("WEBHOOK_ENABLED", "false") == "true"
+
+ new_webhook_enabled = st.checkbox(
+ "启用Webhook通知",
+ value=current_webhook_enabled,
+ help="开启后可以发送到钉钉或飞书群",
+ key="input_webhook_enabled"
+ )
+ st.session_state.temp_config["WEBHOOK_ENABLED"] = "true" if new_webhook_enabled else "false"
+
+ # Webhook类型选择
+ webhook_type_info = config_info.get("WEBHOOK_TYPE", {"description": "Webhook类型", "value": "dingtalk", "options": ["dingtalk", "feishu"]})
+ current_webhook_type = st.session_state.temp_config.get("WEBHOOK_TYPE", "dingtalk")
+
+ new_webhook_type = st.selectbox(
+ f"📲 {webhook_type_info['description']}",
+ options=webhook_type_info.get('options', ["dingtalk", "feishu"]),
+ index=0 if current_webhook_type == "dingtalk" else 1,
+ disabled=not new_webhook_enabled,
+ key="input_webhook_type"
+ )
+ st.session_state.temp_config["WEBHOOK_TYPE"] = new_webhook_type
+
+ # Webhook URL
+ webhook_url_info = config_info.get("WEBHOOK_URL", {"description": "Webhook地址", "value": ""})
+ current_webhook_url = st.session_state.temp_config.get("WEBHOOK_URL", "")
+
+ new_webhook_url = st.text_input(
+ f"🔗 {webhook_url_info['description']}",
+ value=current_webhook_url,
+ disabled=not new_webhook_enabled,
+ placeholder="https://oapi.dingtalk.com/robot/send?access_token=...",
+ key="input_webhook_url"
+ )
+ st.session_state.temp_config["WEBHOOK_URL"] = new_webhook_url
+
+ if new_webhook_enabled and new_webhook_url:
+ st.success(f"✅ Webhook配置完整 ({new_webhook_type})")
+ elif new_webhook_enabled:
+ st.warning("⚠️ 请配置Webhook URL")
+ else:
+ st.info("ℹ️ Webhook通知未启用")
+
+ # 显示帮助信息
+ if new_webhook_type == "dingtalk":
+ st.caption("💡 钉钉机器人配置:\n1. 进入钉钉群 → 设置 → 智能群助手\n2. 添加机器人 → 自定义\n3. 复制Webhook地址")
+ else:
+ st.caption("💡 飞书机器人配置:\n1. 进入飞书群 → 设置 → 群机器人\n2. 添加机器人 → 自定义机器人\n3. 复制Webhook地址")
+
+ st.markdown("---")
+ st.info("💡 **使用说明**:\n- 可以同时启用邮件和Webhook通知\n- 实时监测和智策定时分析都会使用配置的通知方式\n- 配置后建议使用各功能中的测试按钮验证通知是否正常")
+
# 操作按钮
st.markdown("---")
col1, col2, col3, col4 = st.columns([1, 1, 1, 2])
@@ -2151,6 +2305,19 @@ MINIQMT_ENABLED="{current_config.get('MINIQMT_ENABLED', 'false')}"
MINIQMT_ACCOUNT_ID="{current_config.get('MINIQMT_ACCOUNT_ID', '')}"
MINIQMT_HOST="{current_config.get('MINIQMT_HOST', '127.0.0.1')}"
MINIQMT_PORT="{current_config.get('MINIQMT_PORT', '58610')}"
+
+# ========== 邮件通知配置(可选)==========
+EMAIL_ENABLED="{current_config.get('EMAIL_ENABLED', 'false')}"
+SMTP_SERVER="{current_config.get('SMTP_SERVER', '')}"
+SMTP_PORT="{current_config.get('SMTP_PORT', '587')}"
+EMAIL_FROM="{current_config.get('EMAIL_FROM', '')}"
+EMAIL_PASSWORD="{current_config.get('EMAIL_PASSWORD', '')}"
+EMAIL_TO="{current_config.get('EMAIL_TO', '')}"
+
+# ========== Webhook通知配置(可选)==========
+WEBHOOK_ENABLED="{current_config.get('WEBHOOK_ENABLED', 'false')}"
+WEBHOOK_TYPE="{current_config.get('WEBHOOK_TYPE', 'dingtalk')}"
+WEBHOOK_URL="{current_config.get('WEBHOOK_URL', '')}"
""", language="bash")
def display_batch_analysis_results(results, period):
diff --git a/config_manager.py b/config_manager.py
index 47c6304..99b9495 100644
--- a/config_manager.py
+++ b/config_manager.py
@@ -56,6 +56,67 @@ class ConfigManager:
"required": False,
"type": "text"
},
+ "EMAIL_ENABLED": {
+ "value": "false",
+ "description": "启用邮件通知",
+ "required": False,
+ "type": "boolean"
+ },
+ "SMTP_SERVER": {
+ "value": "",
+ "description": "SMTP服务器地址",
+ "required": False,
+ "type": "text"
+ },
+ "SMTP_PORT": {
+ "value": "587",
+ "description": "SMTP服务器端口",
+ "required": False,
+ "type": "text"
+ },
+ "EMAIL_FROM": {
+ "value": "",
+ "description": "发件人邮箱",
+ "required": False,
+ "type": "text"
+ },
+ "EMAIL_PASSWORD": {
+ "value": "",
+ "description": "邮箱授权码",
+ "required": False,
+ "type": "password"
+ },
+ "EMAIL_TO": {
+ "value": "",
+ "description": "收件人邮箱",
+ "required": False,
+ "type": "text"
+ },
+ "WEBHOOK_ENABLED": {
+ "value": "false",
+ "description": "启用Webhook通知",
+ "required": False,
+ "type": "boolean"
+ },
+ "WEBHOOK_TYPE": {
+ "value": "dingtalk",
+ "description": "Webhook类型(dingtalk/feishu)",
+ "required": False,
+ "type": "select",
+ "options": ["dingtalk", "feishu"]
+ },
+ "WEBHOOK_URL": {
+ "value": "",
+ "description": "Webhook地址",
+ "required": False,
+ "type": "text"
+ },
+ "WEBHOOK_KEYWORD": {
+ "value": "aiagents通知",
+ "description": "Webhook自定义关键词(钉钉安全验证)",
+ "required": False,
+ "type": "text"
+ },
}
def read_env(self) -> Dict[str, str]:
@@ -124,6 +185,24 @@ class ConfigManager:
lines.append(f'MINIQMT_ACCOUNT_ID="{config.get("MINIQMT_ACCOUNT_ID", "")}"')
lines.append(f'MINIQMT_HOST="{config.get("MINIQMT_HOST", "127.0.0.1")}"')
lines.append(f'MINIQMT_PORT="{config.get("MINIQMT_PORT", "58610")}"')
+ lines.append("")
+
+ # 邮件通知配置
+ lines.append("# ========== 邮件通知配置(可选)==========")
+ lines.append(f'EMAIL_ENABLED="{config.get("EMAIL_ENABLED", "false")}"')
+ lines.append(f'SMTP_SERVER="{config.get("SMTP_SERVER", "")}"')
+ lines.append(f'SMTP_PORT="{config.get("SMTP_PORT", "587")}"')
+ lines.append(f'EMAIL_FROM="{config.get("EMAIL_FROM", "")}"')
+ lines.append(f'EMAIL_PASSWORD="{config.get("EMAIL_PASSWORD", "")}"')
+ lines.append(f'EMAIL_TO="{config.get("EMAIL_TO", "")}"')
+ lines.append("")
+
+ # Webhook通知配置
+ lines.append("# ========== Webhook通知配置(可选)==========")
+ lines.append(f'WEBHOOK_ENABLED="{config.get("WEBHOOK_ENABLED", "false")}"')
+ lines.append(f'WEBHOOK_TYPE="{config.get("WEBHOOK_TYPE", "dingtalk")}"')
+ lines.append(f'WEBHOOK_URL="{config.get("WEBHOOK_URL", "")}"')
+ lines.append(f'WEBHOOK_KEYWORD="{config.get("WEBHOOK_KEYWORD", "aiagents通知")}"')
with open(self.env_file, 'w', encoding='utf-8') as f:
f.write('\n'.join(lines))
diff --git a/notification_service.py b/notification_service.py
index ad53618..db2258a 100644
--- a/notification_service.py
+++ b/notification_service.py
@@ -27,7 +27,9 @@ class NotificationService:
'email_password': '',
'email_to': '',
'webhook_enabled': False,
- 'webhook_url': ''
+ 'webhook_url': '',
+ 'webhook_type': 'dingtalk', # dingtalk 或 feishu
+ 'webhook_keyword': 'aiagents通知' # 钉钉自定义关键词
}
# 从环境变量加载配置
@@ -43,6 +45,14 @@ class NotificationService:
config['email_password'] = os.getenv('EMAIL_PASSWORD')
if os.getenv('EMAIL_TO'):
config['email_to'] = os.getenv('EMAIL_TO')
+ if os.getenv('WEBHOOK_ENABLED'):
+ config['webhook_enabled'] = os.getenv('WEBHOOK_ENABLED').lower() == 'true'
+ if os.getenv('WEBHOOK_URL'):
+ config['webhook_url'] = os.getenv('WEBHOOK_URL')
+ if os.getenv('WEBHOOK_TYPE'):
+ config['webhook_type'] = os.getenv('WEBHOOK_TYPE').lower()
+ if os.getenv('WEBHOOK_KEYWORD'):
+ config['webhook_keyword'] = os.getenv('WEBHOOK_KEYWORD')
return config
@@ -75,13 +85,26 @@ class NotificationService:
def send_notification(self, notification: Dict) -> bool:
"""发送单个通知"""
- # 优先尝试邮件通知
- if self.config['email_enabled']:
- return self._send_email_notification(notification)
+ success = False
- # 备用方案:在Streamlit界面显示
- self._show_streamlit_notification(notification)
- return True
+ # 尝试webhook通知
+ if self.config['webhook_enabled']:
+ webhook_success = self._send_webhook_notification(notification)
+ if webhook_success:
+ success = True
+
+ # 尝试邮件通知
+ if self.config['email_enabled']:
+ email_success = self._send_email_notification(notification)
+ if email_success:
+ success = True
+
+ # 如果两者都未启用或都失败,使用界面通知作为备用
+ if not success:
+ self._show_streamlit_notification(notification)
+ success = True
+
+ return success
def _send_email_notification(self, notification: Dict) -> bool:
"""发送邮件通知"""
@@ -262,6 +285,237 @@ class NotificationService:
self.config['email_to']
])
}
+
+ def _send_webhook_notification(self, notification: Dict) -> bool:
+ """发送Webhook通知"""
+ try:
+ # 检查webhook配置是否完整
+ if not self.config['webhook_url']:
+ print("⚠️ Webhook URL未配置")
+ return False
+
+ webhook_type = self.config['webhook_type']
+
+ if webhook_type == 'dingtalk':
+ return self._send_dingtalk_webhook(notification)
+ elif webhook_type == 'feishu':
+ return self._send_feishu_webhook(notification)
+ else:
+ print(f"⚠️ 不支持的webhook类型: {webhook_type}")
+ return False
+
+ except Exception as e:
+ print(f"Webhook发送失败: {e}")
+ return False
+
+ def _send_dingtalk_webhook(self, notification: Dict) -> bool:
+ """发送钉钉Webhook通知"""
+ try:
+ import requests
+
+ # 构建钉钉消息格式(包含自定义关键词)
+ keyword = self.config.get('webhook_keyword', '')
+ title_prefix = f"{keyword} - " if keyword else ""
+ content_prefix = f"### {keyword} - " if keyword else "### "
+
+ data = {
+ "msgtype": "markdown",
+ "markdown": {
+ "title": f"{title_prefix}{notification['symbol']} {notification['name']}",
+ "text": f"""{content_prefix}股票监测提醒
+
+**股票代码**: {notification['symbol']}
+
+**股票名称**: {notification['name']}
+
+**提醒类型**: {notification['type']}
+
+**提醒内容**: {notification['message']}
+
+**触发时间**: {notification['triggered_at']}
+
+---
+
+_此消息由AI股票分析系统自动发送_"""
+ }
+ }
+
+ print(f"[钉钉] 正在发送Webhook...")
+ print(f" - URL: {self.config['webhook_url'][:50]}...")
+
+ response = requests.post(
+ self.config['webhook_url'],
+ json=data,
+ headers={'Content-Type': 'application/json'},
+ timeout=10
+ )
+
+ if response.status_code == 200:
+ result = response.json()
+ if result.get('errcode') == 0:
+ print(f"[成功] 钉钉Webhook发送成功")
+ return True
+ else:
+ print(f"[失败] 钉钉Webhook返回错误: {result.get('errmsg')}")
+ return False
+ else:
+ print(f"[失败] 钉钉Webhook请求失败: HTTP {response.status_code}")
+ return False
+
+ except Exception as e:
+ print(f"钉钉Webhook发送异常: {e}")
+ return False
+
+ def _send_feishu_webhook(self, notification: Dict) -> bool:
+ """发送飞书Webhook通知"""
+ try:
+ import requests
+
+ # 构建飞书消息格式
+ data = {
+ "msg_type": "interactive",
+ "card": {
+ "header": {
+ "title": {
+ "content": f"📊 股票监测提醒 - {notification['symbol']}",
+ "tag": "plain_text"
+ },
+ "template": "blue"
+ },
+ "elements": [
+ {
+ "tag": "div",
+ "fields": [
+ {
+ "is_short": True,
+ "text": {
+ "content": f"**股票代码**\n{notification['symbol']}",
+ "tag": "lark_md"
+ }
+ },
+ {
+ "is_short": True,
+ "text": {
+ "content": f"**股票名称**\n{notification['name']}",
+ "tag": "lark_md"
+ }
+ }
+ ]
+ },
+ {
+ "tag": "div",
+ "fields": [
+ {
+ "is_short": True,
+ "text": {
+ "content": f"**提醒类型**\n{notification['type']}",
+ "tag": "lark_md"
+ }
+ },
+ {
+ "is_short": True,
+ "text": {
+ "content": f"**触发时间**\n{notification['triggered_at']}",
+ "tag": "lark_md"
+ }
+ }
+ ]
+ },
+ {
+ "tag": "div",
+ "text": {
+ "content": f"**提醒内容**\n{notification['message']}",
+ "tag": "lark_md"
+ }
+ },
+ {
+ "tag": "hr"
+ },
+ {
+ "tag": "note",
+ "elements": [
+ {
+ "tag": "plain_text",
+ "content": "此消息由AI股票分析系统自动发送"
+ }
+ ]
+ }
+ ]
+ }
+ }
+
+ print(f"[飞书] 正在发送Webhook...")
+ print(f" - URL: {self.config['webhook_url'][:50]}...")
+
+ response = requests.post(
+ self.config['webhook_url'],
+ json=data,
+ headers={'Content-Type': 'application/json'},
+ timeout=10
+ )
+
+ if response.status_code == 200:
+ result = response.json()
+ if result.get('code') == 0:
+ print(f"[成功] 飞书Webhook发送成功")
+ return True
+ else:
+ print(f"[失败] 飞书Webhook返回错误: {result.get('msg')}")
+ return False
+ else:
+ print(f"[失败] 飞书Webhook请求失败: HTTP {response.status_code}")
+ return False
+
+ except Exception as e:
+ print(f"飞书Webhook发送异常: {e}")
+ return False
+
+ def send_test_webhook(self) -> tuple[bool, str]:
+ """发送测试Webhook"""
+ try:
+ # 检查webhook配置是否完整
+ if not self.config['webhook_url']:
+ return False, "Webhook URL未配置,请检查环境变量设置"
+
+ # 创建测试通知(包含关键词"aiagents通知"以通过钉钉安全设置)
+ test_notification = {
+ 'symbol': '测试',
+ 'name': 'Webhook配置测试',
+ 'type': '系统测试',
+ 'message': '如果您收到此消息,说明Webhook配置正确!',
+ 'triggered_at': '刚刚'
+ }
+
+ webhook_type = self.config['webhook_type']
+
+ if webhook_type == 'dingtalk':
+ success = self._send_dingtalk_webhook(test_notification)
+ if success:
+ return True, "钉钉Webhook测试成功!请检查钉钉群消息。"
+ else:
+ return False, "钉钉Webhook发送失败,请检查URL和网络连接"
+
+ elif webhook_type == 'feishu':
+ success = self._send_feishu_webhook(test_notification)
+ if success:
+ return True, "飞书Webhook测试成功!请检查飞书群消息。"
+ else:
+ return False, "飞书Webhook发送失败,请检查URL和网络连接"
+
+ else:
+ return False, f"不支持的webhook类型: {webhook_type}"
+
+ except Exception as e:
+ return False, f"发送失败: {str(e)}"
+
+ def get_webhook_config_status(self) -> Dict:
+ """获取Webhook配置状态"""
+ return {
+ 'enabled': self.config['webhook_enabled'],
+ 'webhook_type': self.config['webhook_type'],
+ 'webhook_url': self.config['webhook_url'][:50] + '...' if self.config['webhook_url'] else '未配置',
+ 'configured': bool(self.config['webhook_url'])
+ }
# 全局通知服务实例
notification_service = NotificationService()
\ No newline at end of file
diff --git a/sector_strategy_scheduler.py b/sector_strategy_scheduler.py
index 2a122e1..06c528b 100644
--- a/sector_strategy_scheduler.py
+++ b/sector_strategy_scheduler.py
@@ -128,36 +128,46 @@ class SectorStrategyScheduler:
self._send_error_notification(f"分析异常: {str(e)}")
def _send_analysis_notification(self, result):
- """发送分析结果邮件"""
+ """发送分析结果通知(邮件和/或webhook)"""
try:
- # 检查邮件配置
config = notification_service.config
- if not config.get('email_enabled') or not all([
+ predictions = result.get("final_predictions", {})
+ timestamp = result.get("timestamp", datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
+
+ sent_count = 0
+
+ # 尝试发送Webhook
+ if config.get('webhook_enabled') and config.get('webhook_url'):
+ print("[智策定时] [Webhook] 准备发送...")
+ webhook_success = self._send_webhook_direct(predictions, timestamp)
+ if webhook_success:
+ print("[智策定时] ✓ Webhook发送成功")
+ sent_count += 1
+ else:
+ print("[智策定时] ✗ Webhook发送失败")
+
+ # 尝试发送邮件
+ if config.get('email_enabled') and all([
config.get('smtp_server'),
config.get('email_from'),
config.get('email_password'),
config.get('email_to')
]):
- print("[智策定时] ⚠️ 邮件配置不完整,跳过发送")
- return
+ print("[智策定时] [邮件] 准备发送...")
+ subject = f"智策板块分析报告 - {timestamp}"
+ body = self._format_email_body(predictions, timestamp)
+ email_success = self._send_email_direct(subject, body)
+ if email_success:
+ print("[智策定时] ✓ 邮件发送成功")
+ sent_count += 1
+ else:
+ print("[智策定时] ✗ 邮件发送失败")
- predictions = result.get("final_predictions", {})
- timestamp = result.get("timestamp", datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
-
- # 构建邮件内容
- subject = f"智策板块分析报告 - {timestamp}"
- body = self._format_email_body(predictions, timestamp)
-
- # 直接发送邮件
- success = self._send_email_direct(subject, body)
-
- if success:
- print("[智策定时] ✓ 邮件发送成功")
- else:
- print("[智策定时] ✗ 邮件发送失败")
+ if sent_count == 0:
+ print("[智策定时] ⚠️ 未配置通知方式或发送全部失败")
except Exception as e:
- print(f"[智策定时] ✗ 邮件发送异常: {e}")
+ print(f"[智策定时] ✗ 通知发送异常: {e}")
import traceback
traceback.print_exc()
@@ -177,6 +187,144 @@ class SectorStrategyScheduler:
except:
pass
+ def _send_webhook_direct(self, predictions, timestamp):
+ """发送webhook通知"""
+ try:
+ import requests
+
+ config = notification_service.config
+ webhook_type = config.get('webhook_type', 'dingtalk')
+ webhook_url = config['webhook_url']
+
+ # 格式化简洁的分析摘要
+ summary = self._format_webhook_summary(predictions, timestamp)
+
+ if webhook_type == 'dingtalk':
+ return self._send_dingtalk(webhook_url, summary, timestamp)
+ elif webhook_type == 'feishu':
+ return self._send_feishu(webhook_url, summary, timestamp)
+ else:
+ print(f"[智策定时] ✗ 不支持的webhook类型: {webhook_type}")
+ return False
+
+ except Exception as e:
+ print(f"[智策定时] ✗ Webhook发送失败: {e}")
+ import traceback
+ traceback.print_exc()
+ return False
+
+ def _send_dingtalk(self, url, summary, timestamp):
+ """发送钉钉消息"""
+ try:
+ import requests
+
+ # 获取自定义关键词
+ keyword = notification_service.config.get('webhook_keyword', '')
+ title_prefix = f"{keyword} - " if keyword else ""
+
+ data = {
+ "msgtype": "markdown",
+ "markdown": {
+ "title": f"{title_prefix}智策板块分析报告",
+ "text": summary
+ }
+ }
+
+ response = requests.post(url, json=data, headers={'Content-Type': 'application/json'}, timeout=10)
+
+ if response.status_code == 200:
+ result = response.json()
+ return result.get('errcode') == 0
+ return False
+
+ except Exception as e:
+ print(f"[智策定时] 钉钉发送异常: {e}")
+ return False
+
+ def _send_feishu(self, url, summary, timestamp):
+ """发送飞书消息"""
+ try:
+ import requests
+
+ # 获取自定义关键词(飞书通常不需要关键词,但保持一致性)
+ keyword = notification_service.config.get('webhook_keyword', '')
+ title_prefix = f"【{keyword} - " if keyword else "【"
+
+ data = {
+ "msg_type": "text",
+ "content": {
+ "text": f"{title_prefix}智策板块分析报告】\n分析时间: {timestamp}\n\n{summary}"
+ }
+ }
+
+ response = requests.post(url, json=data, headers={'Content-Type': 'application/json'}, timeout=10)
+
+ if response.status_code == 200:
+ result = response.json()
+ return result.get('code') == 0
+ return False
+
+ except Exception as e:
+ print(f"[智策定时] 飞书发送异常: {e}")
+ return False
+
+ def _format_webhook_summary(self, predictions, timestamp):
+ """格式化webhook摘要(精简版)"""
+ # 获取自定义关键词
+ keyword = notification_service.config.get('webhook_keyword', '')
+ title_prefix = f"{keyword} - " if keyword else ""
+
+ lines = []
+ lines.append(f"### {title_prefix}智策板块分析报告")
+ lines.append(f"**分析时间**: {timestamp}")
+ lines.append("")
+
+ # 板块多空(只显示高信心度的)
+ long_short = predictions.get("long_short", {})
+ if long_short:
+ bullish = [item for item in long_short.get("bullish", []) if item.get('confidence', 0) >= 7]
+ bearish = [item for item in long_short.get("bearish", []) if item.get('confidence', 0) >= 7]
+
+ if bullish or bearish:
+ lines.append("#### 📊 板块多空")
+ if bullish:
+ lines.append("**看多**: " + "、".join([f"{item.get('sector')}({item.get('confidence')}分)" for item in bullish[:3]]))
+ if bearish:
+ lines.append("**看空**: " + "、".join([f"{item.get('sector')}({item.get('confidence')}分)" for item in bearish[:3]]))
+ lines.append("")
+
+ # 板块轮动(只显示潜力板块)
+ rotation = predictions.get("rotation", {})
+ if rotation:
+ potential = rotation.get("potential", [])[:3]
+ if potential:
+ lines.append("#### 🔄 潜力接力板块")
+ for item in potential:
+ lines.append(f"- {item.get('sector')}: {item.get('advice', 'N/A')}")
+ lines.append("")
+
+ # 板块热度TOP3
+ heat = predictions.get("heat", {})
+ if heat:
+ hottest = heat.get("hottest", [])[:3]
+ if hottest:
+ lines.append("#### 🌡️ 热度TOP3")
+ for idx, item in enumerate(hottest, 1):
+ lines.append(f"{idx}. {item.get('sector')} - {item.get('score', 0)}分")
+ lines.append("")
+
+ # 策略总结
+ summary = predictions.get("summary", {})
+ if summary and summary.get('key_opportunity'):
+ lines.append("#### 💡 核心机会")
+ lines.append(summary['key_opportunity'][:150] + "..." if len(summary.get('key_opportunity', '')) > 150 else summary.get('key_opportunity', ''))
+ lines.append("")
+
+ lines.append("---")
+ lines.append("*由智策AI系统自动生成*")
+
+ return "\n".join(lines)
+
def _send_email_direct(self, subject, body):
"""直接发送邮件(参考notification_service的实现)"""
try:
diff --git a/update_env_example.py b/update_env_example.py
new file mode 100644
index 0000000..9a054dc
--- /dev/null
+++ b/update_env_example.py
@@ -0,0 +1,107 @@
+# -*- coding: utf-8 -*-
+"""更新.env.example模板文件"""
+
+env_example_content = """# ============================================================
+# AI股票分析系统环境配置模板
+# ============================================================
+# 使用说明:
+# 1. 复制此文件并重命名为 .env
+# 2. 根据实际情况填写配置项
+# 3. 敏感信息(如API密钥、密码)请妥善保管,不要提交到版本控制
+# ============================================================
+
+# ========== DeepSeek API配置 ==========
+# DeepSeek API密钥(必填)
+# 获取地址:https://platform.deepseek.com/api_keys
+DEEPSEEK_API_KEY=your_actual_deepseek_api_key_here
+
+# DeepSeek API基础URL(可选,使用默认值即可)
+DEEPSEEK_BASE_URL=https://api.deepseek.com/v1
+
+
+# ========== Tushare数据接口(可选)==========
+# Tushare Token(可选,用于获取更多金融数据)
+# 获取地址:https://tushare.pro/register
+TUSHARE_TOKEN=
+
+
+# ========== MiniQMT量化交易配置(可选)==========
+# 是否启用MiniQMT量化交易接口
+MINIQMT_ENABLED=false
+
+# MiniQMT账户ID
+MINIQMT_ACCOUNT_ID=
+
+# MiniQMT服务器地址
+MINIQMT_HOST=127.0.0.1
+
+# MiniQMT服务器端口
+MINIQMT_PORT=58610
+
+
+# ========== 邮件通知配置(可选)==========
+# 是否启用邮件通知
+EMAIL_ENABLED=false
+
+# SMTP服务器地址
+# 常用邮箱SMTP服务器:
+# - 163邮箱:smtp.163.com
+# - QQ邮箱:smtp.qq.com
+# - Gmail:smtp.gmail.com
+# - 企业邮箱:根据邮箱服务商提供的信息填写
+SMTP_SERVER=smtp.163.com
+
+# SMTP服务器端口
+# 常用端口:
+# - 465:SSL加密连接(推荐)
+# - 587:TLS加密连接
+SMTP_PORT=465
+
+# 发件人邮箱地址
+EMAIL_FROM=your_email@163.com
+
+# 邮箱授权码(不是登录密码!)
+# 获取方法:
+# - 163邮箱:设置 -> POP3/SMTP/IMAP -> 开启服务 -> 获取授权码
+# - QQ邮箱:设置 -> 账户 -> POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务 -> 开启服务 -> 生成授权码
+EMAIL_PASSWORD=your_email_authorization_code
+
+# 收件人邮箱地址(接收通知的邮箱)
+EMAIL_TO=receiver@example.com
+
+
+# ========== Webhook通知配置(可选)==========
+# 是否启用Webhook通知(钉钉/飞书)
+WEBHOOK_ENABLED=false
+
+# Webhook类型
+# 可选值:dingtalk(钉钉)、feishu(飞书)
+WEBHOOK_TYPE=dingtalk
+
+# Webhook地址
+# 钉钉机器人:https://oapi.dingtalk.com/robot/send?access_token=YOUR_ACCESS_TOKEN
+# 飞书机器人:https://open.feishu.cn/open-apis/bot/v2/hook/YOUR_HOOK_ID
+WEBHOOK_URL=
+
+# Webhook自定义关键词(仅钉钉需要)
+# 说明:
+# - 如果钉钉机器人设置了"自定义关键词"安全验证,请在此填写关键词
+# - 系统会自动在消息标题和内容中包含此关键词
+# - 如果不使用关键词验证,可以留空或使用其他安全方式(加签、IP白名单)
+# - 飞书机器人通常不需要关键词,可以留空
+# 示例:aiagents通知
+WEBHOOK_KEYWORD=
+
+
+# ========== 时区配置 ==========
+# 系统时区设置(可选)
+TZ=Asia/Shanghai
+"""
+
+with open('.env.example', 'w', encoding='utf-8') as f:
+ f.write(env_example_content)
+
+print("[OK] .env.example file updated successfully")
+print("[OK] File encoding: UTF-8")
+print("[OK] All Chinese characters should display correctly")
+
diff --git a/环境配置功能说明.md b/环境配置功能说明.md
index c386e59..bea4693 100644
--- a/环境配置功能说明.md
+++ b/环境配置功能说明.md
@@ -53,6 +53,55 @@
- **⚠️ 警告**:量化交易涉及真实资金操作,请谨慎配置和使用!
+### 4. 通知配置(可选)⭐新增
+
+#### 📧 邮件通知
+- **启用开关**
+ - 描述:是否启用邮件通知功能
+ - 默认:关闭
+ - 适用:实时监测和智策定时分析
+
+- **SMTP服务器地址**
+ - 描述:邮件服务器地址
+ - 示例:`smtp.qq.com`、`smtp.163.com`
+
+- **SMTP端口**
+ - 描述:邮件服务器端口
+ - 默认:`587` (TLS) 或 `465` (SSL)
+
+- **发件人邮箱**
+ - 描述:发送通知的邮箱地址
+ - 示例:`your-email@qq.com`
+
+- **邮箱授权码**
+ - 描述:SMTP服务授权码(不是登录密码)
+ - 获取:邮箱设置 → SMTP服务 → 生成授权码
+
+- **收件人邮箱**
+ - 描述:接收通知的邮箱地址
+ - 示例:`recipient@qq.com`
+
+#### 📱 Webhook通知
+- **启用开关**
+ - 描述:是否启用Webhook通知功能
+ - 默认:关闭
+ - 适用:实时监测和智策定时分析
+
+- **Webhook类型**
+ - 描述:选择Webhook平台
+ - 选项:钉钉 (`dingtalk`) 或 飞书 (`feishu`)
+
+- **Webhook地址**
+ - 描述:机器人Webhook URL
+ - 钉钉示例:`https://oapi.dingtalk.com/robot/send?access_token=xxxxx`
+ - 飞书示例:`https://open.feishu.cn/open-apis/bot/v2/hook/xxxxx`
+ - 获取:群设置 → 群机器人 → 添加自定义机器人
+
+**💡 提示**:
+- 邮件和Webhook可以同时启用
+- 配置后建议使用测试功能验证
+- 详见《Webhook通知配置指南.md》
+
## 使用流程
1. **进入配置页面**
diff --git a/环境配置快速指南.md b/环境配置快速指南.md
new file mode 100644
index 0000000..5f3fe53
--- /dev/null
+++ b/环境配置快速指南.md
@@ -0,0 +1,236 @@
+# 环境配置快速指南
+
+## 📋 配置步骤
+
+### 1. 创建配置文件
+
+如果您是首次使用,请复制模板文件:
+
+```bash
+# Windows PowerShell
+Copy-Item .env.example .env
+
+# Linux/Mac
+cp .env.example .env
+```
+
+### 2. 配置必填项
+
+#### ✅ DeepSeek API配置(必填)
+
+1. 访问 [DeepSeek Platform](https://platform.deepseek.com/api_keys)
+2. 注册/登录账号
+3. 创建API密钥
+4. 在`.env`文件中填写:
+
+```env
+DEEPSEEK_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+```
+
+### 3. 配置可选项
+
+#### 📧 邮件通知配置(推荐)
+
+**配置示例(163邮箱):**
+
+```env
+EMAIL_ENABLED=true
+SMTP_SERVER=smtp.163.com
+SMTP_PORT=465
+EMAIL_FROM=your_email@163.com
+EMAIL_PASSWORD=your_authorization_code
+EMAIL_TO=receiver@qq.com
+```
+
+**获取邮箱授权码:**
+
+1. **163邮箱**
+ - 登录163邮箱网页版
+ - 设置 → POP3/SMTP/IMAP
+ - 开启"POP3/SMTP服务"
+ - 点击"生成授权码"
+ - 复制授权码(16位字符)
+
+2. **QQ邮箱**
+ - 登录QQ邮箱网页版
+ - 设置 → 账户
+ - 找到"POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务"
+ - 开启"POP3/SMTP服务"
+ - 点击"生成授权码"
+ - 按提示完成验证
+
+**常用SMTP配置:**
+
+| 邮箱类型 | SMTP服务器 | SSL端口 | TLS端口 |
+|---------|-----------|---------|---------|
+| 163邮箱 | smtp.163.com | 465 | 587 |
+| QQ邮箱 | smtp.qq.com | 465 | 587 |
+| Gmail | smtp.gmail.com | 465 | 587 |
+| 126邮箱 | smtp.126.com | 465 | 587 |
+
+#### 📱 Webhook通知配置(可选)
+
+**钉钉机器人配置:**
+
+1. 在钉钉群中添加自定义机器人
+2. 安全设置选择"自定义关键词"
+3. **关键词必须设置为:`aiagents通知`**
+4. 复制Webhook地址
+5. 在`.env`文件中填写:
+
+```env
+WEBHOOK_ENABLED=true
+WEBHOOK_TYPE=dingtalk
+WEBHOOK_URL=https://oapi.dingtalk.com/robot/send?access_token=xxxxxx
+```
+
+**飞书机器人配置:**
+
+1. 在飞书群中添加自定义机器人
+2. 复制Webhook地址
+3. 在`.env`文件中填写:
+
+```env
+WEBHOOK_ENABLED=true
+WEBHOOK_TYPE=feishu
+WEBHOOK_URL=https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxx
+```
+
+#### 📊 Tushare数据接口(可选)
+
+1. 访问 [Tushare官网](https://tushare.pro/register)
+2. 注册账号
+3. 获取Token
+4. 在`.env`文件中填写:
+
+```env
+TUSHARE_TOKEN=your_tushare_token_here
+```
+
+#### 💹 MiniQMT量化交易(可选)
+
+如果您使用MiniQMT进行量化交易:
+
+```env
+MINIQMT_ENABLED=true
+MINIQMT_ACCOUNT_ID=your_account_id
+MINIQMT_HOST=127.0.0.1
+MINIQMT_PORT=58610
+```
+
+## 🧪 配置测试
+
+配置完成后,运行测试工具验证配置:
+
+```bash
+# Windows
+.\venv\Scripts\python.exe test_notification_config.py
+
+# Linux/Mac
+python test_notification_config.py
+```
+
+**测试结果示例:**
+
+```
+============================================================
+通知配置测试工具
+============================================================
+
+[邮件] 测试邮件配置
+ - 启用状态: [已启用]
+ - SMTP服务器: smtp.163.com
+ - 配置完整性: [完整]
+[成功] 测试邮件发送成功!
+
+[Webhook] 测试Webhook配置
+ - 启用状态: [已启用]
+ - Webhook类型: dingtalk
+ - 配置完整性: [完整]
+[成功] 钉钉Webhook测试成功!
+
+============================================================
+测试结果汇总
+============================================================
+邮件通知: [OK] 正常
+Webhook通知: [OK] 正常
+```
+
+## ⚠️ 常见问题
+
+### Q1: 邮件发送失败 - 认证错误
+
+**问题**:`SMTPAuthenticationError`
+
+**解决方案**:
+- 确认使用的是**授权码**,不是登录密码
+- 检查邮箱是否开启了POP3/SMTP服务
+- 163邮箱授权码需要在邮箱设置中生成
+
+### Q2: 钉钉消息发送失败 - 关键词不匹配
+
+**问题**:`关键词不匹配`
+
+**解决方案**:
+- 确保钉钉机器人的自定义关键词设置为:**`aiagents通知`**
+- 或者修改机器人安全设置为"加签"或"IP地址"
+
+### Q3: 网络连接失败
+
+**问题**:`getaddrinfo failed` 或 `Connection timeout`
+
+**解决方案**:
+- 检查网络连接
+- 检查防火墙设置
+- 确认SMTP服务器地址正确
+- 尝试使用不同的端口(465或587)
+
+### Q4: .env文件中文乱码
+
+**问题**:编辑器显示中文乱码
+
+**解决方案**:
+- 使用UTF-8编码打开文件
+- VS Code:右下角点击编码 → 选择"UTF-8"
+- 记事本:另存为时选择"UTF-8"编码
+
+## 📁 配置文件说明
+
+```
+.env.example # 配置模板(提交到版本控制)
+.env # 实际配置(不提交到版本控制,包含敏感信息)
+```
+
+## 🔐 安全建议
+
+1. **不要提交.env文件到版本控制系统**
+ - `.env`文件已在`.gitignore`中
+ - 只提交`.env.example`模板
+
+2. **定期更换密钥**
+ - 建议定期更换API密钥和授权码
+ - 如发现泄露,立即更换
+
+3. **权限控制**
+ - 限制`.env`文件的访问权限
+ - 不要在公开场合分享配置信息
+
+## 📚 相关文档
+
+- [邮件配置指南.md](邮件配置指南.md) - 详细的邮件配置说明
+- [Webhook通知配置指南.md](Webhook通知配置指南.md) - Webhook配置详解
+- [通知功能修复说明.md](通知功能修复说明.md) - 问题排查指南
+
+## 🆘 需要帮助?
+
+如遇到问题:
+1. 运行测试工具查看详细错误信息
+2. 查看相关文档
+3. 检查系统日志
+4. 参考常见问题解答
+
+---
+
+**更新时间**: 2025-10-14
+**版本**: v1.0
+