From e62f18aa880054356672a1db257cb98f717dba79 Mon Sep 17 00:00:00 2001 From: oficcejo Date: Mon, 6 Oct 2025 17:38:13 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=8E=AF=E5=A2=83=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 +- app.py | 226 ++++++++++++++++++++++++++++++++++++++++++++ config_manager.py | 174 ++++++++++++++++++++++++++++++++++ 环境配置功能说明.md | 193 +++++++++++++++++++++++++++++++++++++ 资金流向功能说明.md | 1 + 5 files changed, 600 insertions(+), 2 deletions(-) create mode 100644 config_manager.py create mode 100644 环境配置功能说明.md diff --git a/README.md b/README.md index 30a932b..eb033cd 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,18 @@ # 🤖 复合多AI智能体股票团队分析系统 -- 初心:在股市摸爬滚打多年,自学自编各种指标,花冤枉钱学习了各种战法各种策略,也曾入各种小班,总是赚少赔多,逐渐失去在股市玩的信心。自从去年deepseek上市,一直探索用ai辅助分析,且近日受tradingagents项目启发(感谢原作),结合跟踪主力资金玩法(某指每年收费6000rmb),用各种ai辅助编程,拼凑了这么个小程序,根据软件提供的辅助信息,形成了自己的交易系统,近1一个月来,账户也慢慢在扭亏为盈。开源此软件的目的,就是为了使像我一样的一些小散,不再迷茫,也许这个软件不能让你发财,但是他能给你信心。希望能帮到你!欢迎加微信群讨论 +- 初心:在股市摸爬滚打多年,自学自编各种指标,花冤枉钱学习了各种战法各种策略,也曾入各种小班,总是赚少赔多,逐渐失去在股市玩的信心。自从去年deepseek上市,一直探索用ai辅助分析,且近日受tradingagents项目启发(感谢原作),结合跟踪主力资金玩法(某指每年收费6000rmb),用各种ai辅助编程,拼凑了这么个小程序,根据软件提供的辅助信息,形成了自己的交易系统,近1一个月来,账户也慢慢在扭亏为盈。开源此软件的目的,就是为了使像我一样的一些小散,不再迷茫,也许这个软件不能让你发财,但是他能给你信心。 +- 希望能帮到你!欢迎加微信群讨论 image ### 基于Python + Streamlit + DeepSeek的智能股票分析系统,模拟证券公司分析师团队,提供全方位的股票投资分析和决策建议。 image image +# 注意!!!右侧官方测试网站,请在环境配置中设置deepseek临时apikey,测试结束后请尽快删除或禁用!!否则会有泄露风险 + ## ✨ 更新说明 -### 增加股票监测功能,增加历史记录中个股导入到监测板块 +### 1006增加跟踪主力资金mcp,增加环境配置功能 +### 1005增加股票监测功能,增加历史记录中个股导入到监测板块 ## ✨ 功能特色 diff --git a/app.py b/app.py index dadafbb..79555b1 100644 --- a/app.py +++ b/app.py @@ -15,6 +15,7 @@ from database import db from monitor_manager import display_monitor_manager, get_monitor_summary from monitor_service import monitor_service from notification_service import notification_service +from config_manager import config_manager # 页面配置 st.set_page_config( @@ -301,6 +302,15 @@ def main(): del st.session_state.show_history if 'show_monitor' in st.session_state: del st.session_state.show_monitor + if 'show_config' in st.session_state: + del st.session_state.show_config + + if st.button("⚙️ 环境配置", use_container_width=True, key="nav_config"): + st.session_state.show_config = True + if 'show_history' in st.session_state: + del st.session_state.show_history + if 'show_monitor' in st.session_state: + del st.session_state.show_monitor st.markdown("---") @@ -383,6 +393,11 @@ def main(): display_monitor_manager() return + # 检查是否显示环境配置 + if 'show_config' in st.session_state and st.session_state.show_config: + display_config_manager() + return + # 主界面 col1, col2, col3 = st.columns([2, 1, 1]) @@ -1333,5 +1348,216 @@ def display_record_detail(record_id): del st.session_state.add_to_monitor_id st.rerun() +def display_config_manager(): + """显示环境配置管理界面""" + st.subheader("⚙️ 环境配置管理") + + st.markdown(""" +
+

在这里可以配置系统的环境变量,包括API密钥、数据源配置、量化交易配置等。

+

注意:配置修改后需要重启应用才能生效。

