Compare commits

...

10 Commits

Author SHA1 Message Date
monkey
e5c6aab89e
update README.md.
Signed-off-by: monkey <693696817@qq.com>
2025-09-11 11:05:07 +00:00
monkey
d79f6fedce
update README.md.
Signed-off-by: monkey <693696817@qq.com>
2025-09-11 10:56:55 +00:00
monkey
9ac4003fcf
update README.md.
环境配置方法修正

Signed-off-by: monkey <693696817@qq.com>
2025-09-11 10:51:41 +00:00
monkey
f693e3eef0
update app/services/ai_analysis_service.py.
class AIAnalysisService:
    def __init__(self):
        # 配置OpenAI客户端连接到Volces API
        self.model = ""  # Volces 模型接入点ID
        self.client = OpenAI(
            api_key = "",  # 豆包大模型APIkey
            base_url = "https://ark.cn-beijing.volces.com/api/v3"
        )

Signed-off-by: monkey <693696817@qq.com>
2025-09-11 10:47:59 +00:00
monkey
03fff3fc9e
update README.md.
Signed-off-by: monkey <693696817@qq.com>
2025-01-15 13:10:16 +00:00
monkey
0665de1ca6
update README.md.
Signed-off-by: monkey <693696817@qq.com>
2025-01-15 13:05:09 +00:00
zyj118
6f03031e3e docs: 更新README,完善豆包大模型API申请说明 2025-01-15 15:15:14 +08:00
monkey
13afb93569
add LICENSE.
Signed-off-by: monkey <693696817@qq.com>
2025-01-15 07:09:48 +00:00
zyj118
5926fa5f46 初始化提交:AI价值投资盯盘系统 2025-01-15 14:41:21 +08:00
zyj118
7ad16b0a1b docs: 更新AI API获取说明为豆包大模型 2025-01-13 20:17:36 +08:00
21 changed files with 1870 additions and 553 deletions

7
.env.example Normal file
View File

@ -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

22
.gitignore vendored
View File

@ -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
Thumbs.db

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 monkey
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

315
README.md
View File

@ -1,238 +1,165 @@
# 价值投资盯盘系统
# AI价值投资盯盘系统
一个专注于中国 A 股市场的智能股票分析与监控平台,基于 Python FastAPI 开发集成实时行情监控、AI 智能分析和价值投资建议等功能,助力投资者进行理性的价值投资决策
一个基于Python的A股智能监控和AI分析系统集成了多维度的投资分析功能包括传统价值投资分析、道德经智慧分析以及知名投资大师的视角分析
## 功能特点
## 系统界面预览
![系统主界面](docs/images/main.png)
![输入图片说明](docs/images/image2.png)
![输入图片说明](docs/images/image.png)
## 🚀 核心功能
### 1. A股实时监控
- 支持所有 A 股上市公司的实时监控
- 沪深两市实时价格和涨跌幅更新
- 自定义市值目标区间预警
- 个股交易状态实时提示
### 1. 股票监控
- 实时股票数据监控
- 自定义目标市值设置
- 目标市值预警(高估,低估,合理)
- 多维度指标展示PE、PB、ROE等价值投资指标
### 2. AI 智能分析
- 基于中国市场特点的智能投资建议
- A股市场合理价格区间估算
- 结合中国经济环境的目标市值评估
- 多维度分析报告:
- A股市场估值分析
- 中国特色财务健康状况评估
- 行业对标成长潜力评估
- 系统性风险评估
### 2. 指数行情
- 主要指数实时行情展示
### 3. A股财务指标分析
- 估值指标PE市盈率、PB市净率、PS市销率
- 盈利能力ROE净资产收益率、毛利率、净利率
- 成长能力:营收增长、利润增长、研发投入
- 运营效率:资产周转率、存货周转率等
- 偿债能力:资产负债率、流动比率等
- 现金流指标:经营现金流、自由现金流等
### 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数据可视化
- jQueryDOM操作
- WebSocket实时数据推送
1. 克隆项目
## 📦 安装部署
### 1. 环境准备
```bash
git clone https://github.com/693696817/stock-monitor.git
# 克隆项目
git clone https://gitee.com/zyj118/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/register?reg=431380)
2. 注册并获取Token
3. 可选:充值获取更高级别权限
#### 豆包大模型API
1. 访问[火山引擎豆包大模型](https://www.volcengine.com/product/doubao)
2. 注册账号(支持个人开发者注册)
3. 进入控制台创建应用
4. 获取API Key和Model ID
5. 按量付费,支持免费额度体验
### 3. 环境配置
修改配置文件
找到app/services/ai_analysis_service.py 替换自己API的模型接入点ID豆包大模型APIkeybase_url 。
![输入图片说明](16915e87-8099-402c-80d4-f4018d56dcf9.png)
```
class AIAnalysisService:
def __init__(self):
# 配置OpenAI客户端连接到Volces API
self.model = "" # Volces 模型接入点ID
self.client = OpenAI(
api_key = "", # 豆包大模型APIkey
base_url = "https://ark.cn-beijing.volces.com/api/v3"
)
```
5. 运行
### 4. 启动系统
```bash
python run.py
```
访问 http://localhost:8000 即可使用系统
6. 访问
- 打开浏览器访问 `http://localhost:8000`
- 默认端口为 8000可在 `run.py` 中修改
## 🤝 联系作者
## 使用指南
如果您对系统有任何问题或建议,欢迎联系:
### 添加监控股票
1. 在主页面顶部输入 A 股股票代码6位数字000001
2. 可选择设置目标市值区间
3. 点击"添加"按钮开始监控
- 微信zyj118
- QQ693696817
- Email693696817@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提供免费额度超出后按量计费
### 扩展开发
1. 添加新的数据源
- 在 `services` 中添加新的服务类
- 实现数据获取和处理方法
2. 数据时效性
- 行情数据实时更新
- AI分析结果默认缓存1小时
2. 扩展AI分析
- 修改 `ai_analysis_service.py`
- 添加新的分析维度和方法
3. 系统性能
- 建议监控股票数量不超过30只
- 定时刷新间隔建议60秒以上
3. 自定义UI
- 修改 `templates` 中的HTML文件
- 更新样式和交互逻辑
4.投资有风险入市需谨慎。此系统仅为基于大数据和AI大模型的价值投资辅助分析并不构成任何操作建议风险自担
## 维护说明
### 数据更新
- 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. **AI分析服务 API Key**
- 访问 [Volcengine智能对话](https://www.volcengine.com/product/intelligent-chat)
- 注册企业账号并开通服务
- 在控制台获取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密钥不要将其提交到代码仓库中。
欢迎提交Issue和Pull Request
本系统欢迎任何形式的二次开发,如果您觉得该系统对您有帮助,欢迎打赏!您对作者的鼓励是更新该系统的动力!
![输入图片说明](docs/images/wechat.png)

View File

@ -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

View File

@ -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)}"}
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)}"}

View File

@ -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):

View File

