增加港股支持

This commit is contained in:
oficcejo
2025-10-10 17:07:21 +08:00
parent 88c7db1ab9
commit 80bead4f2f
8 changed files with 1015 additions and 30 deletions
+6 -1
View File
@@ -4,12 +4,17 @@ FROM python:3.12-slim
# 设置工作目录
WORKDIR /app
# 安装Node.js (pywencai需要)
# 安装Node.js (pywencai需要) 和中文字体 (PDF生成需要)
RUN apt-get update && apt-get install -y \
curl \
gnupg \
fonts-noto-cjk \
fonts-wqy-zenhei \
fonts-wqy-microhei \
fontconfig \
&& curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
&& apt-get install -y nodejs \
&& fc-cache -fv \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
+207
View File
@@ -0,0 +1,207 @@
# PDF中文乱码修复说明
## 问题描述
在Docker环境中,PDF导出时中文显示为乱码或方框,但本地Windows环境正常。
## 原因分析
- Docker容器基于Linux系统,默认不包含中文字体
- PDF生成器(reportlab)需要中文字体才能正确渲染中文字符
- 原代码只配置了Windows系统的字体路径
## 修复方案
### 已修改的文件
#### 1. `Dockerfile`
添加了中文字体包安装:
```dockerfile
# 安装Node.js (pywencai需要) 和中文字体 (PDF生成需要)
RUN apt-get update && apt-get install -y \
curl \
gnupg \
fonts-noto-cjk \
fonts-wqy-zenhei \
fonts-wqy-microhei \
fontconfig \
&& curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
&& apt-get install -y nodejs \
&& fc-cache -fv \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
```
安装的字体包:
- **fonts-noto-cjk**: Google Noto CJK字体(支持中日韩文字)
- **fonts-wqy-zenhei**: 文泉驿正黑体
- **fonts-wqy-microhei**: 文泉驿微米黑体
- **fontconfig**: 字体配置工具
#### 2. `pdf_generator.py`
更新了字体注册函数,支持Linux系统:
```python
def register_chinese_fonts():
"""注册中文字体 - 支持Windows和Linux系统"""
# Windows系统字体路径
windows_font_paths = [...]
# Linux系统字体路径(Docker环境)
linux_font_paths = [
'/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc',
'/usr/share/fonts/truetype/wqy/wqy-microhei.ttc',
'/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc',
# ... 更多字体路径
]
```
## 重新部署步骤
### 方式一:Docker Compose(推荐)
```bash
# 1. 停止并删除现有容器
docker-compose down
# 2. 删除旧镜像(可选,但推荐)
docker rmi agentsstock1-app
# 3. 重新构建并启动
docker-compose up -d --build
# 4. 查看日志,确认字体加载成功
docker-compose logs -f
```
### 方式二:Docker命令
```bash
# 1. 停止并删除现有容器
docker stop agentsstock1
docker rm agentsstock1
# 2. 删除旧镜像
docker rmi agentsstock1
# 3. 重新构建镜像
docker build -t agentsstock1 .
# 4. 启动新容器
docker run -d -p 8503:8501 \
-v $(pwd)/.env:/app/.env \
--name agentsstock1 \
agentsstock1
# 5. 查看日志
docker logs -f agentsstock1
```
## 验证修复
### 1. 检查字体安装
进入容器检查字体:
```bash
docker exec -it agentsstock1 bash
fc-list :lang=zh # 列出所有中文字体
```
应该看到类似输出:
```
/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc: WenQuanYi Zen Hei:style=Regular
/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc: Noto Sans CJK SC:style=Regular
...
```
### 2. 查看应用日志
在生成PDF时,日志中应该显示:
```
✅ 成功注册中文字体: /usr/share/fonts/truetype/wqy/wqy-zenhei.ttc
```
### 3. 测试PDF导出
1. 在Web界面分析任意股票
2. 点击"生成并下载PDF报告"
3. 打开下载的PDF文件
4. 确认中文正常显示
## 故障排查
### 问题1:构建时字体安装失败
**现象**:构建过程中apt-get install失败
**解决方案**
```bash
# 清理Docker缓存后重试
docker system prune -a
docker-compose build --no-cache
```
### 问题2:字体未加载
**现象**:日志显示"未找到中文字体"
**检查步骤**
1. 确认Dockerfile中正确添加了字体包
2. 进入容器检查字体文件是否存在
3. 运行 `fc-cache -fv` 刷新字体缓存
### 问题3PDF仍然乱码
**现象**:字体已安装但PDF中文仍显示为方框
**可能原因**
1. 字体文件权限问题
2. reportlab缓存问题
3. 字体格式不兼容
**解决方案**
```bash
# 重新构建时清理所有缓存
docker-compose down -v
docker system prune -a
docker-compose up -d --build
```
## 技术说明
### 字体选择
我们安装了3种字体包:
1. **Noto Sans CJK**:Google开发,覆盖范围广,质量高
2. **文泉驿正黑**:开源中文字体,适合阅读
3. **文泉驿微米黑**:适合小字号显示
系统会按优先级自动选择第一个可用的字体。
### 字体文件格式
- **TTC**TrueType Collection(字体集合文件)
- **TTF**TrueType Font(单个字体文件)
reportlab的TTFont可以处理这两种格式。
### Docker镜像大小
添加中文字体后,镜像大小会增加约50-100MB:
- fonts-noto-cjk: ~70MB
- fonts-wqy-zenhei: ~10MB
- fonts-wqy-microhei: ~5MB
这是正常的,为了支持完整的中文显示必须付出的空间代价。
## 注意事项
1. **本地环境无影响**:修改后的代码在Windows本地环境仍然正常工作
2. **字体缓存**:首次启动时fontconfig会建立字体缓存,可能需要几秒钟
3. **镜像更新**:已部署的用户需要重新构建镜像才能应用修复
4. **备份数据**:重新部署前请备份数据库文件(.db文件)
## 相关资源
- [ReportLab中文支持文档](https://www.reportlab.com/docs/reportlab-userguide.pdf)
- [Noto字体项目](https://www.google.com/get/noto/)
- [文泉驿字体项目](http://wenq.org/)
- [Docker字体配置指南](https://docs.docker.com/config/)
## 更新日志
- **2025-10-10**: 初始版本,添加Docker中文字体支持
- **2025-10-10**: 更新pdf_generator.py,支持跨平台字体检测
---
如有问题,请联系:ws3101001@126.com
+132 -4
View File
@@ -9,6 +9,32 @@
<img width="1910" height="923" alt="01" src="https://github.com/user-attachments/assets/7dcd4b2c-8b4b-428b-8a17-4d843e98a626" />
<img width="1910" height="923" alt="02" src="https://github.com/user-attachments/assets/02018fff-4e6b-4354-b258-a5da25537c38" />
## ✨1010 更新说明(最新)
### 🇭🇰 新增港股分析支持 ⭐️
- **市场扩展**:现已支持A股、港股、美股三大市场
- **港股代码**:支持多种格式(700/00700/HK00700
- **技术分析**:完整支持K线、技术指标、趋势判断
- **财务分析**:支持21项财务指标(ROE、市盈率、净利润等)
- **智能分析**:技术分析师、基本面分析师、风险管理师全面支持
- **使用简单**:直接输入港股代码即可分析(如:00700 腾讯控股)
## ✨1010 更新说明
### 最新更新:主力选股功能上线 ⭐️
- **智能选股**:基于主力资金流向,AI团队精选优质标的
- **数据获取**:使用问财获取前100名主力资金净流入股票
- **多维筛选**:市值范围、区间涨跌幅、财务指标等多维度筛选
- **AI分析团队**
- 💰 资金流向分析师:分析主力资金流向趋势和热点板块
- 📊 行业板块分析师:解读行业轮动和市场热点
- 📈 财务基本面分析师:评估公司财务健康度和成长性
- 👔 资深研究员:综合决策,精选3-5只优质标的
- **完整报告**:支持Markdown、HTML、CSV多格式导出
- **候选列表**:前100名主力资金股票完整列表(按资金流向排序)
- **智能匹配**:自动识别"区间主力资金流向"、"区间涨跌幅"等字段
- **季报数据**:优化季报获取,改用问财接口,数据更准确
<img width="1910" height="923" alt="主力选股功能" src="https://github.com/user-attachments/assets/main_force_selector.png" />
## ✨1009 更新说明
### 最新更新:增加支持docker部署 ⭐️
## ✨1008 更新说明
@@ -41,7 +67,7 @@
- **市场情绪分析师**:专注市场心理和情绪分析
- **新闻公告分析师**:专注热点新闻及公告影响分析
### 📊 完整分析流程
1. 📈 获取股票数据(支持A股和美股)
1. 📈 获取股票数据(支持A股、港股和美股)
2. 📊 获取详细数据(三大报表+财务指标+20日资金数据+新闻+公告)
3. 🔍 多智能体并行分析
4. 🤝 团队综合讨论
@@ -68,6 +94,28 @@
<img width="1910" height="923" alt="image" src="https://github.com/user-attachments/assets/242ee212-ba6c-4e0a-ae16-47aff3f356e6" />
### 🎯 主力选股功能(新增)⭐️
- **智能选股**:基于主力资金流向,筛选优质投资标的
- **数据来源**:问财数据,获取区间主力资金净流入前100名股票
- **多维筛选**
- 起始日期:自定义区间开始日期
- 市值范围:50亿-5000亿灵活设置
- 涨跌幅限制:过滤涨幅过高的股票,避免追高
- **AI分析团队**
- 💰 **资金流向分析师**:分析主力资金动向、热点板块、资金持续性
- 📊 **行业板块分析师**:解读行业轮动、板块联动、市场情绪
- 📈 **财务基本面分析师**:评估公司盈利能力、成长性、财务健康度
- 👔 **资深研究员**:综合三大分析师意见,精选3-5只优质标的
- **批量分析**:一次性分析100只股票,效率高
- **完整报告**
- 📄 Markdown格式:便于编辑和二次处理
- 🌐 HTML格式:美观易读,支持浏览器打开
- 📊 CSV格式:候选股票完整数据导出
- **候选列表**:前100名股票按主力资金流向排序展示
- **关键指标**:区间主力资金流向、区间涨跌幅、市值、市盈率、市净率等
<img width="1910" height="923" alt="主力选股界面" src="https://github.com/user-attachments/assets/main_force_ui.png" />
<img width="1910" height="923" alt="AI分析报告" src="https://github.com/user-attachments/assets/main_force_report.png" />
### 🔍 实时监测功能
- **智能监测**:自动监控股票价格变动
- **关键位置提醒**:进场区间、止盈位、止损位触发通知
@@ -259,9 +307,10 @@ streamlit run app.py
## 📊 使用指南
### 股票代码格式(美股暂不支持)
- **股**AAPL, MSFT, GOOGL, TSLA, NVDA
- **A股**000001, 600036, 000002, 600519
### 股票代码格式
- **A股**6位数字代码(如 000001, 600036, 600519, 000858
- **股**1-5位数字代码(如 700, 00700, 9988, 01810)或带HK前缀(如 HK00700
- **美股**:字母代码(如 AAPL, MSFT, GOOGL, TSLA, NVDA
### 单个股票分析流程
1. 选择"单个分析"模式
@@ -329,6 +378,56 @@ streamlit run app.py
- 批量分析时间较长,请耐心等待
- 可在历史记录中查看所有分析结果
### 主力选股功能使用流程 ⭐️ 新增
1. **进入主力选股**
- 点击侧边栏"🎯 主力选股"按钮
2. **设置筛选参数**
- **起始日期**:选择区间开始日期(如"2025年7月23日"
- **市值范围**
- 最小市值:默认50亿(可调整)
- 最大市值:默认5000亿(可调整)
- **最大涨跌幅**:默认50%(过滤涨幅过高的股票)
3. **开始分析**
- 点击"🚀 开始主力选股分析"按钮
- 系统会自动:
- 从问财获取前100名主力资金净流入股票
- 按条件筛选(市值、涨跌幅)
- AI分析师团队进行整体分析
- 资深研究员精选3-5只优质标的
4. **查看分析结果**
- **统计信息**
- 获取股票数:原始数据量
- 筛选后:符合条件的股票数
- 最终推荐:精选的优质标的数量
- **AI分析师报告**(三个标签页):
- 💰 资金流向分析:主力资金动向、热点板块
- 📊 行业板块分析:行业轮动、板块联动
- 📈 财务基本面分析:盈利能力、成长性评估
- **精选推荐**
- 展开查看每只推荐股票的详细信息
- 推荐理由、关键指标、能力评分
- **候选股票列表**
- 前100名股票完整列表
- 按主力资金流向排序
- 包含行业、资金流向、涨跌幅、市值、市盈率等
5. **导出报告**
- 📄 **下载Markdown报告**:便于编辑和二次处理
- 🌐 **下载HTML报告**:美观易读,可打印
- 📊 **下载候选列表CSV**:Excel打开,便于筛选排序
6. **使用技巧**
- **起始日期**:建议选择近3-6个月的日期
- **市值范围**:中小盘(50-300亿)波动较大,大盘(300-5000亿)相对稳定
- **涨跌幅限制**:建议30%-50%,避免追高
- **查看调试信息**:展开"🔍 调试信息"查看实际获取的列名
### 结果解读
- **投资评级**:买入/持有/卖出
- **目标价位**:预期价格目标
@@ -514,6 +613,33 @@ AI股票分析系统
- 通知历史管理
- 配置测试功能
#### 🎯 主力选股模块 ⭐️ 新增
**main_force_selector.py**
- 问财数据获取(主力资金净流入)
- 多维度筛选(市值、涨跌幅)
- 智能列名匹配
- 数据格式化和清洗
**main_force_analysis.py**
- AI分析师团队协作
- 整体数据分析(100只股票)
- 资金流向分析
- 行业板块分析
- 财务基本面分析
- 资深研究员决策
**main_force_ui.py**
- 参数配置界面
- 分析进度显示
- 结果可视化展示
- 报告导出功能
**main_force_pdf_generator.py**
- Markdown报告生成
- HTML报告生成
- CSV数据导出
- 美观格式化输出
#### 🤖 量化交易模块 (miniqmt_interface.py) ⭐️ 新增
- MiniQMT接口对接
- 自动交易执行
@@ -542,6 +668,8 @@ AI股票分析系统
### 数据源
- **美股数据**Yahoo Finance (yfinance)
- **A股数据**AKShare免费接口
- **主力资金数据**:问财(pywencai)- 主力选股功能 ⭐️
- **季报数据**:问财(pywencai)- 财务数据补充 ⭐️
- **技术指标**TA-Lib技术分析库
### AI模型
+28 -15
View File
@@ -383,6 +383,7 @@ def main():
st.markdown("""
**股票代码格式**
- 🇨🇳 A股:6位数字(如600519)
- 🇭🇰 港股:1-5位数字(如700、00700)或HK前缀(如HK00700
- 🇺🇸 美股:字母代码(如AAPL)
**功能说明**
@@ -448,8 +449,8 @@ def main():
with col1:
stock_input = st.text_input(
"🔍 请输入股票代码或名称",
placeholder="例如: AAPL, 000001, 600036",
help="支持美股代码(如AAPL)和A股代码(如000001)"
placeholder="例如: AAPL, 000001, 00700",
help="支持A股(如000001)、港股(如00700)和美股(如AAPL)"
)
with col2:
@@ -464,9 +465,9 @@ def main():
# 批量股票分析界面
stock_input = st.text_area(
"🔍 请输入多个股票代码(每行一个或用逗号分隔)",
placeholder="例如:\n000001\n600036\n600519\n\n或者: 000001, 600036, 600519",
placeholder="例如:\n000001\n600036\n00700\n\n或者: 000001, 600036, 00700, AAPL",
height=120,
help="支持多种格式:每行一个代码或用逗号分隔"
help="支持多种格式:每行一个代码或用逗号分隔。支持A股、港股、美股"
)
col1, col2, col3 = st.columns(3)
@@ -1414,9 +1415,9 @@ def show_example_interface():
with col1:
st.markdown("""
### 🚀 如何使用
1. **输入股票代码**:支持美股(如AAPL、MSFT)和A股(如000001、600036)
1. **输入股票代码**:支持A股(如000001)、港股(如00700)和美股(如AAPL)
2. **点击开始分析**:系统将启动AI分析师团队
3. **查看分析报告**:5位专业分析师将从不同角度分析
3. **查看分析报告**:位专业分析师将从不同角度分析
4. **获得投资建议**:获得最终的投资评级和操作建议
### 📊 分析维度
@@ -1431,23 +1432,35 @@ def show_example_interface():
st.markdown("""
### 📈 示例股票代码
**美股热门**
- AAPL (苹果)
- MSFT (微软)
- GOOGL (谷歌)
- TSLA (特斯拉)
- NVDA (英伟达)
**A股热门**
- 000001 (平安银行)
- 600036 (招商银行)
- 000002 (万科A)
- 600519 (贵州茅台)
- 000858 (五粮液)
**港股热门**
- 00700 或 700 (腾讯控股)
- 09988 或 9988 (阿里巴巴-SW)
- 01810 或 1810 (小米集团-W)
**美股热门**
- AAPL (苹果)
- MSFT (微软)
- NVDA (英伟达)
""")
st.info("💡 提示:首次运行需要配置DeepSeek API Key,请在.env中设置DEEPSEEK_API_KEY")
st.markdown("---")
st.markdown("""
### 🌏 市场支持说明
- **A股**:完整支持(技术分析、财务数据、资金流向、市场情绪、新闻公告)
- **港股**:部分支持(技术分析、21项财务指标)⭐️
- **美股**:完整支持(技术分析、财务数据)
### 📊 港股支持的财务指标
盈利能力(6项)、营运能力(3项)、偿债能力(2项)、市场表现(4项)、分红指标(3项)、股本结构(3项)
""")
def display_history_records():
"""显示历史分析记录"""
st.subheader("📚 历史分析记录")
+26 -7
View File
@@ -21,30 +21,49 @@ import tempfile
import os
def register_chinese_fonts():
"""注册中文字体"""
"""注册中文字体 - 支持Windows和Linux系统"""
try:
# 检查是否已经注册过
if 'ChineseFont' in pdfmetrics.getRegisteredFontNames():
return 'ChineseFont'
# 尝试注册系统中文字体
font_paths = [
# Windows系统字体路径
windows_font_paths = [
'C:/Windows/Fonts/simsun.ttc', # 宋体
'C:/Windows/Fonts/simhei.ttf', # 黑体
'C:/Windows/Fonts/msyh.ttc', # 微软雅黑
'C:/Windows/Fonts/msyh.ttf', # 微软雅黑(TTF格式)
]
for font_path in font_paths:
# Linux系统字体路径(Docker环境)
linux_font_paths = [
'/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc', # 文泉驿正黑
'/usr/share/fonts/truetype/wqy/wqy-microhei.ttc', # 文泉驿微米黑
'/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc', # Noto Sans CJK
'/usr/share/fonts/opentype/noto/NotoSerifCJK-Regular.ttc', # Noto Serif CJK
'/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf', # Droid字体
]
# 合并所有可能的字体路径
all_font_paths = windows_font_paths + linux_font_paths
# 尝试注册字体
for font_path in all_font_paths:
if os.path.exists(font_path):
try:
pdfmetrics.registerFont(TTFont('ChineseFont', font_path))
print(f"✅ 成功注册中文字体: {font_path}")
return 'ChineseFont'
except:
except Exception as e:
print(f"⚠️ 尝试注册字体 {font_path} 失败: {e}")
continue
# 如果没有找到中文字体,使用默认字体
# 如果没有找到中文字体,打印警告并使用默认字体
print("⚠️ 警告:未找到中文字体,PDF中文可能显示为方框")
print("建议:在Docker中安装中文字体包")
return 'Helvetica'
except:
except Exception as e:
print(f"❌ 注册中文字体时出错: {e}")
return 'Helvetica'
def create_pdf_report(stock_info, agents_results, discussion_result, final_decision):
+225 -3
View File
@@ -19,9 +19,13 @@ class StockDataFetcher:
def get_stock_info(self, symbol):
"""获取股票基本信息"""
try:
# 处理中国股票代码
# 处理中国A
if self._is_chinese_stock(symbol):
return self._get_chinese_stock_info(symbol)
# 处理港股
elif self._is_hk_stock(symbol):
return self._get_hk_stock_info(symbol)
# 处理美股
else:
return self._get_us_stock_info(symbol)
except Exception as e:
@@ -32,16 +36,36 @@ class StockDataFetcher:
try:
if self._is_chinese_stock(symbol):
return self._get_chinese_stock_data(symbol, period)
elif self._is_hk_stock(symbol):
return self._get_hk_stock_data(symbol, period)
else:
return self._get_us_stock_data(symbol, period, interval)
except Exception as e:
return {"error": f"获取股票数据失败: {str(e)}"}
def _is_chinese_stock(self, symbol):
"""判断是否为中国股"""
# 简单判断:包含数字且长度为6位的认为是中国股
"""判断是否为中国A"""
# 简单判断:包含数字且长度为6位的认为是中国A
return symbol.isdigit() and len(symbol) == 6
def _is_hk_stock(self, symbol):
"""判断是否为港股"""
# 港股代码通常是1-5位数字,或者前面带HK/hk前缀
if symbol.upper().startswith('HK'):
return True
# 纯数字且长度在1-5位之间,认为可能是港股
if symbol.isdigit() and 1 <= len(symbol) <= 5:
return True
return False
def _normalize_hk_code(self, symbol):
"""规范化港股代码为5位格式(如700 -> 00700"""
# 移除HK前缀
if symbol.upper().startswith('HK'):
symbol = symbol[2:]
# 补齐到5位
return symbol.zfill(5)
def _get_chinese_stock_info(self, symbol):
"""获取中国股票基本信息"""
try:
@@ -187,6 +211,92 @@ class StockDataFetcher:
"exchange": "上海/深圳证券交易所"
}
def _get_hk_stock_info(self, symbol):
"""获取港股基本信息"""
try:
# 规范化港股代码
hk_code = self._normalize_hk_code(symbol)
# 初始化基本信息
info = {
"symbol": hk_code,
"name": "未知",
"current_price": "N/A",
"change_percent": "N/A",
"pe_ratio": "N/A",
"pb_ratio": "N/A",
"market_cap": "N/A",
"market": "香港股市",
"exchange": "香港交易所"
}
# 方法1: 获取港股实时行情
try:
# 使用akshare获取港股实时数据
realtime_df = ak.stock_hk_spot_em()
if realtime_df is not None and not realtime_df.empty:
# 查找对应股票
stock_data = realtime_df[realtime_df['代码'] == hk_code]
if not stock_data.empty:
row = stock_data.iloc[0]
info['name'] = row.get('名称', '未知')
info['current_price'] = row.get('最新价', 'N/A')
info['change_percent'] = row.get('涨跌幅', 'N/A')
# 市值(港元)
market_cap = row.get('总市值', 'N/A')
if market_cap != 'N/A':
try:
info['market_cap'] = float(market_cap)
except:
pass
# 市盈率
pe = row.get('市盈率', 'N/A')
if pe != 'N/A' and pe != '-':
try:
pe_val = float(pe)
if 0 < pe_val <= 1000:
info['pe_ratio'] = pe_val
except:
pass
except Exception as e:
print(f"获取港股实时数据失败: {e}")
# 方法2: 尝试使用历史数据获取价格信息
if info['current_price'] == 'N/A':
try:
hist_df = ak.stock_hk_hist(symbol=hk_code, period="daily",
start_date=(datetime.now() - timedelta(days=5)).strftime('%Y%m%d'),
end_date=datetime.now().strftime('%Y%m%d'), adjust="qfq")
if hist_df is not None and not hist_df.empty:
latest = hist_df.iloc[-1]
info['current_price'] = latest['收盘']
# 计算涨跌幅
if len(hist_df) > 1:
prev_close = hist_df.iloc[-2]['收盘']
change_pct = ((latest['收盘'] - prev_close) / prev_close) * 100
info['change_percent'] = round(change_pct, 2)
except Exception as e:
print(f"获取港股历史数据失败: {e}")
return info
except Exception as e:
print(f"获取港股信息完全失败: {e}")
# 返回基本信息
return {
"symbol": symbol,
"name": f"港股{symbol}",
"current_price": "N/A",
"change_percent": "N/A",
"pe_ratio": "N/A",
"pb_ratio": "N/A",
"market_cap": "N/A",
"market": "香港股市",
"exchange": "香港交易所"
}
def _get_us_stock_info(self, symbol):
"""获取美股基本信息"""
import time
@@ -315,6 +425,48 @@ class StockDataFetcher:
except Exception as e:
return {"error": f"获取中国股票数据失败: {str(e)}"}
def _get_hk_stock_data(self, symbol, period="1y"):
"""获取港股历史数据"""
try:
# 规范化港股代码
hk_code = self._normalize_hk_code(symbol)
# 计算日期范围
end_date = datetime.now().strftime('%Y%m%d')
if period == "1y":
start_date = (datetime.now() - timedelta(days=365)).strftime('%Y%m%d')
elif period == "6mo":
start_date = (datetime.now() - timedelta(days=180)).strftime('%Y%m%d')
elif period == "3mo":
start_date = (datetime.now() - timedelta(days=90)).strftime('%Y%m%d')
elif period == "1mo":
start_date = (datetime.now() - timedelta(days=30)).strftime('%Y%m%d')
else:
start_date = (datetime.now() - timedelta(days=365)).strftime('%Y%m%d')
# 获取港股历史数据
df = ak.stock_hk_hist(symbol=hk_code, period="daily",
start_date=start_date, end_date=end_date, adjust="qfq")
if df is not None and not df.empty:
# 重命名列以匹配标准格式
df = df.rename(columns={
'日期': 'Date',
'开盘': 'Open',
'收盘': 'Close',
'最高': 'High',
'最低': 'Low',
'成交量': 'Volume'
})
df['Date'] = pd.to_datetime(df['Date'])
df.set_index('Date', inplace=True)
return df
else:
return {"error": "无法获取港股历史数据"}
except Exception as e:
return {"error": f"获取港股数据失败: {str(e)}"}
def _get_us_stock_data(self, symbol, period="1y", interval="1d"):
"""获取美股历史数据"""
try:
@@ -398,6 +550,8 @@ class StockDataFetcher:
try:
if self._is_chinese_stock(symbol):
return self._get_chinese_financial_data(symbol)
elif self._is_hk_stock(symbol):
return self._get_hk_financial_data(symbol)
else:
return self._get_us_financial_data(symbol)
except Exception as e:
@@ -547,6 +701,74 @@ class StockDataFetcher:
traceback.print_exc()
return None
def _get_hk_financial_data(self, symbol):
"""获取港股财务数据"""
hk_code = self._normalize_hk_code(symbol)
financial_data = {
"symbol": hk_code,
"balance_sheet": None,
"income_statement": None,
"cash_flow": None,
"financial_ratios": {},
"quarter_data": None,
"data_source": "eastmoney",
"note": "港股财务数据来自东方财富"
}
try:
# 使用akshare获取港股财务指标(东方财富数据源)
print(f"正在获取港股 {hk_code} 的财务指标...")
try:
financial_indicator = ak.stock_hk_financial_indicator_em(symbol=hk_code)
if financial_indicator is not None and not financial_indicator.empty:
# 将财务指标数据转换为字典
indicator_dict = financial_indicator.iloc[0].to_dict()
# 整理财务比率数据
financial_data["financial_ratios"] = {
"基本每股收益": self._safe_convert(indicator_dict.get('基本每股收益(元)', 'N/A')),
"每股净资产": self._safe_convert(indicator_dict.get('每股净资产(元)', 'N/A')),
"每股股息TTM": self._safe_convert(indicator_dict.get('每股股息TTM(港元)', 'N/A')),
"派息比率": self._safe_convert(indicator_dict.get('派息比率(%)', 'N/A')),
"每股经营现金流": self._safe_convert(indicator_dict.get('每股经营现金流(元)', 'N/A')),
"股息率TTM": self._safe_convert(indicator_dict.get('股息率TTM(%)', 'N/A')),
"总市值": self._safe_convert(indicator_dict.get('总市值(港元)', 'N/A')),
"港股市值": self._safe_convert(indicator_dict.get('港股市值(港元)', 'N/A')),
"营业总收入": self._safe_convert(indicator_dict.get('营业总收入', 'N/A')),
"营业收入环比增长": self._safe_convert(indicator_dict.get('营业总收入滚动环比增长(%)', 'N/A')),
"销售净利率": self._safe_convert(indicator_dict.get('销售净利率(%)', 'N/A')),
"净利润": self._safe_convert(indicator_dict.get('净利润', 'N/A')),
"净利润环比增长": self._safe_convert(indicator_dict.get('净利润滚动环比增长(%)', 'N/A')),
"ROE股东权益回报率": self._safe_convert(indicator_dict.get('股东权益回报率(%)', 'N/A')),
"市盈率": self._safe_convert(indicator_dict.get('市盈率', 'N/A')),
"市净率": self._safe_convert(indicator_dict.get('市净率', 'N/A')),
"ROA总资产回报率": self._safe_convert(indicator_dict.get('总资产回报率(%)', 'N/A')),
"法定股本": self._safe_convert(indicator_dict.get('法定股本(股)', 'N/A')),
"已发行股本": self._safe_convert(indicator_dict.get('已发行股本(股)', 'N/A')),
"每手股": self._safe_convert(indicator_dict.get('每手股', 'N/A')),
}
print(f"✅ 成功获取港股 {hk_code} 的财务指标")
print(f" ROE: {financial_data['financial_ratios']['ROE股东权益回报率']}")
print(f" 市盈率: {financial_data['financial_ratios']['市盈率']}")
print(f" 市净率: {financial_data['financial_ratios']['市净率']}")
else:
print(f"⚠️ 未获取到港股 {hk_code} 的财务指标数据")
financial_data["note"] = "未获取到财务数据"
except Exception as e:
print(f"⚠️ 获取港股财务指标失败: {e}")
financial_data["note"] = f"获取财务数据失败: {str(e)}"
return financial_data
except Exception as e:
print(f"获取港股财务数据异常: {e}")
financial_data["note"] = f"获取失败: {str(e)}"
return financial_data
def _get_us_financial_data(self, symbol):
"""获取美股财务数据"""
financial_data = {
+165
View File
@@ -0,0 +1,165 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
PDF中文字体测试脚本
用于验证Docker环境中字体是否正确安装
"""
import os
import sys
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
def check_system_fonts():
"""检查系统中可用的中文字体"""
print("=" * 60)
print("检查系统中的中文字体")
print("=" * 60)
# Windows字体路径
windows_paths = [
'C:/Windows/Fonts/simsun.ttc',
'C:/Windows/Fonts/simhei.ttf',
'C:/Windows/Fonts/msyh.ttc',
'C:/Windows/Fonts/msyh.ttf',
]
# Linux字体路径
linux_paths = [
'/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc',
'/usr/share/fonts/truetype/wqy/wqy-microhei.ttc',
'/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc',
'/usr/share/fonts/opentype/noto/NotoSerifCJK-Regular.ttc',
]
all_paths = windows_paths + linux_paths
found_fonts = []
for font_path in all_paths:
if os.path.exists(font_path):
print(f"✅ 找到字体: {font_path}")
found_fonts.append(font_path)
else:
print(f"❌ 未找到: {font_path}")
print(f"\n总计找到 {len(found_fonts)} 个中文字体文件")
return found_fonts
def test_font_registration():
"""测试字体注册"""
print("\n" + "=" * 60)
print("测试字体注册")
print("=" * 60)
fonts = check_system_fonts()
if not fonts:
print("\n❌ 错误:未找到任何中文字体")
print("建议:")
print(" - Windows: 确保系统已安装中文字体")
print(" - Linux/Docker: 运行 'apt-get install fonts-noto-cjk fonts-wqy-zenhei'")
return False
# 尝试注册第一个找到的字体
test_font = fonts[0]
try:
pdfmetrics.registerFont(TTFont('TestChineseFont', test_font))
print(f"\n✅ 成功注册字体: {test_font}")
print(f" 注册名称: TestChineseFont")
return True
except Exception as e:
print(f"\n❌ 字体注册失败: {e}")
return False
def test_pdf_generation():
"""测试PDF生成"""
print("\n" + "=" * 60)
print("测试PDF生成")
print("=" * 60)
try:
from reportlab.lib.pagesizes import A4
from reportlab.platypus import SimpleDocTemplate, Paragraph
from reportlab.lib.styles import ParagraphStyle
import io
# 导入字体注册函数
from pdf_generator import register_chinese_fonts
# 注册字体
font_name = register_chinese_fonts()
print(f"\n使用字体: {font_name}")
# 创建测试PDF
buffer = io.BytesIO()
doc = SimpleDocTemplate(buffer, pagesize=A4)
# 创建样式
style = ParagraphStyle(
'TestStyle',
fontName=font_name,
fontSize=12
)
# 创建内容
test_text = "这是一个中文PDF测试 - AI股票分析系统"
paragraph = Paragraph(test_text, style)
# 生成PDF
doc.build([paragraph])
# 检查生成的PDF大小
pdf_size = len(buffer.getvalue())
print(f"✅ PDF生成成功,大小: {pdf_size} 字节")
# 保存测试PDF
with open('test_chinese_pdf.pdf', 'wb') as f:
f.write(buffer.getvalue())
print(f"✅ 测试PDF已保存到: test_chinese_pdf.pdf")
print(f" 请打开文件检查中文是否正常显示")
return True
except Exception as e:
print(f"❌ PDF生成失败: {e}")
import traceback
traceback.print_exc()
return False
def main():
"""主函数"""
print("\n")
print("" + "=" * 58 + "")
print("" + " " * 15 + "PDF中文字体测试" + " " * 15 + "")
print("" + "=" * 58 + "")
print()
# 检测操作系统
import platform
print(f"操作系统: {platform.system()} {platform.release()}")
print(f"Python版本: {sys.version}")
print()
# 运行测试
font_check = check_system_fonts()
font_reg = test_font_registration()
pdf_gen = test_pdf_generation()
# 总结
print("\n" + "=" * 60)
print("测试总结")
print("=" * 60)
print(f"字体检查: {'✅ 通过' if font_check else '❌ 失败'}")
print(f"字体注册: {'✅ 通过' if font_reg else '❌ 失败'}")
print(f"PDF生成: {'✅ 通过' if pdf_gen else '❌ 失败'}")
if font_check and font_reg and pdf_gen:
print("\n🎉 所有测试通过!PDF中文字体配置正确。")
else:
print("\n⚠️ 部分测试失败,请查看上方详细信息进行排查。")
print()
if __name__ == "__main__":
main()
+226
View File
@@ -0,0 +1,226 @@
# 港股分析功能说明
## ✨ 功能概述
系统现已支持港股分析功能,可以对香港交易所上市的股票进行技术面和基本面分析。
## 📊 支持的功能
### ✅ 完全支持
1. **股票代码识别**
- 支持1-5位数字代码(如:700, 9988, 01810
- 支持HK前缀格式(如:HK00700)
- 自动规范化为5位标准格式
2. **基本信息获取**
- 股票名称
- 当前价格
- 涨跌幅
- 市盈率(PE
- 市净率(PB
- 市值
3. **历史数据获取**
- 支持多个时间周期(1mo, 3mo, 6mo, 1y
- OHLCV数据(开盘、最高、最低、收盘、成交量)
- 完整的历史K线数据
4. **技术指标计算**
- 移动平均线(MA5, MA10, MA20, MA60
- 相对强弱指标(RSI
- MACD指标
- 布林带(Bollinger Bands
- KDJ指标
- 成交量指标
5. **AI智能分析**
- 技术分析师:图表形态、趋势判断
- 风险管理师:风险识别与控制
- 基本面分析师:公司价值评估(含21项财务指标)⭐️ 新增
- 团队综合决策
### ✅ 完全支持(新增)
1. **财务指标数据**
- 基本每股收益、每股净资产
- 每股股息TTM、派息比率、股息率TTM
- 每股经营现金流
- 总市值、港股市值
- 营业总收入、营业收入环比增长
- 销售净利率、净利润、净利润环比增长
- ROE(股东权益回报率)
- ROA(总资产回报率)
- 市盈率、市净率
- 法定股本、已发行股本、每手股数
- 数据来源:东方财富(akshare接口)
### ❌ 暂不支持
1. **资金流向分析**(仅支持A股)
2. **市场情绪分析**(仅支持A股)
3. **新闻公告分析**(仅支持A股)
## 🔧 使用方法
### 代码格式示例
```python
# 方式1:简短格式
700 # 腾讯控股
9988 # 阿里巴巴-SW
1810 # 小米集团-W
# 方式2:标准5位格式
00700 # 腾讯控股
09988 # 阿里巴巴-SW
01810 # 小米集团-W
# 方式3HK前缀格式
HK00700 # 腾讯控股
HK09988 # 阿里巴巴-SW
HK01810 # 小米集团-W
```
### 在系统中使用
1. **单个分析**
- 在输入框输入港股代码(如:700 或 00700)
- 点击"开始分析"
- 查看AI团队分析报告
2. **批量分析**
- 支持混合分析A股、港股、美股
- 例如:`000001, 00700, AAPL`
3. **分析师选择**
- ✅ 推荐选择:技术分析师、基本面分析师(含21项财务指标)、风险管理师
- ❌ 不推荐:市场情绪分析师、新闻公告分析师(港股不支持)
## 📈 热门港股代码
| 代码 | 公司名称 | 行业 |
|------|----------|------|
| 00700 | 腾讯控股 | 互联网科技 |
| 09988 | 阿里巴巴-SW | 电商/云计算 |
| 01810 | 小米集团-W | 智能手机/IoT |
| 00388 | 香港交易所 | 金融服务 |
| 00939 | 建设银行 | 银行 |
| 01024 | 快手-W | 短视频平台 |
| 09618 | 京东集团-SW | 电商 |
| 03690 | 美团-W | 本地生活服务 |
| 02331 | 李宁 | 体育用品 |
| 01299 | 友邦保险 | 保险 |
## 💡 使用建议
### 适合场景
- ✅ 技术面分析(K线、指标、形态)
- ✅ 基本面分析(21项财务指标)⭐️ 新增
- ✅ 短期交易策略制定
- ✅ 中长期投资决策
- ✅ 价格趋势判断
- ✅ 风险评估
- ✅ 价值投资分析
### 建议补充
- 💡 行业对比(建议参考行业报告)
- 💡 深度研究(建议结合年报和行业分析)
## 🔍 技术实现
### 数据来源
- **行情数据**AKShare - `stock_hk_spot_em()`
- **历史数据**AKShare - `stock_hk_hist()`
- **财务指标**AKShare - `stock_hk_financial_indicator_em()` ⭐️ 新增
- **技术指标**TA-Lib库计算
### 代码位置
- **主要实现**`stock_data.py`
- `_is_hk_stock()` - 港股识别
- `_normalize_hk_code()` - 代码规范化
- `_get_hk_stock_info()` - 基本信息获取
- `_get_hk_stock_data()` - 历史数据获取
- `_get_hk_financial_data()` - 财务数据获取
## 📊 支持的财务指标(21项)
### 盈利能力指标
- 基本每股收益(EPS
- 净利润
- 净利润环比增长率
- 销售净利率
- ROE(股东权益回报率)
- ROA(总资产回报率)
### 营运能力指标
- 营业总收入
- 营业收入环比增长率
- 每股经营现金流
### 偿债能力指标
- 每股净资产
- 总资产
### 市场表现指标
- 市盈率(P/E
- 市净率(P/B
- 总市值
- 港股市值
### 分红指标
- 每股股息TTM
- 股息率TTM
- 派息比率
### 股本结构
- 法定股本
- 已发行股本
- 每手股数
## 🚀 后续优化方向
1. **数据源扩展**
- ✅ 已完成:财务指标数据(21项)
- 待开发:完整财务报表(资产负债表、利润表、现金流量表)
- 待开发:港股通资金流向
2. **功能增强**
- 港股特有指标分析
- 恒生指数关联分析
- 南下资金追踪
3. **用户体验**
- 港股交易时间提示
- 货币汇率转换
- 港股通标的筛选
## 📝 注意事项
1. **交易时间**
- 港股交易时间与A股不同
- 上午:9:30-12:00
- 下午:13:00-16:00
- 注意节假日差异
2. **货币单位**
- 报价单位:港币(HKD
- 与人民币汇率需要转换
3. **数据延迟**
- 免费数据可能有延迟
- 建议以实盘为准
4. **投资风险**
- 港股T+0交易,风险较大
- 涨跌幅无限制
- 请谨慎投资
## 📞 技术支持
如遇到港股分析相关问题,请:
1. 查看系统日志输出
2. 运行测试脚本:`python test_hk_stock.py`
3. 联系技术支持:ws3101001@126.com
---
**最后更新**2025年10月10日
**版本**v1.0
**状态**:✅ 已完成测试