import streamlit as st from datetime import datetime from typing import Dict, List from monitor_db import monitor_db from monitor_service import monitor_service from notification_service import notification_service def display_monitor_panel(): """显示监测面板""" st.markdown("## 📊 实时监测面板") # 监测服务控制 col1, col2, col3, col4 = st.columns([1, 1, 1, 1]) with col1: if st.button("▶️ 启动监测服务", type="primary"): monitor_service.start_monitoring() with col2: if st.button("⏹️ 停止监测服务"): monitor_service.stop_monitoring() with col3: if st.button("🔄 手动更新所有"): stocks = monitor_service.get_stocks_needing_update() for stock in stocks: monitor_service.manual_update_stock(stock['id']) st.success(f"✅ 已手动更新 {len(stocks)} 只股票") with col4: # 显示定时调度状态 try: scheduler = monitor_service.get_scheduler() status = scheduler.get_status() if status['scheduler_running']: st.success("⏰ 定时已启用") else: st.info("⏰ 定时未启用") except: st.info("⏰ 定时未配置") # 显示通知 display_notifications() # 显示监测股票 display_monitored_stocks() def display_notifications(): """显示通知""" notifications = notification_service.get_streamlit_notifications() if notifications: st.markdown("### 🔔 最新提醒") for notification in notifications[-5:]: # 只显示最近5条 notification_type = notification['type'] color_map = { 'entry': '🟢', 'take_profit': '🟡', 'stop_loss': '🔴' } icon = color_map.get(notification_type, '🔵') st.info(f"{icon} **{notification['symbol']}** - {notification['message']}") if st.button("清空提醒"): notification_service.clear_streamlit_notifications() st.rerun() def display_monitored_stocks(): """显示监测股票卡片""" stocks = monitor_db.get_monitored_stocks() if not stocks: st.info("📋 暂无监测股票,请在分析完成后点击'加入监测'按钮添加") return st.markdown(f"### 📈 监测中 ({len(stocks)} 只)") # 每行显示3个卡片 cols = st.columns(3) for i, stock in enumerate(stocks): col_idx = i % 3 with cols[col_idx]: display_stock_card(stock) def display_stock_card(stock: Dict): """显示单个股票监测卡片""" with st.container(): st.markdown(f"### {stock['symbol']} - {stock['name']}") # 评级和状态 col1, col2 = st.columns([1, 1]) with col1: rating_color = { '买入': '🟢', '持有': '🟡', '卖出': '🔴' } st.metric("评级", f"{rating_color.get(stock['rating'], '⚪')} {stock['rating']}") with col2: if stock['current_price'] and stock['current_price'] != 'N/A': st.metric("当前价格", f"¥{stock['current_price']}") else: st.metric("当前价格", "等待更新") # 关键价位 entry_range = stock['entry_range'] st.info(f"**进场区间**: ¥{entry_range['min']} - ¥{entry_range['max']}") if stock['take_profit']: st.success(f"**止盈位**: ¥{stock['take_profit']}") if stock['stop_loss']: st.error(f"**止损位**: ¥{stock['stop_loss']}") # 最后更新时间 if stock['last_checked']: last_checked = datetime.fromisoformat(stock['last_checked']) st.caption(f"最后更新: {last_checked.strftime('%m-%d %H:%M')}") # 操作按钮 col1, col2 = st.columns([1, 1]) with col1: if st.button("🔄 更新", key=f"update_{stock['id']}"): if monitor_service.manual_update_stock(stock['id']): st.success("✅ 更新成功") else: st.error("❌ 更新失败") with col2: if st.button("🗑️ 移除", key=f"remove_{stock['id']}"): monitor_db.remove_monitored_stock(stock['id']) st.success("✅ 已移除监测") st.rerun() def add_to_monitor_dialog(stock_info: Dict, analysis_result: Dict): """显示添加到监测的对话框""" st.markdown("---") st.markdown("## 📈 添加到实时监测") # 从分析结果中提取关键数据 final_decision = analysis_result.get('final_decision', {}) rating = final_decision.get('rating', '持有') reasoning = final_decision.get('reasoning', '') # 生成唯一的session标识符 import uuid import time session_id = f"{stock_info.get('symbol', 'unknown')}_{int(time.time())}_{uuid.uuid4().hex[:6]}" # 解析关键价位(从分析结果中提取或手动输入) col1, col2 = st.columns([1, 1]) with col1: # 进场区间 st.subheader("🎯 进场区间") entry_min = st.number_input("最低进场价", value=0.0, key=f"entry_min_{session_id}") entry_max = st.number_input("最高进场价", value=0.0, key=f"entry_max_{session_id}") if entry_min > 0 and entry_max > 0 and entry_max > entry_min: entry_range = {"min": entry_min, "max": entry_max} else: st.warning("请输入有效的进场区间") entry_range = None with col2: # 止盈止损 st.subheader("⚖️ 风险控制") take_profit = st.number_input("止盈价位", value=0.0, key=f"take_profit_{session_id}") stop_loss = st.number_input("止损价位", value=0.0, key=f"stop_loss_{session_id}") if take_profit > 0: st.success(f"止盈位: ¥{take_profit}") if stop_loss > 0: st.error(f"止损位: ¥{stop_loss}") # 监测设置 st.subheader("⏰ 监测设置") check_interval = st.slider("监测间隔(分钟)", 5, 120, 30, key=f"check_interval_{session_id}") notification_enabled = st.checkbox("启用提醒", value=True, key=f"notification_enabled_{session_id}") # 添加按钮 if st.button("✅ 确认加入监测", type="primary", key=f"add_monitor_{session_id}"): if entry_range: # 添加到监测数据库 stock_id = monitor_db.add_monitored_stock( symbol=stock_info.get('symbol'), name=stock_info.get('name'), rating=rating, entry_range=entry_range, take_profit=take_profit if take_profit > 0 else None, stop_loss=stop_loss if stop_loss > 0 else None, check_interval=check_interval ) st.success(f"✅ 已成功将 {stock_info.get('symbol')} 加入实时监测") st.balloons() # 立即更新一次价格 monitor_service.manual_update_stock(stock_id) else: st.error("❌ 请设置有效的进场区间") def get_monitor_summary() -> Dict: """获取监测摘要信息""" stocks = monitor_db.get_monitored_stocks() summary = { 'total_stocks': len(stocks), 'stocks_needing_update': len(monitor_service.get_stocks_needing_update()), 'pending_notifications': len(monitor_db.get_pending_notifications()), 'active_monitoring': monitor_service.running } return summary