@ -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 = "" # Volces 模型接入点ID
self.client = OpenAI(
api_key = Config.get_ai_api_key(), # 从配置获取 API Key
api_key = "", # 豆包大模型APIkey
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

View File

@ -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:

View File

@ -642,8 +642,13 @@
<!-- AI价值投资分析模块 -->
<div class="col-12">
<div class="card">
<div class="card-header bg-light">
<i class="bi bi-robot"></i> AI价值投资分析
<div class="card-header bg-light d-flex justify-content-between align-items-center">
<div>
<i class="bi bi-robot"></i> AI价值投资分析
</div>
<button class="btn btn-outline-primary btn-sm" onclick="refreshAIAnalysis()" id="refreshAIBtn">
<i class="bi bi-arrow-repeat"></i> 更新分析
</button>
</div>
<div class="card-body">
<div id="aiAnalysisError" class="alert alert-danger d-none">
@ -785,6 +790,203 @@
</div>
</footer>
<!-- 编辑目标市值弹窗 -->
<div class="modal fade" id="editTargetModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">编辑监控目标</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form id="editTargetForm">
<input type="hidden" id="editStockCode" name="stock_code">
<div class="mb-3">
<label class="form-label">目标市值区间 (亿元)</label>
<div class="input-group">
<input type="number" step="0.01" class="form-control" id="editTargetMin"
name="target_market_value_min" placeholder="最小值">
<span class="input-group-text">-</span>
<input type="number" step="0.01" class="form-control" id="editTargetMax"
name="target_market_value_max" placeholder="最大值">
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary" onclick="updateTarget()">保存</button>
</div>
</div>
</div>
</div>
<!-- 道德经分析弹窗 -->
<div class="modal fade" id="taoAnalysisModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">道德经分析</h5>
<div class="ms-auto me-2">
<button type="button" class="btn btn-outline-primary btn-sm" onclick="refreshTaoAnalysis()">
<i class="bi bi-arrow-clockwise"></i> 更新分析
</button>
</div>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div id="taoAnalysisError" class="alert alert-danger d-none">
<!-- 错误信息将在这里显示 -->
</div>
<div id="taoAnalysisLoading" class="text-center py-4 d-none">
<div class="spinner-border text-success" role="status">
<span class="visually-hidden">分析中...</span>
</div>
<div class="mt-2 text-muted">以道德经智慧分析中,请稍候...</div>
</div>
<div id="taoAnalysisContent">
<div class="card mb-4">
<div class="card-header bg-light">
<i class="bi bi-book"></i> 道德经视角
</div>
<div class="card-body">
<div id="taoPhilosophy" class="mb-4">
<!-- 道德经哲学分析将在这里显示 -->
</div>
</div>
</div>
<div class="card mb-4">
<div class="card-header bg-light">
<i class="bi bi-building"></i> 企业道德评估
</div>
<div class="card-body">
<div id="businessEthics" class="mb-4">
<!-- 企业道德评估将在这里显示 -->
</div>
</div>
</div>
<div class="card">
<div class="card-header bg-light">
<i class="bi bi-lightbulb"></i> 投资建议
</div>
<div class="card-body">
<div id="taoAdvice">
<!-- 基于道德经的投资建议将在这里显示 -->
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 价值投资大咖分析弹窗 -->
<div class="modal fade" id="masterAnalysisModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">价值投资大咖分析</h5>
<div class="ms-auto me-2">
<button type="button" class="btn btn-outline-primary btn-sm" onclick="refreshMasterAnalysis()">
<i class="bi bi-arrow-clockwise"></i> 更新分析
</button>
</div>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div id="masterAnalysisError" class="alert alert-danger d-none">
<!-- 错误信息将在这里显示 -->
</div>
<div id="masterAnalysisLoading" class="text-center py-4 d-none">
<div class="spinner-border text-warning" role="status">
<span class="visually-hidden">分析中...</span>
</div>
<div class="mt-2 text-muted">大咖们正在分析,请稍候...</div>
</div>
<div id="masterAnalysisContent">
<!-- 巴菲特分析 -->
<div class="card mb-4">
<div class="card-header bg-light d-flex align-items-center">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/5/51/Warren_Buffett_KU_Visit.jpg/120px-Warren_Buffett_KU_Visit.jpg"
class="rounded-circle me-2" style="width: 30px; height: 30px; object-fit: cover;"
alt="Warren Buffett">
<span>巴菲特视角</span>
</div>
<div class="card-body">
<div id="buffettAnalysis" class="mb-4">
<!-- 巴菲特分析将在这里显示 -->
</div>
</div>
</div>
<!-- 格雷厄姆分析 -->
<div class="card mb-4">
<div class="card-header bg-light d-flex align-items-center">
<img src="https://upload.wikimedia.org/wikipedia/en/thumb/5/5e/Benjamin_Graham.jpg/120px-Benjamin_Graham.jpg"
class="rounded-circle me-2" style="width: 30px; height: 30px; object-fit: cover;"
alt="Benjamin Graham">
<span>格雷厄姆视角</span>
</div>
<div class="card-body">
<div id="grahamAnalysis" class="mb-4">
<!-- 格雷厄姆分析将在这里显示 -->
</div>
</div>
</div>
<!-- 林园分析 -->
<div class="card mb-4">
<div class="card-header bg-light d-flex align-items-center">
<img src="https://pic3.zhimg.com/v2-f6a12dbc2d5f6e7f9c4f2e4e5c9c9c9c_720w.jpg"
class="rounded-circle me-2" style="width: 30px; height: 30px; object-fit: cover;"
alt="林园">
<span>林园视角</span>
</div>
<div class="card-body">
<div id="linYuanAnalysis" class="mb-4">
<!-- 林园分析将在这里显示 -->
</div>
</div>
</div>
<!-- 李大霄分析 -->
<div class="card mb-4">
<div class="card-header bg-light d-flex align-items-center">
<img src="https://img.gelonghui.com/apply/column/20200410/column_20200410112754895_31795.jpg"
class="rounded-circle me-2" style="width: 30px; height: 30px; object-fit: cover;"
alt="李大霄">
<span>李大霄视角</span>
</div>
<div class="card-body">
<div id="liDaxiaoAnalysis" class="mb-4">
<!-- 李大霄分析将在这里显示 -->
</div>
</div>
</div>
<!-- 段永平分析 -->
<div class="card">
<div class="card-header bg-light d-flex align-items-center">
<img src="https://img.caixin.com/2011-05-17/1305626275743167_840_560.jpg"
class="rounded-circle me-2" style="width: 30px; height: 30px; object-fit: cover;"
alt="段永平">
<span>段永平视角</span>
</div>
<div class="card-body">
<div id="duanYongpingAnalysis">
<!-- 段永平分析将在这里显示 -->
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
<script>
@ -793,6 +995,42 @@
let stockData = [];
let loadingStocks = new Set();
// 显示编辑目标市值弹窗
function showEditTargetModal(btn) {
const stockCode = btn.dataset.stockCode;
const targetMin = btn.dataset.targetMin;
const targetMax = btn.dataset.targetMax;
document.getElementById('editStockCode').value = stockCode;
document.getElementById('editTargetMin').value = targetMin;
document.getElementById('editTargetMax').value = targetMax;
new bootstrap.Modal(document.getElementById('editTargetModal')).show();
}
// 更新监控目标
async function updateTarget() {
const form = document.getElementById('editTargetForm');
const formData = new FormData(form);
try {
const response = await fetch('/api/update_target', {
method: 'POST',
body: formData
});
if (!response.ok) {
throw new Error(await response.text() || '更新失败');
}
bootstrap.Modal.getInstance(document.getElementById('editTargetModal')).hide();
await refreshWatchlist(true);
} catch (error) {
console.error('更新目标失败:', error);
alert('更新目标失败:' + error.message);
}
}
// 添加排序功能
document.querySelectorAll('.sortable').forEach(header => {
header.addEventListener('click', () => {
@ -910,9 +1148,12 @@
function renderStockList(data) {
const stockTableBody = document.getElementById('stockTableBody');
if (!stockTableBody) return;
// 清空现有内容
stockTableBody.innerHTML = '';
if (!data || data.length === 0) {
// 检查数据是否为空
if (!data || !Array.isArray(data) || data.length === 0) {
const emptyRow = document.createElement('tr');
emptyRow.innerHTML = '<td colspan="18" class="text-center text-muted py-4">暂无监控的股票</td>';
stockTableBody.appendChild(emptyRow);
@ -921,14 +1162,15 @@
}
// 排序数据
let sortedData = [...data];
if (currentSortField) {
data.sort((a, b) => {
sortedData.sort((a, b) => {
let aValue = parseFloat(a.stock_info[currentSortField]);
let bValue = parseFloat(b.stock_info[currentSortField]);
// 处理无效值
if (aValue === null || aValue === undefined || isNaN(aValue)) aValue = -Infinity;
if (bValue === null || bValue === undefined || isNaN(bValue)) bValue = -Infinity;
if (isNaN(aValue)) aValue = -Infinity;
if (isNaN(bValue)) bValue = -Infinity;
// 数值比较
const comparison = aValue - bValue;
@ -936,8 +1178,11 @@
});
}
data.forEach(item => {
// 渲染每一行
sortedData.forEach(item => {
const { stock_info, targets } = item;
if (!stock_info) return; // 跳过无效数据
const row = document.createElement('tr');
row.setAttribute('data-stock-code', stock_info.code);
@ -951,10 +1196,29 @@
<a href="javascript:void(0)" onclick="showCompanyDetail('${stock_info.code}')" class="text-primary">
${stock_info.name || '-'}
</a>
<button class="btn btn-link btn-sm p-0 ms-2 text-danger"
onclick="showTaoAnalysis('${stock_info.code}')"
title="道德经分析">
<i class="bi bi-yin-yang"></i>
</button>
<button class="btn btn-link btn-sm p-0 ms-2 text-dark"
onclick="showMasterAnalysis('${stock_info.code}')"
title="价值投资大咖分析">
<i class="bi bi-person-fill"></i>
</button>
</td>
<td>${formatNumber(stock_info.price)}</td>
<td>${formatPercent(stock_info.change_percent)}</td>
<td>${formatTargetRange(targets.target_market_value)}</td>
<td>${formatTargetRange(targets.target_market_value)}
<button class="btn btn-link btn-sm p-0 ms-2 text-primary edit-target-btn"
data-stock-code="${stock_info.code}"
data-target-min="${targets.target_market_value?.min || ''}"
data-target-max="${targets.target_market_value?.max || ''}"
onclick="showEditTargetModal(this)"
title="编辑目标市值">
<i class="bi bi-pencil"></i>
</button>
</td>
<td>${formatNumber(stock_info.market_value, true)}</td>
<td>${formatNumber(stock_info.pe_ratio, true)}</td>
<td>${formatNumber(stock_info.pb_ratio, true)}</td>
@ -981,47 +1245,6 @@
document.getElementById('stockCount').textContent = data.length;
}
// 更新单个股票数据
function updateStockData(stockData) {
const row = document.querySelector(`tr[data-stock-code="${stockData.stock_info.code}"]`);
if (!row) return;
const { stock_info, targets } = stockData;
// 检查市值状态
const marketValueStatus = checkMarketValueStatus(stock_info.market_value, targets.target_market_value);
const marketValueIcon = getMarketValueIcon(marketValueStatus);
row.innerHTML = `
<td>${stock_info.code}${marketValueIcon}</td>
<td>
<a href="javascript:void(0)" onclick="showCompanyDetail('${stock_info.code}')" class="text-primary">
${stock_info.name || '-'}
</a>
</td>
<td>${formatNumber(stock_info.price)}</td>
<td>${formatPercent(stock_info.change_percent)}</td>
<td>${formatTargetRange(stockData.targets.target_market_value)}</td>
<td>${formatNumber(stock_info.market_value, true)}</td>
<td>${formatNumber(stock_info.pe_ratio, true)}</td>
<td>${formatNumber(stock_info.pb_ratio, true)}</td>
<td>${formatNumber(stock_info.ps_ratio, true)}</td>
<td>${formatPercent(stock_info.dividend_yield)}</td>
<td>${formatPercent(stock_info.roe)}</td>
<td>${formatPercent(stock_info.gross_profit_margin)}</td>
<td>${formatPercent(stock_info.net_profit_margin)}</td>
<td>${formatPercent(stock_info.debt_to_assets, false, true)}</td>
<td>${formatPercent(stock_info.net_profit_yoy)}</td>
<td>${formatNumber(stock_info.bps, true)}</td>
<td>${formatNumber(stock_info.ocfps)}</td>
<td>
<button class="btn btn-sm btn-danger remove-btn" data-stock-code="${stock_info.code}">
<i class="bi bi-trash"></i>
</button>
</td>
`;
}
// 刷新监控列表
async function refreshWatchlist(forceRefresh = false) {
try {
@ -1029,32 +1252,72 @@
if (!response.ok) throw new Error('获取监控列表失败');
const data = await response.json();
if (!Array.isArray(data)) {
throw new Error('返回数据格式错误');
}
stockData = data; // 更新全局数据
renderStockList(data);
// 异步加载每个股票的详细数据
data.forEach(item => {
loadStockData(item.stock_info.code, forceRefresh);
if (item && item.stock_info && item.stock_info.code) {
loadStockData(item.stock_info.code, forceRefresh);
}
});
} catch (error) {
console.error('刷新数据失败:', error);
alert('刷新数据失败:' + error.message);
// 显示错误信息
const stockTableBody = document.getElementById('stockTableBody');
if (stockTableBody) {
stockTableBody.innerHTML = `
<tr>
<td colspan="18" class="text-center text-danger">
<i class="bi bi-exclamation-triangle"></i>
加载数据失败:${error.message}
</td>
</tr>
`;
}
}
}
// 异步加载股票数据
// 更新单个股票数据
async function loadStockData(stockCode, forceRefresh = false) {
if (!stockCode || loadingStocks.has(stockCode)) return;
try {
loadingStocks.add(stockCode);
const url = `/api/stock_info/${stockCode}${forceRefresh ? '?force_refresh=true' : ''}`;
const response = await fetch(url);
if (!response.ok) throw new Error('获取股票数据失败');
if (!response.ok) {
throw new Error('获取股票数据失败');
}
const data = await response.json();
if (data.error) throw new Error(data.error);
if (data.error) {
throw new Error(data.error);
}
updateStockData(data);
// 更新全局数据中的股票信息
const index = stockData.findIndex(item => item.stock_info.code === stockCode);
if (index !== -1) {
stockData[index] = data;
renderStockList(stockData);
}
} catch (error) {
console.error(`加载股票 ${stockCode} 数据失败:`, error);
// 在界面上显示错误状态
const row = document.querySelector(`tr[data-stock-code="${stockCode}"]`);
if (row) {
const cells = row.getElementsByTagName('td');
for (let i = 2; i < cells.length - 1; i++) {
cells[i].innerHTML = '<span class="text-danger">加载失败</span>';
}
}
} finally {
loadingStocks.delete(stockCode);
}
}
@ -1116,6 +1379,12 @@
removeStock(stockCode);
}
});
// 移除DataTable初始化代码因为我们使用原生表格排序
// 初始化指数数据
refreshIndexData();
setInterval(refreshIndexData, 60000); // 每分钟更新一次
});
// 获取指数数据
@ -1217,6 +1486,7 @@
// 显示公司详情弹窗
async function showCompanyDetail(stockCode) {
const modal = new bootstrap.Modal(document.getElementById('companyModal'));
document.getElementById('companyModal').setAttribute('data-stock-code', stockCode);
modal.show();
// 显示加载状态
@ -1509,6 +1779,235 @@
zeroRecords: "暂无数据"
}
});
// 刷新AI分析
async function refreshAIAnalysis() {
const stockCode = document.querySelector('#companyModal').getAttribute('data-stock-code');
if (!stockCode) return;
const refreshBtn = document.getElementById('refreshAIBtn');
const originalText = refreshBtn.innerHTML;
refreshBtn.innerHTML = '<i class="bi bi-arrow-repeat"></i> 分析中...';
refreshBtn.disabled = true;
try {
const response = await fetch(`/api/ai_analysis/${stockCode}?force_refresh=true`);
if (!response.ok) {
throw new Error(await response.text() || '更新失败');
}
const result = await response.json();
if (result.error) {
throw new Error(result.error);
}
// 更新AI分析显示
document.getElementById('investmentSuggestion').innerHTML = `
<div class="mb-2"><strong>总体建议:</strong>${result.investment_suggestion.summary || '-'}</div>
<div class="mb-2"><strong>建议操作:</strong>${result.investment_suggestion.action || '-'}</div>
<div><strong>关注重点:</strong>
<p class="mb-0">${result.investment_suggestion.key_points || '-'}</p>
</div>
`;
const priceRange = result.price_analysis?.合理价格区间 || [];
document.getElementById('reasonablePriceRange').innerHTML = `
<div class="mb-2">${priceRange[0] || '-'} - ${priceRange[1] || '-'} 元</div>
`;
const marketValue = result.price_analysis?.目标市值区间 || [];
document.getElementById('targetMarketValue').innerHTML = `
<div class="mb-2">${marketValue[0] || '-'} - ${marketValue[1] || '-'} 亿元</div>
`;
document.getElementById('valuationAnalysis').innerHTML = `
<div class="mb-2">${result.analysis?.估值分析 || '-'}</div>
`;
document.getElementById('financialHealth').innerHTML = `
<div>${result.analysis?.财务健康状况 || '-'}</div>
`;
document.getElementById('growthPotential').innerHTML = `
<div>${result.analysis?.成长潜力 || '-'}</div>
`;
document.getElementById('riskAssessment').innerHTML = `
<div>${result.analysis?.风险评估 || '-'}</div>
`;
} catch (error) {
console.error('更新AI分析失败', error);
alert('更新AI分析失败' + error.message);
} finally {
refreshBtn.innerHTML = originalText;
refreshBtn.disabled = false;
}
}
// 显示道德经分析弹窗
async function showTaoAnalysis(stockCode) {
const modal = new bootstrap.Modal(document.getElementById('taoAnalysisModal'));
document.getElementById('taoAnalysisModal').setAttribute('data-stock-code', stockCode);
modal.show();
// 显示加载状态
document.getElementById('taoAnalysisError').classList.add('d-none');
document.getElementById('taoAnalysisLoading').classList.remove('d-none');
document.getElementById('taoAnalysisContent').classList.add('d-none');
try {
// 获取道德经分析数据
const response = await fetch(`/api/tao_analysis/${stockCode}`);
const data = await response.json();
if (data.error) {
document.getElementById('taoAnalysisError').textContent = data.error;
document.getElementById('taoAnalysisError').classList.remove('d-none');
document.getElementById('taoAnalysisLoading').classList.add('d-none');
return;
}
// 更新道德经分析显示
const formatContent = (content) => {
if (typeof content === 'string') {
return content.replace(/\n/g, '<br>');
} else if (content && typeof content === 'object') {
return JSON.stringify(content, null, 2).replace(/\n/g, '<br>');
}
return String(content || '-');
};
document.getElementById('taoPhilosophy').innerHTML = formatContent(data.tao_philosophy);
document.getElementById('businessEthics').innerHTML = formatContent(data.business_ethics);
document.getElementById('taoAdvice').innerHTML = formatContent(data.investment_advice);
document.getElementById('taoAnalysisLoading').classList.add('d-none');
document.getElementById('taoAnalysisContent').classList.remove('d-none');
} catch (error) {
console.error('获取道德经分析失败:', error);
document.getElementById('taoAnalysisError').textContent = error.message || '获取道德经分析失败,请稍后重试';
document.getElementById('taoAnalysisError').classList.remove('d-none');
document.getElementById('taoAnalysisLoading').classList.add('d-none');
document.getElementById('taoAnalysisContent').classList.add('d-none');
}
}
// 显示价值投资大咖分析弹窗
async function showMasterAnalysis(stockCode) {
const modal = new bootstrap.Modal(document.getElementById('masterAnalysisModal'));
document.getElementById('masterAnalysisModal').setAttribute('data-stock-code', stockCode);
modal.show();
// 显示加载状态
document.getElementById('masterAnalysisError').classList.add('d-none');
document.getElementById('masterAnalysisLoading').classList.remove('d-none');
document.getElementById('masterAnalysisContent').classList.add('d-none');
try {
// 获取价值投资大咖分析数据
const response = await fetch(`/api/master_analysis/${stockCode}`);
const data = await response.json();
if (data.error) {
document.getElementById('masterAnalysisError').textContent = data.error;
document.getElementById('masterAnalysisError').classList.remove('d-none');
document.getElementById('masterAnalysisLoading').classList.add('d-none');
return;
}
// 更新各个大咖的分析显示
const formatContent = (content) => {
if (typeof content === 'string') {
return content.replace(/\n/g, '<br>');
} else if (content && typeof content === 'object') {
return JSON.stringify(content, null, 2).replace(/\n/g, '<br>');
}
return String(content || '-');
};
document.getElementById('buffettAnalysis').innerHTML = formatContent(data.buffett_analysis);
document.getElementById('grahamAnalysis').innerHTML = formatContent(data.graham_analysis);
document.getElementById('linYuanAnalysis').innerHTML = formatContent(data.lin_yuan_analysis);
document.getElementById('liDaxiaoAnalysis').innerHTML = formatContent(data.li_daxiao_analysis);
document.getElementById('duanYongpingAnalysis').innerHTML = formatContent(data.duan_yongping_analysis);
document.getElementById('masterAnalysisLoading').classList.add('d-none');
document.getElementById('masterAnalysisContent').classList.remove('d-none');
} catch (error) {
console.error('获取价值投资大咖分析失败:', error);
document.getElementById('masterAnalysisError').textContent = error.message || '获取价值投资大咖分析失败,请稍后重试';
document.getElementById('masterAnalysisError').classList.remove('d-none');
document.getElementById('masterAnalysisLoading').classList.add('d-none');
document.getElementById('masterAnalysisContent').classList.add('d-none');
}
}
async function refreshTaoAnalysis() {
const stockCode = document.querySelector('#taoAnalysisModal').getAttribute('data-stock-code');
if (!stockCode) return;
// 显示加载状态
document.querySelector('#taoAnalysisLoading').classList.remove('d-none');
document.querySelector('#taoAnalysisContent').classList.add('d-none');
document.querySelector('#taoAnalysisError').classList.add('d-none');
try {
const response = await fetch(`/api/tao_analysis/${stockCode}?force_refresh=true`);
const data = await response.json();
if (data.error) {
throw new Error(data.error);
}
// 更新内容
document.querySelector('#taoPhilosophy').innerHTML = formatContent(data.tao_philosophy);
document.querySelector('#businessEthics').innerHTML = formatContent(data.business_ethics);
document.querySelector('#investmentAdvice').innerHTML = formatContent(data.investment_advice);
// 显示内容
document.querySelector('#taoAnalysisContent').classList.remove('d-none');
} catch (error) {
document.querySelector('#taoAnalysisError').textContent = `分析失败: ${error.message}`;
document.querySelector('#taoAnalysisError').classList.remove('d-none');
} finally {
document.querySelector('#taoAnalysisLoading').classList.add('d-none');
}
}
async function refreshMasterAnalysis() {
const stockCode = document.querySelector('#masterAnalysisModal').getAttribute('data-stock-code');
if (!stockCode) return;
// 显示加载状态
document.querySelector('#masterAnalysisLoading').classList.remove('d-none');
document.querySelector('#masterAnalysisContent').classList.add('d-none');
document.querySelector('#masterAnalysisError').classList.add('d-none');
try {
const response = await fetch(`/api/master_analysis/${stockCode}?force_refresh=true`);
const data = await response.json();
if (data.error) {
throw new Error(data.error);
}
// 更新内容
document.querySelector('#buffettAnalysis').innerHTML = formatContent(data.buffett_analysis);
document.querySelector('#grahamAnalysis').innerHTML = formatContent(data.graham_analysis);
document.querySelector('#linYuanAnalysis').innerHTML = formatContent(data.lin_yuan_analysis);
document.querySelector('#liDaxiaoAnalysis').innerHTML = formatContent(data.li_daxiao_analysis);
document.querySelector('#duanYongpingAnalysis').innerHTML = formatContent(data.duan_yongping_analysis);
// 显示内容
document.querySelector('#masterAnalysisContent').classList.remove('d-none');
} catch (error) {
document.querySelector('#masterAnalysisError').textContent = `分析失败: ${error.message}`;
document.querySelector('#masterAnalysisError').classList.remove('d-none');
} finally {
document.querySelector('#masterAnalysisLoading').classList.add('d-none');
}
}
</script>
</body>
</html>

178
config.json Normal file
View File

@ -0,0 +1,178 @@
{
"watchlist": {
"300059": {
"target_market_value": {
"min": 2500.0,
"max": 2800.0
}
},
"601318": {
"target_market_value": {
"min": 8000.0,
"max": 9500.0
}
},
"000963": {
"target_market_value": {
"min": 500.0,
"max": 650.0
}
},
"002415": {
"target_market_value": {
"min": 2000.0,
"max": 2200.0
}
},
"000423": {
"target_market_value": {
"min": 270.0,
"max": 330.0
}
},
"000538": {
"target_market_value": {
"min": 807.0,
"max": 1210.0
}
},
"600085": {
"target_market_value": {
"min": 336.0,
"max": 429.0
}
},
"002714": {
"target_market_value": {
"min": 1650.0,
"max": 2200.0
}
},
"002007": {
"target_market_value": {
"min": 240.0,
"max": 288.0
}
},
"600132": {
"target_market_value": {
"min": 220.0,
"max": 290.0
}
},
"002049": {
"target_market_value": {
"min": 360.0,
"max": 480.0
}
},
"600436": {
"target_market_value": {
"min": 960.0,
"max": 1080.0
}
},
"002216": {
"target_market_value": {
"min": 72.0,
"max": 97.0
}
},
"601966": {
"target_market_value": {
"min": 220.0,
"max": 280.0
}
},
"603195": {
"target_market_value": {
"min": 730.0,
"max": 950.0
}
},
"000001": {
"target_market_value": {
"min": 1800.0,
"max": 2500.0
}
},
"600867": {
"target_market_value": {
"min": 120.0,
"max": 160.0
}
},
"603087": {
"target_market_value": {
"min": 170.0,
"max": 283.0
}
},
"603290": {
"target_market_value": {
"min": 150.0,
"max": 200.0
}
},
"600332": {
"target_market_value": {
"min": 380.0,
"max": 460.0
}
},
"300124": {
"target_market_value": {
"min": 1200.0,
"max": 1400.0
}
},
"300146": {
"target_market_value": {
"min": 150.0,
"max": 200.0
}
},
"000999": {
"target_market_value": {
"min": 450.0,
"max": 580.0
}
},
"002466": {
"target_market_value": {
"min": 330.0,
"max": 415.0
}
},
"300009": {
"target_market_value": {
"min": 120.0,
"max": 160.0
}
},
"300743": {
"target_market_value": {
"min": null,
"max": null
}
},
"603511": {
"target_market_value": {
"min": null,
"max": null
}
},
"688553": {
"target_market_value": {
"min": null,
"max": null
}
},
"600030": {
"target_market_value": {
"min": 3200.0,
"max": 3600.0
}
}
}
}

View File

@ -1,6 +0,0 @@
{
"watchlist": {},
"tushare_token": "your_tushare_token_here",
"ai_api_key": "your_ai_api_key_here",
"ai_model_id": "your_ai_model_id_here"
}

12
config.template.py Normal file
View File

@ -0,0 +1,12 @@
import os
# 基础配置
class Config:
# 项目根目录
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Tushare API配置
TUSHARE_TOKEN = 'your_tushare_token_here'
# 配置文件路径
CONFIG_FILE = os.path.join(BASE_DIR, "config.json")

BIN
docs/images/image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

BIN
docs/images/image2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

BIN
docs/images/main.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 501 KiB

BIN
docs/images/wechat.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

View File

@ -1,11 +1,51 @@
aiofiles==23.2.1
annotated-types==0.7.0
anyio==3.7.1
beautifulsoup4==4.12.3
bs4==0.0.2
certifi==2024.12.14
charset-normalizer==3.4.1
click==8.1.8
decorator==5.1.1
et_xmlfile==1.0.0
fastapi==0.104.1
uvicorn==0.24.0
python-multipart==0.0.6
pydantic==2.10.4
requests==2.32.3
pandas==2.2.3
numpy==2.2.1
tushare==1.4.16
h11==0.14.0
html5lib==1.1
idna==3.10
Jinja2==3.1.2
jsonpath==0.82.2
lxml==5.3.0
markdown-it-py==3.0.0
MarkupSafe==3.0.2
mdurl==0.1.2
multitasking==0.0.11
numpy==2.2.1
openpyxl==3.1.5
pandas==2.2.3
py==1.11.0
py_mini_racer==0.6.0
pydantic==2.10.4
pydantic_core==2.27.2
Pygments==2.19.1
pypinyin==0.53.0
python-dateutil==2.9.0.post0
python-multipart==0.0.6
pytz==2024.2
requests==2.32.3
retry==0.9.2
rich==13.9.4
simplejson==3.19.3
six==1.17.0
sniffio==1.3.1
soupsieve==2.6
starlette==0.27.0
tabulate==0.9.0
tqdm==4.67.1
tushare==1.4.16
typing_extensions==4.12.2
tzdata==2024.2
urllib3==2.3.0
uvicorn==0.24.0
webencodings==0.5.1
websocket-client==1.8.0
xlrd==2.0.1

View File

@ -4,13 +4,13 @@
"stock_info": {
"code": "300059",
"name": "东方财富",
"market_value": 3491.76,
"pe_ratio": 42.62,
"pb_ratio": 4.54,
"ps_ratio": 89.81,
"dividend_yield": 0.0018,
"price": 22.12,
"change_percent": 0.011,
"market_value": 3766.43,
"pe_ratio": 45.97,
"pb_ratio": 4.9,
"ps_ratio": 96.88,
"dividend_yield": 0.0017,
"price": 23.86,
"change_percent": 0.0787,
"roe": 0.0811,
"gross_profit_margin": 0.8372,
"net_profit_margin": 2.694,
@ -28,20 +28,20 @@
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"601318": {
"data": {
"stock_info": {
"code": "601318",
"name": "中国平安",
"market_value": 8848.35,
"pe_ratio": 10.33,
"pb_ratio": 0.99,
"ps_ratio": 0.97,
"dividend_yield": 0.0498,
"price": 48.59,
"change_percent": -0.0074,
"market_value": 8988.57,
"pe_ratio": 10.49,
"pb_ratio": 1.01,
"ps_ratio": 0.98,
"dividend_yield": 0.0491,
"price": 49.36,
"change_percent": 0.0158,
"roe": 0.1319,
"gross_profit_margin": 0,
"net_profit_margin": 0.1806,
@ -59,20 +59,20 @@
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"600085": {
"data": {
"stock_info": {
"code": "600085",
"name": "同仁堂",
"market_value": 507.86,
"pe_ratio": 30.43,
"pb_ratio": 4.13,
"ps_ratio": 2.84,
"dividend_yield": 0.027,
"price": 37.03,
"change_percent": 0.0082,
"market_value": 519.24,
"pe_ratio": 31.11,
"pb_ratio": 4.22,
"ps_ratio": 2.91,
"dividend_yield": 0.0264,
"price": 37.86,
"change_percent": 0.0224,
"roe": 0.1037,
"gross_profit_margin": 0.437,
"net_profit_margin": 0.1435,
@ -90,20 +90,20 @@
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"002714": {
"data": {
"stock_info": {
"code": "002714",
"name": "牧原股份",
"market_value": 1980.25,
"market_value": 2023.41,
"pe_ratio": 0,
"pb_ratio": 2.97,
"ps_ratio": 1.79,
"dividend_yield": 0.0227,
"price": 36.25,
"change_percent": 0.0014,
"pb_ratio": 3.04,
"ps_ratio": 1.83,
"dividend_yield": 0.0223,
"price": 37.04,
"change_percent": 0.0218,
"roe": 0.1552,
"gross_profit_margin": 0.1727,
"net_profit_margin": 0.1162,
@ -121,20 +121,20 @@
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"000538": {
"data": {
"stock_info": {
"code": "000538",
"name": "云南白药",
"market_value": 1001.86,
"pe_ratio": 24.47,
"pb_ratio": 2.61,
"ps_ratio": 2.56,
"dividend_yield": 0.0586,
"price": 56.15,
"change_percent": -0.0083,
"market_value": 1024.17,
"pe_ratio": 25.02,
"pb_ratio": 2.67,
"ps_ratio": 2.62,
"dividend_yield": 0.0573,
"price": 57.4,
"change_percent": 0.0223,
"roe": 0.1076,
"gross_profit_margin": 0.284,
"net_profit_margin": 0.1447,
@ -152,20 +152,20 @@
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"000423": {
"data": {
"stock_info": {
"code": "000423",
"name": "东阿阿胶",
"market_value": 391.86,
"pe_ratio": 34.05,
"pb_ratio": 3.95,
"ps_ratio": 8.31,
"dividend_yield": 0.0481,
"price": 60.85,
"change_percent": -0.0178,
"market_value": 398.75,
"pe_ratio": 34.65,
"pb_ratio": 4.02,
"ps_ratio": 8.46,
"dividend_yield": 0.0472,
"price": 61.92,
"change_percent": 0.0176,
"roe": 0.1117,
"gross_profit_margin": 0.7413,
"net_profit_margin": 0.2661,
@ -183,20 +183,20 @@
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"000963": {
"data": {
"stock_info": {
"code": "000963",
"name": "华东医药",
"market_value": 567.33,
"pe_ratio": 19.98,
"pb_ratio": 2.57,
"ps_ratio": 1.4,
"dividend_yield": 0.0288,
"price": 32.34,
"change_percent": -0.0089,
"market_value": 582.24,
"pe_ratio": 20.51,
"pb_ratio": 2.64,
"ps_ratio": 1.43,
"dividend_yield": 0.028,
"price": 33.19,
"change_percent": 0.0263,
"roe": 0.1189,
"gross_profit_margin": 0.3255,
"net_profit_margin": 0.0814,
@ -214,20 +214,20 @@
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"002415": {
"data": {
"stock_info": {
"code": "002415",
"name": "海康威视",
"market_value": 2554.83,
"pe_ratio": 18.11,
"pb_ratio": 3.33,
"ps_ratio": 2.86,
"dividend_yield": 0.0329,
"price": 27.67,
"change_percent": -0.0047,
"market_value": 2618.54,
"pe_ratio": 18.56,
"pb_ratio": 3.41,
"ps_ratio": 2.93,
"dividend_yield": 0.0321,
"price": 28.36,
"change_percent": 0.0249,
"roe": 0.1059,
"gross_profit_margin": 0.4476,
"net_profit_margin": 0.1371,
@ -245,20 +245,20 @@
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"002007": {
"data": {
"stock_info": {
"code": "002007",
"name": "华兰生物",
"market_value": 284.92,
"pe_ratio": 19.23,
"pb_ratio": 2.44,
"ps_ratio": 5.33,
"dividend_yield": 0.0193,
"price": 15.58,
"change_percent": -0.0133,
"market_value": 291.32,
"pe_ratio": 19.66,
"pb_ratio": 2.49,
"ps_ratio": 5.45,
"dividend_yield": 0.0188,
"price": 15.93,
"change_percent": 0.0225,
"roe": 0.0801,
"gross_profit_margin": 0.6177,
"net_profit_margin": 0.2897,
@ -276,20 +276,20 @@
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"600132": {
"data": {
"stock_info": {
"code": "600132",
"name": "重庆啤酒",
"market_value": 277.32,
"pe_ratio": 20.75,
"pb_ratio": 19.67,
"ps_ratio": 1.87,
"dividend_yield": 0.075,
"price": 57.3,
"change_percent": 0.0145,
"market_value": 281.28,
"pe_ratio": 21.04,
"pb_ratio": 19.95,
"ps_ratio": 1.9,
"dividend_yield": 0.074,
"price": 58.12,
"change_percent": 0.0143,
"roe": 0.623,
"gross_profit_margin": 0.492,
"net_profit_margin": 0.2041,
@ -302,25 +302,25 @@
},
"targets": {
"target_market_value": {
"min": 225.0,
"max": 260.0
"min": 220.0,
"max": 290.0
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"002049": {
"data": {
"stock_info": {
"code": "002049",
"name": "紫光国微",
"market_value": 492.36,
"pe_ratio": 19.46,
"pb_ratio": 4.1,
"ps_ratio": 6.51,
"dividend_yield": 0.0116,
"price": 57.95,
"change_percent": -0.0113,
"market_value": 508.67,
"pe_ratio": 20.1,
"pb_ratio": 4.24,
"ps_ratio": 6.72,
"dividend_yield": 0.0113,
"price": 59.87,
"change_percent": 0.0331,
"roe": 0.0847,
"gross_profit_margin": 0.5681,
"net_profit_margin": 0.2383,
@ -338,20 +338,20 @@
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"600436": {
"data": {
"stock_info": {
"code": "600436",
"name": "片仔癀",
"market_value": 1236.8,
"pe_ratio": 44.21,
"pb_ratio": 9.28,
"ps_ratio": 12.3,
"dividend_yield": 0.0169,
"price": 205.0,
"change_percent": 0.0029,
"market_value": 1261.9,
"pe_ratio": 45.11,
"pb_ratio": 9.47,
"ps_ratio": 12.55,
"dividend_yield": 0.0166,
"price": 209.16,
"change_percent": 0.0203,
"roe": 0.1961,
"gross_profit_margin": 0.4544,
"net_profit_margin": 0.3216,
@ -369,20 +369,20 @@
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"002216": {
"data": {
"stock_info": {
"code": "002216",
"name": "三全食品",
"market_value": 97.77,
"pe_ratio": 13.05,
"pb_ratio": 2.28,
"ps_ratio": 1.39,
"dividend_yield": 0.045,
"price": 11.12,
"change_percent": 0.0091,
"market_value": 100.14,
"pe_ratio": 13.36,
"pb_ratio": 2.34,
"ps_ratio": 1.42,
"dividend_yield": 0.0439,
"price": 11.39,
"change_percent": 0.0243,
"roe": 0.0914,
"gross_profit_margin": 0.2503,
"net_profit_margin": 0.0769,
@ -396,24 +396,24 @@
"targets": {
"target_market_value": {
"min": 72.0,
"max": 96.0
"max": 97.0
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"601966": {
"data": {
"stock_info": {
"code": "601966",
"name": "玲珑轮胎",
"market_value": 251.87,
"pe_ratio": 18.11,
"pb_ratio": 1.18,
"ps_ratio": 1.25,
"dividend_yield": 0.0371,
"price": 17.21,
"change_percent": -0.0023,
"market_value": 257.87,
"pe_ratio": 18.54,
"pb_ratio": 1.2,
"ps_ratio": 1.28,
"dividend_yield": 0.0363,
"price": 17.62,
"change_percent": 0.0238,
"roe": 0.0801,
"gross_profit_margin": 0.2435,
"net_profit_margin": 0.1073,
@ -431,20 +431,20 @@
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"603195": {
"data": {
"stock_info": {
"code": "603195",
"name": "公牛集团",
"market_value": 861.35,
"pe_ratio": 22.26,
"pb_ratio": 5.8,
"ps_ratio": 5.49,
"dividend_yield": 0.0321,
"price": 66.66,
"change_percent": -0.0141,
"market_value": 875.57,
"pe_ratio": 22.62,
"pb_ratio": 5.9,
"ps_ratio": 5.58,
"dividend_yield": 0.0316,
"price": 67.76,
"change_percent": 0.0165,
"roe": 0.2228,
"gross_profit_margin": 0.4312,
"net_profit_margin": 0.2589,
@ -462,20 +462,20 @@
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"000001": {
"data": {
"stock_info": {
"code": "000001",
"name": "平安银行",
"market_value": 2173.46,
"pe_ratio": 4.68,
"pb_ratio": 0.52,
"ps_ratio": 1.32,
"dividend_yield": 0.0862,
"price": 11.2,
"change_percent": -0.0089,
"market_value": 2208.39,
"pe_ratio": 4.75,
"pb_ratio": 0.53,
"ps_ratio": 1.34,
"dividend_yield": 0.0848,
"price": 11.38,
"change_percent": 0.0161,
"roe": 0.0825,
"gross_profit_margin": 0,
"net_profit_margin": 0.3561,
@ -488,25 +488,25 @@
},
"targets": {
"target_market_value": {
"min": 2300.0,
"max": 2800.0
"min": 1800.0,
"max": 2500.0
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"600867": {
"data": {
"stock_info": {
"code": "600867",
"name": "通化东宝",
"market_value": 145.52,
"pe_ratio": 12.46,
"pb_ratio": 2.33,
"ps_ratio": 4.73,
"dividend_yield": 0.034,
"price": 7.43,
"change_percent": 0.0095,
"market_value": 150.22,
"pe_ratio": 12.86,
"pb_ratio": 2.41,
"ps_ratio": 4.88,
"dividend_yield": 0.033,
"price": 7.67,
"change_percent": 0.0323,
"roe": -0.0097,
"gross_profit_margin": 0.7447,
"net_profit_margin": -0.0459,
@ -524,20 +524,20 @@
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"603087": {
"data": {
"stock_info": {
"code": "603087",
"name": "甘李药业",
"market_value": 250.34,
"pe_ratio": 73.62,
"pb_ratio": 2.3,
"ps_ratio": 9.6,
"dividend_yield": 0.0168,
"price": 41.65,
"change_percent": 0.0161,
"market_value": 258.16,
"pe_ratio": 75.91,
"pb_ratio": 2.37,
"ps_ratio": 9.9,
"dividend_yield": 0.0163,
"price": 42.95,
"change_percent": 0.0312,
"roe": 0.0462,
"gross_profit_margin": 0.7536,
"net_profit_margin": 0.226,
@ -555,20 +555,20 @@
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"603290": {
"data": {
"stock_info": {
"code": "603290",
"name": "斯达半导",
"market_value": 193.85,
"pe_ratio": 21.29,
"pb_ratio": 2.94,
"ps_ratio": 5.29,
"dividend_yield": 0.0141,
"price": 80.95,
"change_percent": 0.0021,
"market_value": 202.52,
"pe_ratio": 22.24,
"pb_ratio": 3.07,
"ps_ratio": 5.53,
"dividend_yield": 0.0135,
"price": 84.57,
"change_percent": 0.0447,
"roe": 0.065,
"gross_profit_margin": 0.3169,
"net_profit_margin": 0.1773,
@ -586,20 +586,20 @@
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"600332": {
"data": {
"stock_info": {
"code": "600332",
"name": "白云山",
"market_value": 433.11,
"pe_ratio": 10.68,
"pb_ratio": 1.22,
"ps_ratio": 0.57,
"dividend_yield": 0.0431,
"price": 26.64,
"change_percent": 0.0019,
"market_value": 442.54,
"pe_ratio": 10.91,
"pb_ratio": 1.24,
"ps_ratio": 0.59,
"dividend_yield": 0.0422,
"price": 27.22,
"change_percent": 0.0218,
"roe": 0.0888,
"gross_profit_margin": 0.177,
"net_profit_margin": 0.0557,
@ -617,20 +617,20 @@
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"300124": {
"data": {
"stock_info": {
"code": "300124",
"name": "汇川技术",
"market_value": 1570.93,
"pe_ratio": 33.13,
"pb_ratio": 5.86,
"ps_ratio": 5.16,
"dividend_yield": 0.0077,
"price": 58.35,
"change_percent": -0.0273,
"market_value": 1663.81,
"pe_ratio": 35.09,
"pb_ratio": 6.21,
"ps_ratio": 5.47,
"dividend_yield": 0.0072,
"price": 61.8,
"change_percent": 0.0591,
"roe": 0.1316,
"gross_profit_margin": 0.3102,
"net_profit_margin": 0.1345,
@ -648,20 +648,20 @@
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"300146": {
"data": {
"stock_info": {
"code": "300146",
"name": "汤臣倍健",
"market_value": 192.2,
"pe_ratio": 11.01,
"pb_ratio": 1.7,
"ps_ratio": 2.04,
"dividend_yield": 0.0789,
"price": 11.3,
"change_percent": 0.0116,
"market_value": 198.49,
"pe_ratio": 11.37,
"pb_ratio": 1.75,
"ps_ratio": 2.11,
"dividend_yield": 0.0764,
"price": 11.67,
"change_percent": 0.0327,
"roe": 0.074,
"gross_profit_margin": 0.6793,
"net_profit_margin": 0.1504,
@ -679,20 +679,20 @@
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"000999": {
"data": {
"stock_info": {
"code": "000999",
"name": "华润三九",
"market_value": 546.6,
"pe_ratio": 19.16,
"pb_ratio": 2.84,
"ps_ratio": 2.21,
"dividend_yield": 0.0506,
"price": 42.56,
"change_percent": -0.0014,
"market_value": 557.39,
"pe_ratio": 19.54,
"pb_ratio": 2.9,
"ps_ratio": 2.25,
"dividend_yield": 0.0496,
"price": 43.4,
"change_percent": 0.0197,
"roe": 0.1499,
"gross_profit_margin": 0.5268,
"net_profit_margin": 0.1644,
@ -710,7 +710,7 @@
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"000516": {
"data": {
@ -748,13 +748,13 @@
"stock_info": {
"code": "002466",
"name": "天齐锂业",
"market_value": 529.95,
"pe_ratio": 7.26,
"pb_ratio": 1.22,
"ps_ratio": 1.31,
"dividend_yield": 0.0418,
"price": 32.29,
"change_percent": 0.0416,
"market_value": 541.44,
"pe_ratio": 7.42,
"pb_ratio": 1.24,
"ps_ratio": 1.34,
"dividend_yield": 0.0409,
"price": 32.99,
"change_percent": 0.0217,
"roe": -0.12,
"gross_profit_margin": 0.4903,
"net_profit_margin": 0.1723,
@ -772,7 +772,7 @@
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"index_data": {
"data": {
@ -2130,13 +2130,13 @@
"stock_info": {
"code": "300009",
"name": "安科生物",
"market_value": 135.81,
"pe_ratio": 16.03,
"pb_ratio": 3.47,
"ps_ratio": 4.74,
"dividend_yield": 0.0308,
"price": 8.12,
"change_percent": 0.01,
"market_value": 139.66,
"pe_ratio": 16.48,
"pb_ratio": 3.56,
"ps_ratio": 4.87,
"dividend_yield": 0.0299,
"price": 8.35,
"change_percent": 0.0283,
"roe": 0.1537,
"gross_profit_margin": 0.7775,
"net_profit_margin": 0.3122,
@ -2149,25 +2149,25 @@
},
"targets": {
"target_market_value": {
"min": null,
"max": null
"min": 120.0,
"max": 160.0
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"300743": {
"data": {
"stock_info": {
"code": "300743",
"name": "天地数码",
"market_value": 21.74,
"pe_ratio": 39.08,
"pb_ratio": 3.57,
"ps_ratio": 3.38,
"dividend_yield": 0.0241,
"price": 14.17,
"change_percent": 0.0093,
"market_value": 22.94,
"pe_ratio": 41.23,
"pb_ratio": 3.76,
"ps_ratio": 3.56,
"dividend_yield": 0.0229,
"price": 14.95,
"change_percent": 0.055,
"roe": 0.1209,
"gross_profit_margin": 0.3493,
"net_profit_margin": 0.1335,
@ -2185,20 +2185,20 @@
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"603511": {
"data": {
"stock_info": {
"code": "603511",
"name": "爱慕股份",
"market_value": 46.23,
"pe_ratio": 15.12,
"pb_ratio": 1.05,
"ps_ratio": 1.35,
"dividend_yield": 0.0662,
"price": 11.37,
"change_percent": -0.0026,
"market_value": 50.86,
"pe_ratio": 16.64,
"pb_ratio": 1.16,
"ps_ratio": 1.48,
"dividend_yield": 0.0602,
"price": 12.51,
"change_percent": 0.1003,
"roe": 0.0317,
"gross_profit_margin": 0.6597,
"net_profit_margin": 0.0615,
@ -2216,20 +2216,20 @@
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"688553": {
"data": {
"stock_info": {
"code": "688553",
"name": "汇宇制药-W",
"market_value": 58.37,
"pe_ratio": 41.76,
"pb_ratio": 1.5,
"ps_ratio": 6.3,
"market_value": 60.79,
"pe_ratio": 43.49,
"pb_ratio": 1.57,
"ps_ratio": 6.56,
"dividend_yield": 0.0,
"price": 13.78,
"change_percent": 0.0117,
"price": 14.35,
"change_percent": 0.0414,
"roe": 0.0594,
"gross_profit_margin": 0.8315,
"net_profit_margin": 0.2592,
@ -2247,20 +2247,20 @@
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
},
"600030": {
"data": {
"stock_info": {
"code": "600030",
"name": "中信证券",
"market_value": 3928.93,
"pe_ratio": 19.92,
"pb_ratio": 1.53,
"ps_ratio": 6.54,
"dividend_yield": 0.027,
"price": 26.51,
"change_percent": 0.0019,
"market_value": 4105.29,
"pe_ratio": 20.82,
"pb_ratio": 1.6,
"ps_ratio": 6.83,
"dividend_yield": 0.0258,
"price": 27.7,
"change_percent": 0.0449,
"roe": 0.0605,
"gross_profit_margin": 0,
"net_profit_margin": 0.3782,
@ -2273,11 +2273,11 @@
},
"targets": {
"target_market_value": {
"min": null,
"max": null
"min": 3200.0,
"max": 3600.0
}
}
},
"timestamp": "2025-01-13"
"timestamp": "2025-01-15"
}
}

193
项目文档.txt Normal file
View File

@ -0,0 +1,193 @@
# 价值投资盯盘系统项目文档
## 项目概述
**项目名称**:价值投资盯盘系统
**开发者**:张艺杰
**项目类型**A股智能股票分析与监控平台
**技术栈**Python + FastAPI + Bootstrap + ECharts
## 系统功能
### 1. 核心功能
1. **股票监控**
- 实时股票行情监控
- 自定义市值目标区间
- 多维度指标展示
- 涨跌幅实时更新
2. **指数行情**
- 主要指数实时展示
- K线图可视化
- 涨跌幅实时更新
3. **公司详情分析**
- 公司基本信息
- 财务指标分析
- 股东结构分析
- AI智能分析
### 2. 具体指标监控
#### 2.1 基础指标
- 股票代码和名称
- 现价和涨跌幅
- 市值监控
- 目标区间对比
#### 2.2 估值指标
- 市盈率(PE)
- 市净率(PB)
- 市销率(PS)
- 股息率
#### 2.3 财务指标
- ROE净资产收益率
- 毛利率
- 净利率
- 资产负债率
- 净利润增长率
- 每股净资产
- 每股经营现金流
### 3. AI分析功能
1. **投资建议**
- 总体建议
- 建议操作
- 关注重点
2. **价格分析**
- 合理价格区间
- 目标市值区间
3. **多维度分析**
- 估值分析
- 财务健康状况
- 成长潜力
- 风险评估
## 技术实现
### 1. 后端架构
1. **Web框架**
- FastAPI作为主要Web框架
- Uvicorn作为ASGI服务器
2. **数据源集成**
- Tushare API接口
3. **数据处理**
- Pandas进行数据分析
- NumPy进行数值计算
### 2. 前端实现
1. **UI框架**
- Bootstrap 5.1.3
- 响应式设计
2. **数据可视化**
- ECharts 5.4.3
- 动态K线图表
3. **交互设计**
- AJAX异步数据更新
- 实时数据刷新
- 模态框展示详情
### 3. 数据存储
1. **配置存储**
- JSON文件存储监控列表
- 配置文件自动管理
2. **缓存机制**
- 行情数据缓存
- 智能更新策略
## 部署要求
### 1. 系统要求
- Python 3.8+
- 8GB+ RAM
- 现代浏览器支持
### 2. 依赖安装
```bash
pip install -r requirements.txt
```
### 3. 配置说明
- 需配置Tushare API Token
- 配置端口默认为8000
- 支持热重载
## 使用说明
### 1. 启动系统
```bash
python run.py
```
### 2. 访问系统
- 浏览器访问:`http://localhost:8000`
### 3. 基本操作
1. 添加监控股票
- 输入6位股票代码
- 设置目标市值区间
2. 查看股票详情
- 点击股票名称查看详细信息
- 查看AI分析报告
3. 管理监控列表
- 删除不需要的股票
- 强制刷新数据
## 安全性考虑
1. **数据安全**
- API Token安全存储
- 敏感信息加密
2. **访问控制**
- 请求频率限制
- 错误处理机制
## 后续优化方向
1. **功能扩展**
- 增加更多技术指标
- 添加自定义告警功能
- 支持多维度筛选
2. **性能优化**
- 优化数据缓存机制
- 提升响应速度
- 减少资源占用
3. **用户体验**
- 增加自定义主题
- 优化移动端显示
- 添加更多图表类型
## 维护说明
1. **日常维护**
- 定期更新依赖
- 检查API可用性
- 优化数据缓存
2. **问题处理**
- 日志监控
- 异常处理
- 性能监控
## 版权信息
版权所有 © 2024 张艺杰
保留所有权利