diff --git a/README.md b/README.md index f47cd02..f557e76 100644 --- a/README.md +++ b/README.md @@ -51,8 +51,9 @@ - **风险控制**:自动止损、止盈功能 - **持仓监控**:实时查看持仓和盈亏 - **预留接口**:完整的MiniQMT对接接口,可对接真实交易 -image +image image +image ### 📧 邮件通知系统 - **多邮箱支持**:QQ邮箱、163邮箱、Gmail等 diff --git a/app.py b/app.py index 829b827..74106d8 100644 --- a/app.py +++ b/app.py @@ -960,6 +960,13 @@ def display_history_records(): st.session_state.viewing_record_id = record['id'] with col4: + if st.button("➕ 监测", key=f"add_monitor_{record['id']}"): + st.session_state.add_to_monitor_id = record['id'] + st.session_state.viewing_record_id = record['id'] + + # 删除按钮(新增一行) + col5, _, _, _ = st.columns(4) + with col5: if st.button("🗑️ 删除", key=f"delete_{record['id']}"): if db.delete_record(record['id']): st.success("✅ 记录已删除") @@ -971,6 +978,182 @@ def display_history_records(): if 'viewing_record_id' in st.session_state: display_record_detail(st.session_state.viewing_record_id) +def display_add_to_monitor_dialog(record): + """显示加入监测的对话框""" + st.markdown("---") + st.subheader("➕ 加入监测") + + final_decision = record['final_decision'] + + # 从final_decision中提取关键数据 + if isinstance(final_decision, dict): + # 解析进场区间 + entry_range_str = final_decision.get('entry_range', 'N/A') + entry_min = 0.0 + entry_max = 0.0 + + # 尝试解析进场区间字符串,支持多种格式 + if entry_range_str and entry_range_str != 'N/A': + try: + import re + # 移除常见的前缀和单位 + clean_str = str(entry_range_str).replace('¥', '').replace('元', '').replace('$', '') + # 使用正则表达式提取数字 + # 支持格式:10.5-12.0, 10.5 - 12.0, 10.5~12.0, 10.5至12.0 等 + numbers = re.findall(r'\d+\.?\d*', clean_str) + if len(numbers) >= 2: + entry_min = float(numbers[0]) + entry_max = float(numbers[1]) + except: + # 如果解析失败,尝试用分隔符split + try: + clean_str = str(entry_range_str).replace('¥', '').replace('元', '').replace('$', '') + # 尝试多种分隔符 + for sep in ['-', '~', '至', '到']: + if sep in clean_str: + parts = clean_str.split(sep) + if len(parts) == 2: + entry_min = float(parts[0].strip()) + entry_max = float(parts[1].strip()) + break + except: + pass + + # 提取止盈和止损 + take_profit_str = final_decision.get('take_profit', 'N/A') + stop_loss_str = final_decision.get('stop_loss', 'N/A') + + take_profit = 0.0 + stop_loss = 0.0 + + # 解析止盈位 + if take_profit_str and take_profit_str != 'N/A': + try: + import re + # 移除单位和符号 + clean_str = str(take_profit_str).replace('¥', '').replace('元', '').replace('$', '').strip() + # 提取第一个数字 + numbers = re.findall(r'\d+\.?\d*', clean_str) + if numbers: + take_profit = float(numbers[0]) + except: + pass + + # 解析止损位 + if stop_loss_str and stop_loss_str != 'N/A': + try: + import re + # 移除单位和符号 + clean_str = str(stop_loss_str).replace('¥', '').replace('元', '').replace('$', '').strip() + # 提取第一个数字 + numbers = re.findall(r'\d+\.?\d*', clean_str) + if numbers: + stop_loss = float(numbers[0]) + except: + pass + + # 获取评级 + rating = final_decision.get('rating', '买入') + + # 检查是否已经在监测列表中 + from monitor_db import monitor_db + existing_stocks = monitor_db.get_monitored_stocks() + is_duplicate = any(stock['symbol'] == record['symbol'] for stock in existing_stocks) + + if is_duplicate: + st.warning(f"⚠️ {record['symbol']} 已经在监测列表中。继续添加将创建重复监测项。") + + st.info(f""" + **从分析结果中提取的数据:** + - 进场区间: {entry_min} - {entry_max} + - 止盈位: {take_profit if take_profit > 0 else '未设置'} + - 止损位: {stop_loss if stop_loss > 0 else '未设置'} + - 投资评级: {rating} + """) + + # 显示表单供用户确认或修改 + with st.form(key=f"monitor_form_{record['id']}"): + st.markdown("**请确认或修改监测参数:**") + + col1, col2 = st.columns([1, 1]) + + with col1: + st.subheader("🎯 关键位置") + new_entry_min = st.number_input("进场区间最低价", value=float(entry_min), step=0.01, format="%.2f") + new_entry_max = st.number_input("进场区间最高价", value=float(entry_max), step=0.01, format="%.2f") + new_take_profit = st.number_input("止盈价位", value=float(take_profit), step=0.01, format="%.2f") + new_stop_loss = st.number_input("止损价位", value=float(stop_loss), step=0.01, format="%.2f") + + with col2: + st.subheader("⚙️ 监测设置") + check_interval = st.slider("监测间隔(分钟)", 5, 120, 30) + notification_enabled = st.checkbox("启用通知", value=True) + new_rating = st.selectbox("投资评级", ["买入", "持有", "卖出"], + index=["买入", "持有", "卖出"].index(rating) if rating in ["买入", "持有", "卖出"] else 0) + + col_a, col_b, col_c = st.columns(3) + + with col_a: + submit = st.form_submit_button("✅ 确认加入监测", type="primary", use_container_width=True) + + with col_b: + cancel = st.form_submit_button("❌ 取消", use_container_width=True) + + if submit: + if new_entry_min > 0 and new_entry_max > 0 and new_entry_max > new_entry_min: + try: + # 添加到监测数据库 + entry_range = {"min": new_entry_min, "max": new_entry_max} + + stock_id = monitor_db.add_monitored_stock( + symbol=record['symbol'], + name=record['stock_name'], + rating=new_rating, + entry_range=entry_range, + take_profit=new_take_profit if new_take_profit > 0 else None, + stop_loss=new_stop_loss if new_stop_loss > 0 else None, + check_interval=check_interval, + notification_enabled=notification_enabled + ) + + st.success(f"✅ 已成功将 {record['symbol']} 加入监测列表!") + st.balloons() + + # 立即更新一次价格 + from monitor_service import monitor_service + monitor_service.manual_update_stock(stock_id) + + # 清理session state并跳转到监测页面 + if 'add_to_monitor_id' in st.session_state: + del st.session_state.add_to_monitor_id + if 'viewing_record_id' in st.session_state: + del st.session_state.viewing_record_id + if 'show_history' in st.session_state: + del st.session_state.show_history + + # 设置跳转到监测页面 + st.session_state.show_monitor = True + st.session_state.monitor_jump_highlight = record['symbol'] # 标记要高亮显示的股票 + + time.sleep(1.5) + st.rerun() + + except Exception as e: + st.error(f"❌ 加入监测失败: {str(e)}") + else: + st.error("❌ 请输入有效的进场区间(最低价应小于最高价,且都大于0)") + + if cancel: + if 'add_to_monitor_id' in st.session_state: + del st.session_state.add_to_monitor_id + st.rerun() + else: + st.warning("⚠️ 无法从分析结果中提取关键数据") + if st.button("❌ 取消"): + if 'add_to_monitor_id' in st.session_state: + del st.session_state.add_to_monitor_id + st.rerun() + def display_record_detail(record_id): """显示单条记录的详细信息""" st.markdown("---") @@ -1108,11 +1291,29 @@ def display_record_detail(record_id): decision_text = final_decision.get('decision_text', str(final_decision)) st.write(decision_text) + # 加入监测功能 + st.markdown("---") + st.subheader("🎯 操作") + + # 检查是否需要显示加入监测的对话框 + if 'add_to_monitor_id' in st.session_state and st.session_state.add_to_monitor_id == record_id: + display_add_to_monitor_dialog(record) + else: + # 只有在不显示对话框时才显示按钮 + col1, col2 = st.columns([1, 3]) + + with col1: + if st.button("➕ 加入监测", type="primary", use_container_width=True): + st.session_state.add_to_monitor_id = record_id + st.rerun() + # 返回按钮 st.markdown("---") if st.button("⬅️ 返回历史记录列表"): if 'viewing_record_id' in st.session_state: del st.session_state.viewing_record_id + if 'add_to_monitor_id' in st.session_state: + del st.session_state.add_to_monitor_id st.rerun() if __name__ == "__main__": diff --git a/monitor_manager.py b/monitor_manager.py index 5ea0a45..d6b1fa3 100644 --- a/monitor_manager.py +++ b/monitor_manager.py @@ -25,6 +25,12 @@ def display_monitor_manager(): st.markdown("## 📊 股票监测管理") st.markdown("---") + # 检查是否有跳转提示 + if 'monitor_jump_highlight' in st.session_state: + symbol = st.session_state.monitor_jump_highlight + st.success(f"✅ {symbol} 已成功加入监测列表!您可以在下方查看。") + del st.session_state.monitor_jump_highlight + # 监测服务状态 display_monitor_status() diff --git a/加入监测功能测试报告.md b/加入监测功能测试报告.md new file mode 100644 index 0000000..c66f410 --- /dev/null +++ b/加入监测功能测试报告.md @@ -0,0 +1,187 @@ +# 加入监测功能测试报告 + +## 测试日期 +2025-10-05 + +## 问题描述 +用户反馈:点击"加入监测"按钮后,监测页面没有显示新加入的股票。 + +## 测试过程 + +### 1. 数据库写入测试 ✅ + +**测试脚本**: `test_monitor_add.py` + +**测试结果**: +- ✅ 成功从历史记录提取数据 +- ✅ 成功解析进场区间: `44.49 - 47.42` +- ✅ 成功解析止盈位: `48.0` +- ✅ 成功解析止损位: `42.5` +- ✅ 成功写入监测数据库,ID: 3 +- ✅ 验证监测列表,数据完整准确 + +**测试股票**: 603667 - 五洲新春 + +**数据验证**: +``` +股票代码: 603667 +股票名称: 五洲新春 +投资评级: 持有-观望 +进场区间: {'min': 44.49, 'max': 47.42} +止盈位: 48.0 +止损位: 42.5 +监测间隔: 30分钟 +通知启用: True +``` + +### 2. 监测列表显示测试 ✅ + +**测试脚本**: `test_monitor_display.py` + +**测试结果**: +- ✅ 监测列表中共有 3 只股票 +- ✅ 新添加的 603667 成功显示在列表首位 +- ✅ 所有数据字段完整准确 + +## 问题根因分析 + +通过测试发现,数据库写入和读取功能**完全正常**。问题出在用户界面的页面跳转逻辑: + +### 原始逻辑问题 + +```python +# 添加成功后只是刷新页面 +st.success(f"✅ 已成功将 {record['symbol']} 加入监测列表!") +st.balloons() +monitor_service.manual_update_stock(stock_id) + +# 仅清理 add_to_monitor_id +if 'add_to_monitor_id' in st.session_state: + del st.session_state.add_to_monitor_id + +time.sleep(1) +st.rerun() # 刷新后仍停留在历史记录页面 +``` + +**问题**: 添加成功后页面刷新,但用户仍然停留在历史记录详情页面,需要手动切换到监测页面才能看到新添加的股票。 + +## 解决方案 + +### 修改的文件 + +#### 1. `app.py` - 修改跳转逻辑 + +```python +# 清理session state并跳转到监测页面 +if 'add_to_monitor_id' in st.session_state: + del st.session_state.add_to_monitor_id +if 'viewing_record_id' in st.session_state: + del st.session_state.viewing_record_id +if 'show_history' in st.session_state: + del st.session_state.show_history + +# 设置跳转到监测页面 +st.session_state.show_monitor = True +st.session_state.monitor_jump_highlight = record['symbol'] # 标记要高亮显示的股票 + +time.sleep(1.5) +st.rerun() +``` + +**改进点**: +1. ✅ 清理所有相关的 session state(历史记录页面标记、详情页面标记) +2. ✅ 设置 `show_monitor = True` 自动跳转到监测页面 +3. ✅ 传递股票代码用于高亮显示 +4. ✅ 增加延迟到 1.5 秒,让用户看到成功提示 + +#### 2. `monitor_manager.py` - 添加欢迎提示 + +```python +def display_monitor_manager(): + """显示监测管理主页面""" + + st.markdown("## 📊 股票监测管理") + st.markdown("---") + + # 检查是否有跳转提示 + if 'monitor_jump_highlight' in st.session_state: + symbol = st.session_state.monitor_jump_highlight + st.success(f"✅ {symbol} 已成功加入监测列表!您可以在下方查看。") + del st.session_state.monitor_jump_highlight + + # ... 其余代码 +``` + +**改进点**: +1. ✅ 在监测页面顶部显示欢迎提示 +2. ✅ 明确告知用户股票已成功添加 +3. ✅ 提示用户在下方查看 + +## 最终效果 + +### 用户操作流程 + +1. 用户在历史记录页面点击"➕ 监测"按钮 +2. 显示加入监测对话框,自动填充数据 +3. 用户确认或修改参数后点击"✅ 确认加入监测" +4. 显示成功提示和气球动画(1.5秒) +5. **自动跳转到监测页面** +6. **在监测页面顶部显示成功提示** +7. **新添加的股票显示在监测列表中** + +### 改进前后对比 + +| 项目 | 改进前 | 改进后 | +|------|--------|--------| +| 页面跳转 | ❌ 停留在历史记录页面 | ✅ 自动跳转到监测页面 | +| 用户体验 | ❌ 需要手动切换页面 | ✅ 自动展示结果 | +| 成功反馈 | ⚠️ 仅有气球动画 | ✅ 气球动画 + 明确提示 | +| 数据验证 | ⚠️ 用户无法立即确认 | ✅ 立即显示在列表中 | + +## 测试结论 + +### 功能状态 +- ✅ 数据提取功能:正常 +- ✅ 数据解析功能:正常(支持多种格式) +- ✅ 数据库写入:正常 +- ✅ 监测列表显示:正常 +- ✅ 页面跳转:已修复 +- ✅ 用户体验:已优化 + +### 兼容性 +- ✅ 支持进场区间多种格式(-, ~, 至, 元, ¥等) +- ✅ 支持止盈止损多种格式 +- ✅ 重复检测正常工作 +- ✅ 监测服务集成正常 + +## 建议 + +### 使用建议 +1. 加入监测前,建议确认数据准确性 +2. 确保监测服务处于运行状态 +3. 配置邮件参数以接收通知 + +### 未来优化方向 +1. 可以考虑在监测列表中高亮显示刚添加的股票(闪烁效果) +2. 可以添加批量导入功能(一次添加多个历史记录) +3. 可以添加智能建议功能(根据历史记录自动推荐待监测股票) + +## 附录 + +### 测试环境 +- 操作系统: Windows 10 +- Python 版本: 3.12 +- Streamlit 版本: 最新 +- 数据库: SQLite (stock_monitor.db) + +### 测试数据 +- 历史记录数: 多条 +- 监测股票数: 3只 +- 测试股票: 603667 - 五洲新春 + +### 相关文件 +- `app.py` - 主应用文件(已修改) +- `monitor_manager.py` - 监测管理模块(已修改) +- `monitor_db.py` - 监测数据库模块(无修改) +- `database.py` - 分析数据库模块(无修改) + diff --git a/加入监测功能说明.md b/加入监测功能说明.md new file mode 100644 index 0000000..23dc876 --- /dev/null +++ b/加入监测功能说明.md @@ -0,0 +1,101 @@ +# 加入监测功能说明 + +## 功能概述 + +历史记录中的个股分析现在可以一键加入实时监测系统。系统会自动从最终投资决策中提取关键数据,快速创建监测任务。 + +## 功能特点 + +### 1. 智能数据提取 + +系统会自动从历史分析记录的最终投资决策中提取: +- **进场区间**:自动识别最低价和最高价 +- **止盈位**:目标获利价位 +- **止损位**:风险控制价位 +- **投资评级**:买入/持有/卖出 + +### 2. 多格式支持 + +支持解析多种数据格式: + +**进场区间格式**: +- `10.5-12.0` +- `10.5 - 12.0` +- `¥10.5-¥12.0` +- `10.5元-12.0元` +- `10.5~12.0` +- `10.5至12.0` + +**止盈/止损格式**: +- `15.0` +- `¥15.0` +- `15.0元` +- `$15.0` + +### 3. 重复检测 + +- 系统会自动检测股票是否已在监测列表中 +- 如已存在,会给出警告提示 +- 用户可以选择继续添加(创建重复监测项)或取消 + +### 4. 参数可调整 + +在加入监测前,用户可以: +- 确认或修改进场区间 +- 调整止盈止损位 +- 设置监测间隔(5-120分钟) +- 启用/禁用通知功能 +- 修改投资评级 + +## 使用方法 + +### 方法1:从历史记录列表 + +1. 进入"历史记录"页面 +2. 在任意分析记录的展开面板中,点击"➕ 监测"按钮 +3. 系统会自动进入该记录的详情页面并显示加入监测对话框 + +### 方法2:从详情页面 + +1. 进入"历史记录"页面 +2. 点击"👀 查看详情"按钮查看完整分析 +3. 在详情页面底部点击"➕ 加入监测"按钮 +4. 系统会显示加入监测对话框 + +### 使用对话框 + +1. **查看提取的数据**:系统会显示自动提取的进场区间、止盈、止损位等信息 +2. **确认或修改参数**:在表单中调整监测参数 +3. **提交**:点击"✅ 确认加入监测"按钮 +4. **成功**:系统会自动添加到监测列表并立即更新一次价格 + +## 技术实现 + +### 关键函数 + +- `display_add_to_monitor_dialog(record)`:显示加入监测对话框 +- 使用正则表达式 `re.findall()` 提取数字 +- 调用 `monitor_db.add_monitored_stock()` 写入数据库 +- 调用 `monitor_service.manual_update_stock()` 立即更新价格 + +### 数据流程 + +``` +历史记录 → 提取final_decision → 解析关键数据 → 显示确认表单 → 写入监测数据库 → 立即更新价格 +``` + +## 注意事项 + +1. **数据准确性**:系统会尽力解析各种格式的数据,但建议在提交前确认数据准确性 +2. **重复监测**:同一只股票可以创建多个监测项(例如不同的进场区间) +3. **监测服务**:加入监测后,确保监测服务处于运行状态 +4. **通知功能**:需要在 `.env` 中配置邮件参数才能接收通知 + +## 更新日志 + +### 2025-10-05 +- ✅ 实现历史记录加入监测功能 +- ✅ 支持多种数据格式自动解析 +- ✅ 添加重复检测功能 +- ✅ 优化用户界面和操作流程 +