+
+ """, unsafe_allow_html=True) + + # 获取当前配置 + config_info = config_manager.get_config_info() + + # 创建标签页 + tab1, tab2, tab3 = st.tabs(["📝 基本配置", "📊 数据源配置", "🤖 量化交易配置"]) + + # 使用session_state保存临时配置 + if 'temp_config' not in st.session_state: + st.session_state.temp_config = {key: info["value"] for key, info in config_info.items()} + + with tab1: + st.markdown("### DeepSeek API配置") + st.markdown("DeepSeek是系统的核心AI引擎,必须配置才能使用分析功能。") + + # DeepSeek API Key + api_key_info = config_info["DEEPSEEK_API_KEY"] + current_api_key = st.session_state.temp_config.get("DEEPSEEK_API_KEY", "") + + new_api_key = st.text_input( + f"🔑 {api_key_info['description']} {'*' if api_key_info['required'] else ''}", + value=current_api_key, + type="password", + help="从 https://platform.deepseek.com 获取API密钥", + key="input_deepseek_api_key" + ) + st.session_state.temp_config["DEEPSEEK_API_KEY"] = new_api_key + + # 显示当前状态 + if new_api_key: + masked_key = new_api_key[:8] + "*" * (len(new_api_key) - 12) + new_api_key[-4:] if len(new_api_key) > 12 else "***" + st.success(f"✅ API密钥已设置: {masked_key}") + else: + st.warning("⚠️ 未设置API密钥,系统无法使用AI分析功能") + + st.markdown("---") + + # DeepSeek Base URL + base_url_info = config_info["DEEPSEEK_BASE_URL"] + current_base_url = st.session_state.temp_config.get("DEEPSEEK_BASE_URL", "") + + new_base_url = st.text_input( + f"🌐 {base_url_info['description']}", + value=current_base_url, + help="一般无需修改,保持默认即可", + key="input_deepseek_base_url" + ) + st.session_state.temp_config["DEEPSEEK_BASE_URL"] = new_base_url + + st.info("💡 如何获取DeepSeek API密钥?\n\n1. 访问 https://platform.deepseek.com\n2. 注册/登录账号\n3. 进入API密钥管理页面\n4. 创建新的API密钥\n5. 复制密钥并粘贴到上方输入框") + + with tab2: + st.markdown("### Tushare数据接口(可选)") + st.markdown("Tushare提供更丰富的A股财务数据,配置后可以获取更详细的财务分析。") + + tushare_info = config_info["TUSHARE_TOKEN"] + current_tushare = st.session_state.temp_config.get("TUSHARE_TOKEN", "") + + new_tushare = st.text_input( + f"🎫 {tushare_info['description']}", + value=current_tushare, + type="password", + help="从 https://tushare.pro 获取Token", + key="input_tushare_token" + ) + st.session_state.temp_config["TUSHARE_TOKEN"] = new_tushare + + if new_tushare: + st.success("✅ Tushare Token已设置") + else: + st.info("ℹ️ 未设置Tushare Token,系统将使用其他数据源") + + st.info("💡 如何获取Tushare Token?\n\n1. 访问 https://tushare.pro\n2. 注册账号\n3. 进入个人中心\n4. 获取Token\n5. 复制并粘贴到上方输入框") + + with tab3: + st.markdown("### MiniQMT量化交易配置(可选)") + st.markdown("配置后可以使用量化交易功能,自动执行交易策略。") + + # 启用开关 + miniqmt_enabled_info = config_info["MINIQMT_ENABLED"] + current_enabled = st.session_state.temp_config.get("MINIQMT_ENABLED", "false") == "true" + + new_enabled = st.checkbox( + "启用MiniQMT量化交易", + value=current_enabled, + help="开启后可以使用量化交易功能", + key="input_miniqmt_enabled" + ) + st.session_state.temp_config["MINIQMT_ENABLED"] = "true" if new_enabled else "false" + + # 其他配置 + col1, col2 = st.columns(2) + + with col1: + account_id_info = config_info["MINIQMT_ACCOUNT_ID"] + current_account_id = st.session_state.temp_config.get("MINIQMT_ACCOUNT_ID", "") + + new_account_id = st.text_input( + f"🆔 {account_id_info['description']}", + value=current_account_id, + disabled=not new_enabled, + key="input_miniqmt_account_id" + ) + st.session_state.temp_config["MINIQMT_ACCOUNT_ID"] = new_account_id + + host_info = config_info["MINIQMT_HOST"] + current_host = st.session_state.temp_config.get("MINIQMT_HOST", "") + + new_host = st.text_input( + f"🖥️ {host_info['description']}", + value=current_host, + disabled=not new_enabled, + key="input_miniqmt_host" + ) + st.session_state.temp_config["MINIQMT_HOST"] = new_host + + with col2: + port_info = config_info["MINIQMT_PORT"] + current_port = st.session_state.temp_config.get("MINIQMT_PORT", "") + + new_port = st.text_input( + f"🔌 {port_info['description']}", + value=current_port, + disabled=not new_enabled, + key="input_miniqmt_port" + ) + st.session_state.temp_config["MINIQMT_PORT"] = new_port + + if new_enabled: + st.success("✅ MiniQMT已启用") + else: + st.info("ℹ️ MiniQMT未启用") + + st.warning("⚠️ 警告:量化交易涉及真实资金操作,请谨慎配置和使用!") + + # 操作按钮 + st.markdown("---") + col1, col2, col3, col4 = st.columns([1, 1, 1, 2]) + + with col1: + if st.button("💾 保存配置", type="primary", use_container_width=True): + # 验证配置 + is_valid, message = config_manager.validate_config(st.session_state.temp_config) + + if is_valid: + # 保存配置 + if config_manager.write_env(st.session_state.temp_config): + st.success("✅ 配置已保存到 .env 文件") + st.info("ℹ️ 请重启应用使配置生效") + + # 尝试重新加载配置 + try: + config_manager.reload_config() + st.success("✅ 配置已重新加载") + except Exception as e: + st.warning(f"⚠️ 配置重新加载失败: {e}") + + time.sleep(2) + st.rerun() + else: + st.error("❌ 保存配置失败") + else: + st.error(f"❌ 配置验证失败: {message}") + + with col2: + if st.button("🔄 重置", use_container_width=True): + # 重置为当前文件中的值 + st.session_state.temp_config = {key: info["value"] for key, info in config_info.items()} + st.success("✅ 已重置为当前配置") + st.rerun() + + with col3: + if st.button("⬅️ 返回", use_container_width=True): + if 'show_config' in st.session_state: + del st.session_state.show_config + if 'temp_config' in st.session_state: + del st.session_state.temp_config + st.rerun() + + # 显示当前.env文件内容 + st.markdown("---") + with st.expander("📄 查看当前 .env 文件内容"): + current_config = config_manager.read_env() + + st.code(f"""# AI股票分析系统环境配置 +# 由系统自动生成和管理 + +# ========== DeepSeek API配置 ========== +DEEPSEEK_API_KEY="{current_config.get('DEEPSEEK_API_KEY', '')}" +DEEPSEEK_BASE_URL="{current_config.get('DEEPSEEK_BASE_URL', '')}" + +# ========== Tushare数据接口(可选)========== +TUSHARE_TOKEN="{current_config.get('TUSHARE_TOKEN', '')}" + +# ========== MiniQMT量化交易配置(可选)========== +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')}" +""", language="bash") + if __name__ == "__main__": main() \ No newline at end of file diff --git a/config_manager.py b/config_manager.py new file mode 100644 index 0000000..47c6304 --- /dev/null +++ b/config_manager.py @@ -0,0 +1,174 @@ +""" +环境配置管理模块 +用于读取和保存.env配置文件 +""" + +import os +from pathlib import Path +from typing import Dict, Any + + +class ConfigManager: + """配置管理器""" + + def __init__(self, env_file: str = ".env"): + self.env_file = Path(env_file) + self.default_config = { + "DEEPSEEK_API_KEY": { + "value": "", + "description": "DeepSeek API密钥", + "required": True, + "type": "password" + }, + "DEEPSEEK_BASE_URL": { + "value": "https://api.deepseek.com/v1", + "description": "DeepSeek API地址", + "required": False, + "type": "text" + }, + "TUSHARE_TOKEN": { + "value": "", + "description": "Tushare数据接口Token(可选)", + "required": False, + "type": "password" + }, + "MINIQMT_ENABLED": { + "value": "false", + "description": "启用MiniQMT量化交易", + "required": False, + "type": "boolean" + }, + "MINIQMT_ACCOUNT_ID": { + "value": "", + "description": "MiniQMT账户ID", + "required": False, + "type": "text" + }, + "MINIQMT_HOST": { + "value": "127.0.0.1", + "description": "MiniQMT服务器地址", + "required": False, + "type": "text" + }, + "MINIQMT_PORT": { + "value": "58610", + "description": "MiniQMT服务器端口", + "required": False, + "type": "text" + }, + } + + def read_env(self) -> Dict[str, str]: + """读取.env文件""" + config = {} + + if not self.env_file.exists(): + # 如果文件不存在,返回默认配置的值 + for key, info in self.default_config.items(): + config[key] = info["value"] + return config + + try: + with open(self.env_file, 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + # 跳过空行和注释 + if not line or line.startswith('#'): + continue + + # 解析键值对 + if '=' in line: + key, value = line.split('=', 1) + key = key.strip() + value = value.strip() + + # 移除引号 + if value.startswith('"') and value.endswith('"'): + value = value[1:-1] + elif value.startswith("'") and value.endswith("'"): + value = value[1:-1] + + config[key] = value + except Exception as e: + print(f"读取.env文件失败: {e}") + + # 确保所有默认配置项都存在 + for key, info in self.default_config.items(): + if key not in config: + config[key] = info["value"] + + return config + + def write_env(self, config: Dict[str, str]) -> bool: + """保存配置到.env文件""" + try: + lines = [] + lines.append("# AI股票分析系统环境配置") + lines.append("# 由系统自动生成和管理") + lines.append("") + + # DeepSeek配置 + lines.append("# ========== DeepSeek API配置 ==========") + lines.append(f'DEEPSEEK_API_KEY="{config.get("DEEPSEEK_API_KEY", "")}"') + lines.append(f'DEEPSEEK_BASE_URL="{config.get("DEEPSEEK_BASE_URL", "https://api.deepseek.com/v1")}"') + lines.append("") + + # Tushare配置 + lines.append("# ========== Tushare数据接口(可选)==========") + lines.append(f'TUSHARE_TOKEN="{config.get("TUSHARE_TOKEN", "")}"') + lines.append("") + + # MiniQMT配置 + lines.append("# ========== MiniQMT量化交易配置(可选)==========") + lines.append(f'MINIQMT_ENABLED="{config.get("MINIQMT_ENABLED", "false")}"') + 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")}"') + + with open(self.env_file, 'w', encoding='utf-8') as f: + f.write('\n'.join(lines)) + + return True + except Exception as e: + print(f"保存.env文件失败: {e}") + return False + + def get_config_info(self) -> Dict[str, Dict[str, Any]]: + """获取配置信息(包含描述、类型等)""" + current_values = self.read_env() + + config_info = {} + for key, info in self.default_config.items(): + config_info[key] = { + "value": current_values.get(key, info["value"]), + "description": info["description"], + "required": info["required"], + "type": info["type"] + } + + return config_info + + def validate_config(self, config: Dict[str, str]) -> tuple[bool, str]: + """验证配置""" + # 检查必填项 + for key, info in self.default_config.items(): + if info["required"] and not config.get(key): + return False, f"必填项 {info['description']} 不能为空" + + # 验证API Key格式(简单检查长度) + if config.get("DEEPSEEK_API_KEY"): + api_key = config.get("DEEPSEEK_API_KEY", "") + if len(api_key) < 20: + return False, "DeepSeek API Key格式不正确(长度太短)" + + return True, "配置验证通过" + + def reload_config(self): + """重新加载配置(重新加载.env文件)""" + from dotenv import load_dotenv + load_dotenv(override=True) + + +# 全局配置管理器实例 +config_manager = ConfigManager() + diff --git a/环境配置功能说明.md b/环境配置功能说明.md new file mode 100644 index 0000000..c386e59 --- /dev/null +++ b/环境配置功能说明.md @@ -0,0 +1,193 @@ +# 环境配置功能说明 + +## 功能概述 + +新增了可视化的环境配置管理界面,用户可以通过UI界面配置系统的所有环境变量,无需手动编辑 `.env` 文件。 + +## 访问方式 + +在侧栏的"快捷导航"区域,点击 **⚙️ 环境配置** 按钮即可进入配置界面。 + +## 配置项说明 + +### 1. 基本配置(必需) + +#### DeepSeek API配置 +- **API密钥** (必填) + - 描述:DeepSeek AI引擎的API密钥 + - 获取方式:访问 https://platform.deepseek.com + - 注意:这是系统核心功能,必须配置才能使用AI分析 + +- **API地址** (可选) + - 描述:DeepSeek API服务器地址 + - 默认值:`https://api.deepseek.com/v1` + - 注意:一般无需修改 + +### 2. 数据源配置(可选) + +#### Tushare数据接口 +- **Token** (可选) + - 描述:Tushare数据接口令牌 + - 获取方式:访问 https://tushare.pro + - 作用:提供更丰富的A股财务数据 + - 注意:未配置时系统使用其他数据源 + +### 3. 量化交易配置(可选) + +#### MiniQMT量化交易 +- **启用开关** + - 描述:是否启用MiniQMT量化交易功能 + - 默认:关闭 + +- **账户ID** + - 描述:MiniQMT交易账户ID + - 注意:仅在启用时需要配置 + +- **服务器地址** + - 描述:MiniQMT服务器地址 + - 默认:`127.0.0.1` + +- **服务器端口** + - 描述:MiniQMT服务器端口 + - 默认:`58610` + +- **⚠️ 警告**:量化交易涉及真实资金操作,请谨慎配置和使用! + +## 使用流程 + +1. **进入配置页面** + - 点击侧栏的"⚙️ 环境配置"按钮 + +2. **修改配置** + - 在相应标签页中填写或修改配置项 + - 必填项会有 `*` 标记 + - 密码类型的配置会以 `****` 显示 + +3. **保存配置** + - 点击"💾 保存配置"按钮 + - 系统会验证配置的有效性 + - 验证通过后保存到 `.env` 文件 + +4. **生效配置** + - 配置保存后会自动尝试重新加载 + - 建议重启应用以确保所有配置生效 + +## 功能特性 + +### ✅ 可视化配置 +- 友好的UI界面 +- 分类标签页组织 +- 字段说明和帮助信息 + +### ✅ 安全性 +- 密码字段自动隐藏 +- API密钥部分隐藏显示 +- 配置验证功能 + +### ✅ 便捷操作 +- 实时配置预览 +- 一键保存 +- 一键重置 +- 查看当前配置文件 + +### ✅ 智能提示 +- 配置状态实时显示 +- 获取API密钥的详细步骤 +- 字段帮助信息 + +## 配置文件位置 + +配置保存在项目根目录的 `.env` 文件中: +``` +D:\web\agentsstock1\.env +``` + +## 配置示例 + +```bash +# AI股票分析系统环境配置 +# 由系统自动生成和管理 + +# ========== DeepSeek API配置 ========== +DEEPSEEK_API_KEY="sk-xxxxxxxxxxxxxxxxxxxxxxxx" +DEEPSEEK_BASE_URL="https://api.deepseek.com/v1" + +# ========== Tushare数据接口(可选)========== +TUSHARE_TOKEN="" + +# ========== MiniQMT量化交易配置(可选)========== +MINIQMT_ENABLED="false" +MINIQMT_ACCOUNT_ID="" +MINIQMT_HOST="127.0.0.1" +MINIQMT_PORT="58610" +``` + +## 注意事项 + +1. **API密钥安全** + - 不要将 `.env` 文件提交到Git仓库 + - 不要分享你的API密钥给他人 + - 定期更换API密钥 + +2. **配置生效** + - 修改配置后建议重启应用 + - 某些配置可能需要重新加载才能生效 + +3. **必填项** + - DeepSeek API密钥是必填项 + - 其他配置项都是可选的 + +4. **量化交易** + - 量化交易功能涉及真实资金 + - 使用前请充分测试 + - 谨慎配置交易参数 + +## 故障排查 + +### 问题1:保存配置失败 + +**解决方案**: +- 检查文件权限 +- 确保项目目录可写 +- 检查配置格式是否正确 + +### 问题2:配置不生效 + +**解决方案**: +- 重启应用 +- 检查 `.env` 文件是否存在 +- 查看控制台错误信息 + +### 问题3:API密钥验证失败 + +**解决方案**: +- 确认API密钥正确 +- 检查API密钥是否过期 +- 确认网络连接正常 + +## 技术实现 + +### 核心文件 + +1. **config_manager.py** + - 配置管理器 + - 读取/保存 `.env` 文件 + - 配置验证 + +2. **app.py** + - 配置界面 + - 用户交互 + - 状态管理 + +3. **config.py** + - 加载环境变量 + - 提供配置访问接口 + +## 更新日期 + +2025年10月6日 + +## 作者 + +AI股票分析系统开发团队 + diff --git a/资金流向功能说明.md b/资金流向功能说明.md index 1dcdeb9..91660bd 100644 --- a/资金流向功能说明.md +++ b/资金流向功能说明.md @@ -233,6 +233,7 @@ streamlit run app.py #### 3. 提示 "未能获取问财资金流向数据" **原因**: +- 系统未安装node.js,需要node版本>16 - 问财API访问限制 - 股票代码不存在或停牌 - 数据暂时不可用