From 5926fa5f4670a6e1d66ae2ea58949a640faf481d Mon Sep 17 00:00:00 2001 From: zyj118 <693696817@qq.com> Date: Wed, 15 Jan 2025 14:41:21 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=EF=BC=9AAI=E4=BB=B7=E5=80=BC=E6=8A=95=E8=B5=84=E7=9B=AF?= =?UTF-8?q?=E7=9B=98=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 7 + .gitignore | 22 +- README.md | 310 ++++++-------- app/__init__.py | 2 +- app/api/stock_routes.py | 47 ++- app/config.py | 27 +- app/services/ai_analysis_service.py | 440 +++++++++++++++++++- app/services/stock_service.py | 14 + app/templates/index.html | 609 +++++++++++++++++++++++++--- config.json | 178 ++++++++ config.json.example | 6 - config.template.py | 12 + docs/images/main.png | Bin 0 -> 512800 bytes requirements.txt | 54 ++- stock_cache.json | 478 +++++++++++----------- 项目文档.txt | 193 +++++++++ 16 files changed, 1844 insertions(+), 555 deletions(-) create mode 100644 .env.example create mode 100644 config.json delete mode 100644 config.json.example create mode 100644 config.template.py create mode 100644 docs/images/main.png create mode 100644 项目文档.txt diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..4a9bb9f --- /dev/null +++ b/.env.example @@ -0,0 +1,7 @@ +# Tushare API配置 +TUSHARE_TOKEN=your_tushare_token_here + +# Volces API配置 +VOLCES_MODEL_ID=your_model_id_here +VOLCES_API_KEY=your_api_key_here +VOLCES_BASE_URL=https://ark.cn-beijing.volces.com/api/v3 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 5724d8b..a5949cf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +# 环境配置 +.env +config.py + # Python __pycache__/ *.py[cod] @@ -16,14 +20,16 @@ lib64/ parts/ sdist/ var/ -wheels/ *.egg-info/ .installed.cfg *.egg -# 虚拟环境 -venv/ -ENV/ +# 项目特定文件 +stock_cache.json +watchlist.json +ai_stock_analysis/ +dao_analysis/ +daka_analysis/ # IDE .idea/ @@ -31,10 +37,6 @@ ENV/ *.swp *.swo -# 项目特定 -config.json -*.log -.env +# 系统文件 .DS_Store -stock_cache.json -watchlist.json \ No newline at end of file +Thumbs.db \ No newline at end of file diff --git a/README.md b/README.md index b3d4607..4747129 100644 --- a/README.md +++ b/README.md @@ -1,238 +1,158 @@ -# 价值投资盯盘系统 +# AI价值投资盯盘系统 -一个专注于中国 A 股市场的智能股票分析与监控平台,基于 Python FastAPI 开发,集成实时行情监控、AI 智能分析和价值投资建议等功能,助力投资者进行理性的价值投资决策。 +一个基于Python的A股智能监控和AI分析系统,集成了多维度的投资分析功能,包括传统价值投资分析、道德经智慧分析以及知名投资大师的视角分析。 -## 功能特点 +## 系统界面预览 + -### 1. A股实时监控 -- 支持所有 A 股上市公司的实时监控 -- 沪深两市实时价格和涨跌幅更新 -- 自定义市值目标区间预警 -- 个股交易状态实时提示 +## 🚀 核心功能 -### 2. AI 智能分析 -- 基于中国市场特点的智能投资建议 -- A股市场合理价格区间估算 -- 结合中国经济环境的目标市值评估 -- 多维度分析报告: - - A股市场估值分析 - - 中国特色财务健康状况评估 - - 行业对标成长潜力评估 - - 系统性风险评估 +### 1. 股票监控 +- 实时股票数据监控 +- 自定义目标市值设置 +- 价格和市值预警 +- 多维度指标展示(PE、PB、ROE等) -### 3. A股财务指标分析 -- 估值指标:PE(市盈率)、PB(市净率)、PS(市销率)等 -- 盈利能力:ROE(净资产收益率)、毛利率、净利率 -- 成长能力:营收增长、利润增长、研发投入 -- 运营效率:资产周转率、存货周转率等 -- 偿债能力:资产负债率、流动比率等 -- 现金流指标:经营现金流、自由现金流等 +### 2. 指数行情 +- 主要指数实时行情展示 +- K线图技术分析 +- 大盘趋势分析 -### 4. 中国市场行情 -- 上证指数、深证成指、创业板指等主要指数实时行情 -- 专业K线图技术分析 -- A股市场涨跌分布分析 -- 行业板块轮动分析 +### 3. AI智能分析 +- 基础价值投资分析 + - 财务指标分析 + - 估值分析 + - 风险评估 + - 投资建议 +- 道德经分析视角 + - 企业道德评估 + - 可持续发展分析 + - 长期投资价值判断 +- 价值投资大咖分析 + - 巴菲特视角 + - 格雷厄姆视角 + - 林园视角 + - 李大霄视角 + - 段永平视角 -### 5. 上市公司详情 -- 工商登记信息 -- 十大股东持股变动 -- A股特色财务报表分析 -- 公司公告与重大事项 -- 行业地位分析 +### 4. 数据管理 +- 本地数据缓存 +- 历史数据查询 +- 分析报告导出 +- 自动数据更新 -## 技术架构 +## 🛠️ 技术栈 -### 后端技术栈 -- Web框架:FastAPI -- 数据处理:Pandas -- A股数据源:Tushare API(提供专业的 A 股数据) -- 服务器:Uvicorn -- 数据存储:JSON文件 - -### 前端技术栈 -- 框架:Bootstrap 5 -- 图表:ECharts -- 交互:JavaScript -- 样式:CSS3 - -### 主要模块 -``` -项目结构 -├── app/ -│ ├── __init__.py -│ ├── api/ -│ │ └── stock_routes.py # API路由 -│ ├── models/ -│ │ └── stock.py # 数据模型 -│ ├── services/ -│ │ ├── stock_service.py # 股票服务 -│ │ └── ai_analysis_service.py # AI分析服务 -│ ├── templates/ -│ │ ├── index.html # 主页面 -│ │ └── market.html # 市场页面 -│ └── config.py # 配置文件 -├── run.py # 启动文件 -└── requirements.txt # 依赖包 -``` - -## 安装部署 - -### 环境要求 +### 后端 - Python 3.8+ -- pip 包管理器 -- 网络连接(访问 Tushare API) +- FastAPI:高性能Web框架 +- Tushare:金融数据API +- 豆包大模型:AI分析引擎 +- SQLite:本地数据存储 -### 安装步骤 +### 前端 +- Bootstrap 5:响应式UI框架 +- ECharts:数据可视化 +- jQuery:DOM操作 +- WebSocket:实时数据推送 -1. 克隆项目 +## 📦 安装部署 + +### 1. 环境准备 ```bash -git clone https://github.com/693696817/stock-monitor.git +# 克隆项目 +git clone https://gitee.com/your-username/stock-monitor.git cd stock-monitor -``` -2. 创建虚拟环境(推荐) -```bash +# 创建虚拟环境 python -m venv venv source venv/bin/activate # Linux/Mac -venv\Scripts\activate # Windows -``` +venv\\Scripts\\activate # Windows -3. 安装依赖 -```bash +# 安装依赖 pip install -r requirements.txt ``` -4. 配置 -- 复制 `config.json.example` 为 `config.json` -- 在 `config.json` 中配置你的 Tushare Token -```json -{ - "watchlist": {}, - "tushare_token": "your_tushare_token_here" -} +### 2. API配置获取 + +#### Tushare API +1. 访问 [Tushare官网](https://tushare.pro/) +2. 注册并获取Token +3. 可选:充值获取更高级别权限 + +#### 豆包大模型API +1. 访问 [豆包大模型控制台](https://ark.cn-beijing.volces.com/) +2. 注册企业账号 +3. 创建API Key和Model ID + +### 3. 环境配置 +1. 复制配置文件 +```bash +cp .env.example .env +cp config.template.py config.py ``` -5. 运行 +2. 修改配置文件 +```bash +# 编辑.env文件,填入API密钥 +TUSHARE_TOKEN=your_token_here +VOLCES_MODEL_ID=your_model_id_here +VOLCES_API_KEY=your_api_key_here +``` + +### 4. 启动系统 ```bash python run.py ``` +访问 http://localhost:8000 即可使用系统 -6. 访问 -- 打开浏览器访问 `http://localhost:8000` -- 默认端口为 8000,可在 `run.py` 中修改 +## 🤝 联系作者 -## 使用指南 +如果您对系统有任何问题或建议,欢迎联系: -### 添加监控股票 -1. 在主页面顶部输入 A 股股票代码(6位数字,如:000001) -2. 可选择设置目标市值区间 -3. 点击"添加"按钮开始监控 +- 微信:zyj118 +- QQ:693696817 +- Email:693696817@qq.com -### 查看股票详情 -1. 点击股票名称进入详情页 -2. 查看完整的 A 股特色财务指标 -3. 获取针对中国市场的 AI 投资建议 +## 📝 使用说明 -### 指数行情 -- 实时展示沪深主要指数行情 -- 提供大盘趋势分析 -- 行业板块表现对比 +### 1. 添加监控股票 +1. 在主界面输入股票代码 +2. 设置目标市值范围 +3. 点击添加即可 -### 数据更新频率 -- A股交易时段(9:30-11:30, 13:00-15:00)实时更新 -- 盘后自动更新财务数据 -- 可手动强制刷新最新数据 +### 2. 查看AI分析 +1. 点击股票行右侧的分析按钮 +2. 选择需要的分析维度(基础/道德经/大咖) +3. 等待AI分析结果 -## 开发指南 +### 3. 指数行情查看 +1. 点击顶部导航栏的"指数行情" +2. 查看实时指数数据和K线图 -### 代码规范 -- 遵循 PEP 8 编码规范 -- 使用类型注解 -- 保持代码简洁清晰 +## ⚠️ 注意事项 -### 目录结构说明 -- `api/`: API路由和接口定义 -- `models/`: 数据模型和结构定义 -- `services/`: 业务逻辑和服务实现 -- `templates/`: 前端页面模板 +1. API使用限制 + - Tushare免费账号有调用频率限制 + - 豆包大模型API有Token限制 -### 扩展开发 -1. 添加新的数据源 - - 在 `services` 中添加新的服务类 - - 实现数据获取和处理方法 +2. 数据时效性 + - 行情数据实时更新 + - AI分析结果默认缓存1小时 -2. 扩展AI分析 - - 修改 `ai_analysis_service.py` - - 添加新的分析维度和方法 +3. 系统性能 + - 建议监控股票数量不超过30只 + - 定时刷新间隔建议60秒以上 -3. 自定义UI - - 修改 `templates` 中的HTML文件 - - 更新样式和交互逻辑 - -## 维护说明 - -### 数据更新 -- A股交易时段实时行情更新 -- 每日收盘后自动更新财务数据 -- 定期同步公司公告信息 -- 可配置更新频率 - -### 错误处理 -- 完善的错误提示 -- 异常捕获和处理 -- 日志记录 - -## 贡献指南 - -欢迎提交 Issue 和 Pull Request: -1. Fork 本仓库 -2. 创建特性分支 -3. 提交变更 -4. 发起 Pull Request - -## 许可证 +## 📄 许可证 MIT License -## 联系方式 +## 🤝 贡献指南 -- 作者:ZYJ -- 邮箱:693696817@qq.com +1. Fork 本仓库 +2. 新建 feature_xxx 分支 +3. 提交代码 +4. 新建 Pull Request -## 更新日志 - -### v1.0.0 (2024-03) -- 支持全部 A 股上市公司监控 -- 实现核心功能:实时行情、AI 分析、财务分析 -- 完成基础框架搭建 -- 优化 A 股特色分析逻辑 - -## 配置说明 - -在运行系统之前,需要配置以下API密钥: - -1. **Tushare API Token** - - 访问 [Tushare官网](https://tushare.pro/) - - 注册并登录账号 - - 在个人中心获取Token - - 将Token填入 `config.json` 的 `tushare_token` 字段 - -2. **豆包大模型 API Key** - - 访问 [豆包大模型](https://www.doubao.com/) - - 注册并登录账号 - - 在控制台获取API Key和模型ID - - 将API Key填入 `config.json` 的 `ai_api_key` 字段 - - 将模型ID填入 `config.json` 的 `ai_model_id` 字段 - -配置文件示例 (`config.json`): -```json -{ - "watchlist": {}, - "tushare_token": "your_tushare_token_here", - "ai_api_key": "your_ai_api_key_here", - "ai_model_id": "your_ai_model_id_here" -} -``` - -注意:请妥善保管你的API密钥,不要将其提交到代码仓库中。 \ No newline at end of file +欢迎提交Issue和Pull Request! \ No newline at end of file diff --git a/app/__init__.py b/app/__init__.py index fb76ee6..c8e2d15 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -11,7 +11,7 @@ Config.ensure_directories() app = FastAPI() # 设置tushare token -ts.set_token(Config.get_tushare_token()) +ts.set_token(Config.TUSHARE_TOKEN) pro = ts.pro_api() # Mount static files diff --git a/app/api/stock_routes.py b/app/api/stock_routes.py index b908a32..cceaa0d 100644 --- a/app/api/stock_routes.py +++ b/app/api/stock_routes.py @@ -68,7 +68,7 @@ async def get_value_analysis(stock_code: str): return stock_service.get_value_analysis_data(stock_code) @router.get("/api/ai_analysis/{stock_code}") -async def get_ai_analysis(stock_code: str): +async def get_ai_analysis(stock_code: str, force_refresh: bool = False): """获取AI价值投资分析结果""" try: # 首先获取价值分析数据 @@ -77,6 +77,47 @@ async def get_ai_analysis(stock_code: str): return analysis_data # 使用AI服务进行分析 - return ai_service.analyze_value_investment(analysis_data) + return ai_service.analyze_value_investment(analysis_data, force_refresh) except Exception as e: - return {"error": f"AI分析失败: {str(e)}"} \ No newline at end of file + return {"error": f"AI分析失败: {str(e)}"} + +@router.post("/api/update_target") +async def update_target( + stock_code: str = Form(...), + target_market_value_min: Optional[float] = Form(None), + target_market_value_max: Optional[float] = Form(None) +): + """更新股票的目标市值""" + return stock_service.update_target(stock_code, target_market_value_min, target_market_value_max) + +@router.get("/api/tao_analysis/{stock_code}") +async def get_tao_analysis(stock_code: str): + """获取基于道德经的公司分析""" + try: + # 首先获取公司详细信息 + company_info = stock_service.get_company_detail(stock_code) + if "error" in company_info: + return company_info + + # 使用AI服务进行道德经分析 + return ai_service.analyze_tao_philosophy(company_info) + except Exception as e: + return {"error": f"道德经分析失败: {str(e)}"} + +@router.get("/api/master_analysis/{stock_code}") +async def get_master_analysis(stock_code: str): + """获取价值投资大咖的分析结果""" + try: + # 首先获取公司详细信息和财务数据 + company_info = stock_service.get_company_detail(stock_code) + if "error" in company_info: + return company_info + + value_analysis = stock_service.get_value_analysis_data(stock_code) + if "error" in value_analysis: + return value_analysis + + # 使用AI服务进行大咖分析 + return ai_service.analyze_by_masters(company_info, value_analysis) + except Exception as e: + return {"error": f"价值投资大咖分析失败: {str(e)}"} \ No newline at end of file diff --git a/app/config.py b/app/config.py index 2ef8fa0..7ea0fc3 100644 --- a/app/config.py +++ b/app/config.py @@ -1,11 +1,13 @@ import os -import json # 基础配置 class Config: # 项目根目录 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + # Tushare API配置 + TUSHARE_TOKEN = '90f8a141125e1decb952cd49032b7b8409a2d7fa370745f6c9f45c96' + # 配置文件路径 CONFIG_FILE = os.path.join(BASE_DIR, "config.json") @@ -15,29 +17,6 @@ class Config: # 静态文件目录 STATIC_DIR = os.path.join(BASE_DIR, "app", "static") - # API配置 - @classmethod - def load_config(cls): - if os.path.exists(cls.CONFIG_FILE): - with open(cls.CONFIG_FILE, 'r', encoding='utf-8') as f: - return json.load(f) - return {"watchlist": {}} - - @classmethod - def get_tushare_token(cls): - config = cls.load_config() - return config.get('tushare_token') - - @classmethod - def get_ai_api_key(cls): - config = cls.load_config() - return config.get('ai_api_key') - - @classmethod - def get_ai_model_id(cls): - config = cls.load_config() - return config.get('ai_model_id') - # 确保目录存在 @classmethod def ensure_directories(cls): diff --git a/app/services/ai_analysis_service.py b/app/services/ai_analysis_service.py index b6fa63f..a8de894 100644 --- a/app/services/ai_analysis_service.py +++ b/app/services/ai_analysis_service.py @@ -1,24 +1,115 @@ import json import os -import re from openai import OpenAI from app.config import Config class AIAnalysisService: def __init__(self): - self.model = Config.get_ai_model_id() # 从配置获取 model ID + # 配置OpenAI客户端连接到Volces API + self.model = os.getenv('VOLCES_MODEL_ID', 'your_model_id_here') # 从环境变量获取 self.client = OpenAI( - api_key = Config.get_ai_api_key(), # 从配置获取 API Key - base_url = "https://ark.cn-beijing.volces.com/api/v3" + api_key = os.getenv('VOLCES_API_KEY', 'your_api_key_here'), # 从环境变量获取 + base_url = os.getenv('VOLCES_BASE_URL', 'https://ark.cn-beijing.volces.com/api/v3') ) + # 创建AI分析结果缓存目录 + self.cache_dir = os.path.join(Config.BASE_DIR, "ai_stock_analysis") + self.dao_cache_dir = os.path.join(Config.BASE_DIR, "dao_analysis") + self.daka_cache_dir = os.path.join(Config.BASE_DIR, "daka_analysis") - def analyze_value_investment(self, analysis_data): + # 确保所有缓存目录存在 + for directory in [self.cache_dir, self.dao_cache_dir, self.daka_cache_dir]: + if not os.path.exists(directory): + os.makedirs(directory) + + def get_cache_path(self, stock_code: str) -> str: + """获取缓存文件路径""" + return os.path.join(self.cache_dir, f"{stock_code}.json") + + def get_dao_cache_path(self, stock_code: str) -> str: + """获取道德经分析缓存文件路径""" + return os.path.join(self.dao_cache_dir, f"{stock_code}.json") + + def get_daka_cache_path(self, stock_code: str) -> str: + """获取大咖分析缓存文件路径""" + return os.path.join(self.daka_cache_dir, f"{stock_code}.json") + + def load_cache(self, stock_code: str): + """加载缓存的AI分析结果""" + cache_path = self.get_cache_path(stock_code) + if os.path.exists(cache_path): + try: + with open(cache_path, 'r', encoding='utf-8') as f: + return json.load(f) + except Exception as e: + print(f"读取AI分析缓存失败: {str(e)}") + return None + + def save_cache(self, stock_code: str, analysis_result: dict): + """保存AI分析结果到缓存""" + cache_path = self.get_cache_path(stock_code) + try: + with open(cache_path, 'w', encoding='utf-8') as f: + json.dump(analysis_result, f, ensure_ascii=False, indent=4) + except Exception as e: + print(f"保存AI分析缓存失败: {str(e)}") + + def load_dao_cache(self, stock_code: str): + """加载缓存的道德经分析结果""" + cache_path = self.get_dao_cache_path(stock_code) + if os.path.exists(cache_path): + try: + with open(cache_path, 'r', encoding='utf-8') as f: + return json.load(f) + except Exception as e: + print(f"读取道德经分析缓存失败: {str(e)}") + return None + + def save_dao_cache(self, stock_code: str, analysis_result: dict): + """保存道德经分析结果到缓存""" + cache_path = self.get_dao_cache_path(stock_code) + try: + with open(cache_path, 'w', encoding='utf-8') as f: + json.dump(analysis_result, f, ensure_ascii=False, indent=4) + except Exception as e: + print(f"保存道德经分析缓存失败: {str(e)}") + + def load_daka_cache(self, stock_code: str): + """加载缓存的大咖分析结果""" + cache_path = self.get_daka_cache_path(stock_code) + if os.path.exists(cache_path): + try: + with open(cache_path, 'r', encoding='utf-8') as f: + return json.load(f) + except Exception as e: + print(f"读取大咖分析缓存失败: {str(e)}") + return None + + def save_daka_cache(self, stock_code: str, analysis_result: dict): + """保存大咖分析结果到缓存""" + cache_path = self.get_daka_cache_path(stock_code) + try: + with open(cache_path, 'w', encoding='utf-8') as f: + json.dump(analysis_result, f, ensure_ascii=False, indent=4) + except Exception as e: + print(f"保存大咖分析缓存失败: {str(e)}") + + def analyze_value_investment(self, analysis_data: dict, force_refresh: bool = False): """ 对股票进行价值投资分析 :param analysis_data: 包含各项财务指标的字典 + :param force_refresh: 是否强制刷新分析结果 :return: AI分析结果 """ try: + stock_code = analysis_data["stock_info"]["code"] + + # 如果不是强制刷新,尝试从缓存加载 + if not force_refresh: + cached_result = self.load_cache(stock_code) + if cached_result: + print(f"从缓存加载AI分析结果: {stock_code}") + return cached_result + # 打印输入数据用于调试 print(f"输入的分析数据: {json.dumps(analysis_data, ensure_ascii=False, indent=2)}") @@ -53,16 +144,15 @@ class AIAnalysisService: analysis_result = json.loads(analysis_text) print(f"解析后的JSON结果: {json.dumps(analysis_result, ensure_ascii=False, indent=2)}") - # 构建完整的返回结果 - result = analysis_result + # 保存到缓存 + self.save_cache(stock_code, analysis_result) - print(f"最终返回结果: {json.dumps(result, ensure_ascii=False, indent=2)}") - return result + return analysis_result except json.JSONDecodeError as e: print(f"JSON解析失败: {str(e)}") # 如果JSON解析失败,返回错误信息 - return { + error_result = { 'stock_info': analysis_data.get('stock_info', {}), 'valuation': analysis_data.get('valuation', {}), 'profitability': analysis_data.get('profitability', {}), @@ -76,12 +166,10 @@ class AIAnalysisService: "raw_text": analysis_text } } - + return error_result + except Exception as e: print(f"AI分析失败: {str(e)}") - print(f"错误详情: {e.__class__.__name__}") - import traceback - print(f"错误堆栈: {traceback.format_exc()}") return {"error": f"AI分析失败: {str(e)}"} def _parse_analysis_result(self, analysis_text, current_price): @@ -285,7 +373,7 @@ class AIAnalysisService: analysis_requirements = """ 请基于以上数据,从价值投资的角度进行分析。请特别注意: 1. 结合行业特点、公司竞争力、成长性等因素,给出合理的估值区间 -2. 存货周转率为0可能表示数据缺失,分析时需要谨慎对待 +2. 某些数据可能缺失或异常,分析时需要谨慎对待,或者从东财choice获取 3. 考虑当前市场环境和行业整体估值水平 在给出估值区间时,请充分考虑: @@ -300,10 +388,332 @@ class AIAnalysisService: 1. investment_suggestion: 投资建议,包含summary(总体建议)、action(具体操作建议)和key_points(关注重点) 2. analysis: 详细分析,包含估值分析、财务健康状况、成长潜力和风险评估 3. price_analysis: 价格分析,包含合理价格区间和目标市值区间 +实例: + "price_analysis": { + "合理价格区间": [ + xxx, + xxx + ], + "目标市值区间": [ + xxx, + xxx + ] 请确保返回的是一个有效的JSON格式,数值使用数字而不是字符串(价格、市值等),文本分析使用字符串。分析要客观、专业、详细。""" # 组合完整的提示词 prompt = data_section + analysis_requirements + return prompt + + def analyze_tao_philosophy(self, company_info: dict, force_refresh: bool = False): + """ + 基于道德经理念分析公司 + :param company_info: 公司信息 + :param force_refresh: 是否强制刷新分析结果 + :return: AI分析结果 + """ + try: + stock_code = company_info.get('basic_info', {}).get('code') + + # 如果不是强制刷新,尝试从缓存加载 + if not force_refresh and stock_code: + cached_result = self.load_dao_cache(stock_code) + if cached_result: + print(f"从缓存加载道德经分析结果: {stock_code}") + return cached_result + + # 构建提示词 + prompt = self._build_tao_analysis_prompt(company_info) + + # 调用API + response = self.client.chat.completions.create( + model=self.model, + messages=[ + { + "role": "user", + "content": prompt + } + ] + ) + + # 获取分析结果 + analysis_text = response.choices[0].message.content + + try: + # 解析JSON结果 + analysis_result = json.loads(analysis_text) + + # 保存到缓存 + if stock_code: + self.save_dao_cache(stock_code, analysis_result) + + return analysis_result + except json.JSONDecodeError as e: + print(f"道德经分析结果JSON解析失败: {str(e)}") + return {"error": "分析结果格式错误"} + + except Exception as e: + print(f"道德经分析失败: {str(e)}") + return {"error": f"道德经分析失败: {str(e)}"} + + def _build_tao_analysis_prompt(self, company_info: dict): + """ + 构建道德经分析提示词 + """ + basic_info = company_info.get('basic_info', {}) + + prompt = f"""请作为一位精通道德经的智者,运用道德经的智慧来分析{basic_info.get('name', '')}({basic_info.get('code', '')})这家公司。 + +公司基本信息: +- 公司名称:{basic_info.get('name', '')} +- 所属行业:{basic_info.get('industry', '')} +- 主营业务:{basic_info.get('main_business', '')} +- 经营范围:{basic_info.get('business_scope', '')} +- 公司简介:{basic_info.get('introduction', '')} + +请从道德经的智慧角度,分析以下几个方面: + +1. 道德经视角: +- 公司的经营理念是否符合"道法自然"的原则 +- 企业的发展是否遵循"无为而治"的智慧 +- 公司是否体现"上善若水"的品质 +- 管理方式是否符合"柔弱胜刚强"的道理 + +2. 企业道德评估: +- 公司对待员工、客户、供应商的态度 +- 企业的社会责任感和可持续发展理念 +- 公司的价值观和企业文化 +- 经营中的道德风险评估 + +3. 投资建议: +- 基于道德经智慧的投资建议 +- 长期发展潜力分析 +- 需要关注的风险点 +- 持有建议 + +请以JSON格式返回分析结果,包含以下字段: +1. tao_philosophy: 道德经视角的分析 +2. business_ethics: 企业道德评估 +3. investment_advice: 投资建议 + +分析要客观、专业、深入,同时体现道德经的智慧。""" + + return prompt + + def analyze_by_masters(self, company_info: dict, value_analysis: dict, force_refresh: bool = False): + """ + 基于各位价值投资大咖的理念分析公司 + :param company_info: 公司信息 + :param value_analysis: 价值分析数据 + :param force_refresh: 是否强制刷新分析结果 + :return: AI分析结果 + """ + try: + stock_code = company_info.get('basic_info', {}).get('code') + + # 如果不是强制刷新,尝试从缓存加载 + if not force_refresh and stock_code: + cached_result = self.load_daka_cache(stock_code) + if cached_result: + print(f"从缓存加载大咖分析结果: {stock_code}") + return cached_result + + # 打印输入数据用于调试 + print(f"公司信息: {json.dumps(company_info, ensure_ascii=False, indent=2)}") + print(f"价值分析数据: {json.dumps(value_analysis, ensure_ascii=False, indent=2)}") + + # 构建提示词 + prompt = self._build_masters_analysis_prompt(company_info, value_analysis) + + # 打印提示词用于调试 + print(f"大咖分析提示词: {prompt}") + + # 调用API + response = self.client.chat.completions.create( + model=self.model, + messages=[ + { + "role": "user", + "content": prompt + } + ] + ) + + # 获取分析结果 + analysis_text = response.choices[0].message.content + print(f"AI原始返回结果: {analysis_text}") + + try: + # 解析JSON结果 + analysis_result = json.loads(analysis_text) + print(f"解析后的JSON结果: {json.dumps(analysis_result, ensure_ascii=False, indent=2)}") + + # 保存到缓存 + if stock_code: + self.save_daka_cache(stock_code, analysis_result) + + return analysis_result + except json.JSONDecodeError as e: + print(f"大咖分析结果JSON解析失败: {str(e)}") + return {"error": "分析结果格式错误"} + + except Exception as e: + print(f"价值投资大咖分析失败: {str(e)}") + return {"error": f"价值投资大咖分析失败: {str(e)}"} + + def _build_masters_analysis_prompt(self, company_info: dict, value_analysis: dict): + """ + 构建价值投资大咖分析提示词 + """ + basic_info = company_info.get('basic_info', {}) + + # 从value_analysis中获取财务数据 + valuation = value_analysis.get('valuation', {}) + profitability = value_analysis.get('profitability', {}) + growth = value_analysis.get('growth', {}) + operation = value_analysis.get('operation', {}) + solvency = value_analysis.get('solvency', {}) + cash_flow = value_analysis.get('cash_flow', {}) + per_share = value_analysis.get('per_share', {}) + stock_info = value_analysis.get('stock_info', {}) + + # 格式化百分比 + def format_percent(value): + if value is None: + return '-' + try: + if isinstance(value, str): + value = float(value) + if abs(value) <= 1: + value = value * 100 + return f"{value:.2f}%" + except: + return '-' + + # 格式化数字 + def format_number(value): + if value is None: + return '-' + try: + if isinstance(value, str): + value = float(value) + return f"{value:.4f}" + except: + return '-' + + prompt = f"""请分别以五位价值投资大咖的视角,分析{basic_info.get('name', '')}({basic_info.get('code', '')})这家公司。 + +公司基本信息: +- 公司名称:{basic_info.get('name', '')} +- 所属行业:{basic_info.get('industry', '')} +- 主营业务:{basic_info.get('main_business', '')} +- 经营范围:{basic_info.get('business_scope', '')} +- 公司简介:{basic_info.get('introduction', '')} +- 法人代表:{basic_info.get('chairman', '')} +- 总经理:{basic_info.get('manager', '')} +- 注册资本:{basic_info.get('reg_capital', '')}万元 +- 员工人数:{basic_info.get('employees', '')}人 +- 成立日期:{basic_info.get('setup_date', '')} +- 上市日期:{basic_info.get('list_date', '')} + +当前市场信息: +- 当前股价:{format_number(stock_info.get('current_price'))}元 +- 总市值:{format_number(valuation.get('total_market_value'))}亿元 +- 流通市值:{format_number(valuation.get('circulating_market_value'))}亿元 +- 流通比例:{format_percent(valuation.get('circulating_ratio'))} +- 换手率:{format_percent(stock_info.get('turnover_ratio'))} + +估值指标: +- 市盈率(PE):{format_number(valuation.get('pe_ratio'))} +- 市净率(PB):{format_number(valuation.get('pb_ratio'))} +- 市销率(PS):{format_number(valuation.get('ps_ratio'))} +- 股息率:{format_percent(valuation.get('dividend_yield'))} + +盈利能力指标: +- ROE:{format_percent(profitability.get('roe'))} +- ROE(扣非):{format_percent(profitability.get('deducted_roe'))} +- ROA:{format_percent(profitability.get('roa'))} +- 毛利率:{format_percent(profitability.get('gross_margin'))} +- 净利率:{format_percent(profitability.get('net_margin'))} + +成长能力指标: +- 净利润增长率:{format_percent(growth.get('net_profit_growth'))} +- 扣非净利润增长率:{format_percent(growth.get('deducted_net_profit_growth'))} +- 营业总收入增长率:{format_percent(growth.get('revenue_growth'))} +- 营业收入增长率:{format_percent(growth.get('operating_revenue_growth'))} + +运营能力指标: +- 总资产周转率:{format_number(operation.get('asset_turnover'))} +- 存货周转率:{format_number(operation.get('inventory_turnover'))} +- 应收账款周转率:{format_number(operation.get('receivables_turnover'))} +- 流动资产周转率:{format_number(operation.get('current_asset_turnover'))} + +偿债能力指标: +- 流动比率:{format_number(solvency.get('current_ratio'))} +- 速动比率:{format_number(solvency.get('quick_ratio'))} +- 资产负债率:{format_percent(solvency.get('debt_to_assets'))} +- 产权比率:{format_number(solvency.get('equity_ratio'))} + +现金流指标: +- 经营现金流/营收:{format_percent(cash_flow.get('ocf_to_revenue'))} +- 经营现金流/经营利润:{format_percent(cash_flow.get('ocf_to_operating_profit'))} +- 经营现金流同比增长:{format_percent(cash_flow.get('ocf_growth'))} + +每股指标: +- 每股收益(EPS):{format_number(per_share.get('eps'))}元 +- 每股收益(扣非):{format_number(per_share.get('deducted_eps'))}元 +- 每股净资产:{format_number(per_share.get('bps'))}元 +- 每股经营现金流:{format_number(per_share.get('ocfps'))}元 +- 每股留存收益:{format_number(per_share.get('retained_eps'))}元 +- 每股现金流量:{format_number(per_share.get('cfps'))}元 +- 每股息税前利润:{format_number(per_share.get('ebit_ps'))}元 + +请分别从以下五位投资大师的视角进行分析: + +1. 巴菲特视角: +- 是否具有护城河(品牌优势、规模效应、专利技术等) +- 管理层能力和诚信(从财务指标、现金流等反映的经营能力) +- 业务是否容易理解(商业模式的清晰度) +- 长期竞争优势(市场地位、核心竞争力) +- 是否是好生意(盈利能力、现金流状况) +- 以合理价格购买优秀企业的原则(估值分析) + +2. 格雷厄姆视角: +- 安全边际分析(基于净资产、市盈率等) +- 内在价值计算(基于盈利能力和资产价值) +- 财务安全性(偿债能力、资产质量) +- 是否具有投资价值(基于定量分析) +- 基于定量分析的结论(综合财务指标评估) + +3. 林园视角: +- 行业成长性(收入增长、利润增长) +- 公司治理结构(股权结构、管理层背景) +- 研发创新能力(技术优势、产品创新) +- 市场竞争格局(市场份额、竞争态势) +- 估值是否合理(相对估值和绝对估值) + +4. 李大霄视角: +- 市场地位和品牌价值(行业地位、品牌影响力) +- 行业发展趋势(产业政策、市场空间) +- 政策影响分析(行业政策、监管环境) +- 投资时机把握(技术面和基本面) +- 投资建议(综合分析结论) + +5. 段永平视角: +- 商业模式分析(盈利模式、竞争优势) +- 用户价值(产品力、客户粘性) +- 企业文化(管理理念、团队建设) +- 长期发展潜力(成长空间、持续经营能力) +- 是否值得长期持有(投资价值判断) + +请以JSON格式返回分析结果,包含以下字段: +1. buffett_analysis: 巴菲特的分析观点 +2. graham_analysis: 格雷厄姆的分析观点 +3. lin_yuan_analysis: 林园的分析观点 +4. li_daxiao_analysis: 李大霄的分析观点 +5. duan_yongping_analysis: 段永平的分析观点 + +分析要客观、专业、深入,并体现每位投资大师的独特投资理念。请基于上述详细的财务数据进行分析(如果指标缺失或异常,请联网获取),尤其是定量指标的解读。""" + return prompt \ No newline at end of file diff --git a/app/services/stock_service.py b/app/services/stock_service.py index 7fa008a..a24fa6a 100644 --- a/app/services/stock_service.py +++ b/app/services/stock_service.py @@ -226,6 +226,20 @@ class StockService: self._save_watchlist() return {"status": "success"} + def update_target(self, stock_code: str, target_market_value_min: float = None, target_market_value_max: float = None): + """更新股票的目标市值""" + if stock_code not in self.watchlist: + return {"error": "股票不在监控列表中"} + + self.watchlist[stock_code] = { + "target_market_value": { + "min": target_market_value_min, + "max": target_market_value_max + } + } + self._save_watchlist() + return {"status": "success"} + def get_index_info(self): """获取主要指数数据""" try: diff --git a/app/templates/index.html b/app/templates/index.html index 5928e94..c976c2d 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -642,8 +642,13 @@