股票深度研究报告
股票深度研究报告
基于同花顺问财 OpenAPI + 东方财富妙想API 的股票深度研究数据采集与报告生成工具。
使用场景
当用户说以下关键词时,使用此技能:
- "分析XX股票"
- "生成XX的研究报告"
- "XX股票深度研究"
- "XX股票分析"
- "帮我看看XX"
快速开始(一键执行)
# 完整流程:采集(含全部补充)→生成报告→上传IMA(推荐)
python3 ~/.hermes/scripts/stock-research/generate_report.py -c 601899 -n 紫金矿业
# 跳过采集(已有JSON时)
python3 ~/.hermes/scripts/stock-research/generate_report.py -c 601899 -n 紫金矿业 --skip-collect
# 不上传IMA(仅本地生成)
python3 ~/.hermes/scripts/stock-research/generate_report.py -c 601899 -n 紫金矿业 --keep-local
generate_report.py v10 完整流程(4步,全部自动化)
Step 1: collector.py v8 采集全部数据
- 基础采集(13模块,westock-data为主+妙想/问财备选)
- 补充采集(已内置,自动运行):
✓ 历史季度累计数据(2024/2025年Q1-Q4)→ reporter自动计算单季度
✓ 运营效率(应收账款/存货/总资产周转率)→ 问财401时自动切妙想API
✓ 现金流(经营现金流/企业自由现金流)→ 同上
✓ 估值字段(市销率/股息率/营收同比/净利同比/加权ROE)
✓ 行业平均PE/PB
✓ 历史PE详细(5年每年最高/最低/平均,妙想API)
→ JSON文件(0个N/A)
Step 2: reporter_v6.py 生成报告
→ Markdown报告(v6模板13个完整模块)
Step 3: ima_integration.py 上传IMA
→ MD→PDF→COS→知识库
Step 4: 清理旧文件
✓ 删除 output/ 下旧JSON(保留最新)
✓ 删除 miaoxiang/mx_finance_data/ 下所有 .xlsx 和 _description.txt
```bash
# 完整流程:采集(含全部补充)→生成报告→上传IMA(推荐)
python3 ~/.hermes/scripts/stock-research/generate_report.py -c 601899 -n 紫金矿业
# 跳过采集(已有JSON时)
python3 ~/.hermes/scripts/stock-research/generate_report.py -c 601899 -n 紫金矿业 --skip-collect
# 不上传IMA(仅本地生成)
python3 ~/.hermes/scripts/stock-research/generate_report.py -c 601899 -n 紫金矿业 --keep-local
分步执行(调试用)
# 1. 采集数据(v8 westock-data为主)
python3 ~/.hermes/scripts/stock-research/collector.py -c 601899 -n 紫金矿业
# 2. 生成报告
python3 ~/.hermes/scripts/stock-research/reporter_v6.py \
--json-path output/601899_紫金矿业_*.json \
--output output/紫金矿业_深度研究报告.md
# 3. 上传IMA
python3 ~/.hermes/scripts/stock-research/ima_integration.py \
--report-path output/紫金矿业_深度研究报告.md \
--stock-name 紫金矿业 --stock-code 601899
数据覆盖度(v10 - 13模块+3补充模块,60+查询)
collector.py v6已直接集成13个模块的数据采集,无需额外手动调用mx-finance-data补充基础数据。
✅ collector.py 直接采集的数据(13个模块)
| # | 模块 | 查询数 | 数据源技能 |
|---|---|---|---|
| 1 | 报告摘要 | 5 | hithink-finance-query + hithink-industry-query |
| 2 | 宏观与行业 | 7 | hithink-industry-query + hithink-sector-selector |
| 3 | 公司基本面 | 7 | hithink-finance-query + hithink-business-query |
| 4 | 公司治理与股东 | 9 | hithink-management-query + hithink-business-query + news-search |
| 5 | 机构持仓与市场情绪 | 4 | hithink-insresearch-query |
| 6 | 估值分析 | 3 | hithink-finance-query |
| 7 | 重大事件与风险 | 3 | hithink-management-query + hithink-business-query |
| 8 | 资金流向 | 2 | hithink-sector-selector |
| 9 | 新闻资讯 | 4 | news-search |
| 10 | 技术面 | 3 | hithink-market-query |
| 11 | 营收结构与成本 | 4 | hithink-business-query + hithink-finance-query |
| 12 | 杜邦分析与盈利质量 | 3 | hithink-finance-query |
| 13 | 历史估值与同行对比 | 3 | hithink-finance-query |
总计:57个查询,13个模块全覆盖
✅ 仍可使用mx-finance-data补充的高级数据
| 数据项 | 数据源技能 | 调用方式 |
|---|---|---|
| 详细K线数据 | mx-finance-data | --query "XX股票 近20日K线数据 MACD RSI KDJ" |
| 历史估值详细 | mx-finance-data | --query "XX股票 近5年市盈率PE最高最低平均" |
| 宏观数据 | mx-macro-data | --query "中国GDP增速 近5年" |
| 金融资讯/研报 | mx-finance-search | "XX股票 最新研报与公告" |
⚠️ 仍无法获取的数据
| 数据项 | 说明 |
|---|---|
| ESG评级 | 需要专门的ESG数据源 |
⚠️ 注意:collector.py v7 已内置全部补充查询(季度历史/运营效率/现金流/估值字段/历史PE/行业平均),大部分情况下无需额外调用mx-finance-data。
⛔ reporter_v6.py 零硬编码强制规则(2026-05-11 确立)
核心原则:reporter_v6.py中不得有任何"不管数据是什么都输出固定文字"的代码。
两层硬编码风险
| 层级 | 表现 | 危险程度 | 检测方法 |
|---|---|---|---|
| 第一层:数据矛盾 | 结论与上方数据不一致(如净流出写"净流入") | 高 | 📌结论逐条核对 |
| 第二层:公司绑定 | 结论绑定到特定公司(如"黄金冶炼"对所有股票输出) | 极高 | grep公司特定关键词 |
第二层更危险:代码"运行正常"但对非目标公司输出完全错误结论。
禁止的写法
# ❌ 硬编码公司描述
w(f"- 行业地位:{sn},消费电子精密零组件龙头")
w("- 宏观环境:消费电子行业复苏,AI终端需求增长")
w("1. **AI终端驱动:** AI手机、AI眼镜等新品渗透率提升")
w("- 🚀 国际金价高位运行,黄金冶炼利润有保障")
# ❌ 硬编码通用模板
w("- ✅ 行业龙头地位,市场份额领先")
w("- ✅ 全球化布局完善,海外产能占比高")
w("**核心竞争壁垒:** 全球化壁垒+技术壁垒+客户壁垒+品牌壁垒")
必须的写法
# ✅ 从数据动态生成
mktcap_val = sf(mktcap)
if mktcap_val > 1000:
w(f"- **行业地位:** {sn},所属行业大型企业")
elif mktcap_val > 300:
w(f"- **行业地位:** {sn},所属行业骨干企业")
else:
w(f"- **行业地位:** {sn},所属行业参与者")
# ✅ 从营收结构推断驱动因素
if rp:
top1 = rp[0].get("项目名称", "核心业务")
top1_pct = float(rp[0].get("业务收入", 0) or 0) / total_product_rev * 100
w(f"1. **{top1}驱动:** 占收入{top1_pct:.1f}%,是业绩核心增长引擎")
# ✅ 从实际数据推断结论
pe_ratio = sf(pe) / sf(pe_iv) if sf(pe_iv) > 0 else 1
if pe_ratio > 1.5:
w(f"- ⚠️ PE-TTM {pe}倍,显著高于行业均值{pe_iv}倍")
验证检查清单
# 1. 检查硬编码公司特定描述残留
grep -c "黄金\|锑品\|贵金属\|金价\|消费电子\|AI终端\|汽车电子\|全球化布局\|国产替代\|并购整合\|外延式" report.md
# 期望:仅剩分析师研报原文和真实人名(≤5处)
# 2. 检查📌结论是否与数据一致
grep '📌' report.md
# 逐条验证
# 3. 检查N/A和待确认
grep -c "待确认\|N/A" report.md
# 期望:0
修复详情:
- 第一轮(2026-05-10):38处数据矛盾修复 →
references/reporter-hardcoded-conclusion-fixes.md - 第二轮(2026-05-11):28处公司绑定修复 →
references/reporter-hardcoded-conclusion-fixes-round3.md
已知Bug与修复记录
- safe_get函数默认值bug:
safe_get(sections, "key1", "key2", "key3", [])中[]被当作key而非default,必须用default=[]关键字参数 - 股东字段名不一致:
大股东名称vs股东名称,需同时兼容两个字段名 - 持股比例字段名:
持股比例[20260331]vs持股占流通股比例[20260331],需兼容 - croniter依赖:Hermes venv需要单独安装croniter包
- 季度数据缺口(2026-05-05,已修复):collector.py已直接采集季度财务数据(模块1),通过
quarterly_financials查询获取。如仍需更详细的8季度历史数据,可用mx-finance-data补充。 - PDF中文乱码(2026-05-07,已修复):系统缺少中文字体,安装
fonts-noto-cjk+fonts-wqy-microhei解决。CSS font-family 以 "Noto Sans CJK SC" 为首选。 - PDF emoji乱码(2026-05-07,已修复):weasyprint不支持彩色emoji,ima_integration.py自动将emoji替换为纯文本标记([OK]/[!]/[X])。
报告结构
生成的报告严格遵循以下框架:
- 报告摘要 - 核心投资逻辑、风险提示、目标价位
- 深度分析
- 宏观环境与行业分析
- 公司基本面分析(财务、治理、股东)
- 估值分析(PE/PB/同行对比)
- 技术面分析(需额外数据)
- 风险与机会评估
- 投资建议 - 操作策略、入场/止损/目标价位
文件结构(v11 - 最终版)
/root/.hermes/scripts/stock-research/
├── generate_report.py # v10 一键编排(4步:采集→生成→上传→清理)
├── collector.py # v8 数据采集(westock-data为主+妙想/问财备选,13模块全覆盖)
├── reporter_v6.py # v8.4 报告生成(JSON→固定格式MD,含sf()+季度计算+N/A安全处理)
├── ima_integration.py # v2 IMA上传模块(MD→PDF→COS→知识库)
├── miaoxiang/ # 妙想API输出目录(每次成功后清理xlsx文件)
│ └── mx_finance_data/ # mx-finance-data输出(报告成功后必须清空)
├── output/ # 输出目录(上传后自动清理.md/.pdf,保留最新JSON)
└── README.md # 说明文档
⚠️ 清理规则:每次成功生成报告后,删除 output/ 下旧JSON + miaoxiang/mx_finance_data/ 下所有xlsx和txt文件
collector.py v8 数据源策略(2026-05-08 确立,v8升级)
数据源优先级:westock-data(腾讯自选股)> 妙想API > 问财API
降级机制:query_with_fallback() 自动切换
westock-data适用场景:K线、财务报表、公司概况、股东结构、分红、资金流向、技术指标(免费无限制)
问财API适用场景:行业数据、机构研究、新闻资讯(妙想/westock覆盖不到的)
westock-data调用方式:通过 subprocess 调用 npx -y westock-data-skillhub@1.0.3 <command> <code>,解析返回的 Markdown 表格。
westock-data支持的命令:kline, finance, profile, shareholder, dividend, asfund, technical, search, minute, chip, lhb, blocktrade, margintrade, hot, board, calendar, ipo, etf
Pitfalls & 开发经验
⛔ P0 Critical: 季度财务数据缺口(已由generate_report.py v9自动修复)
问题描述: 报告中季度财务数据只有最新一期(如2026Q1),缺失历史季度数据。
根因: hithink-finance-query 查询季度数据时API只返回最新一期,不返回历史季度。
v9自动修复方案(generate_report.py已内置):
generate_report.py v9的Step 2a自动执行以下补充:
- 分两次查询获取2024年和2025年的累计数据
- 从累计值计算单季度值(Q1=累计, Q2=H1-Q1, Q3=9M-H1, Q4=FY-9M)
- 写入JSON的
quarterly_cumulative字段 - reporter_v6.py自动读取并计算9个季度的单季度值
验证方法: 生成报告后,检查季度财务数据表格是否有9行数据(2024Q1-Q4 + 2025Q1-Q4 + 2026Q1)。
⛔ P0 Critical: 报告生成必须使用collector.py(数据质量事故教训)
问题描述(2026-05-04通富微电事故): 系统报告中股价写"约15元",实际为51.77元,偏差3.45倍!市值230亿 vs 实际800亿。
根因分析:
- 报告是通过LLM手动调用mx-finance-data查询生成,没有使用collector.py
- 无JSON数据文件,无法追溯数据来源
- LLM解读API返回数据时产生幻觉(Hallucination)
- 关键指标(股价、市值、资产负债率)全部错误
必须遵守的规则:
⛔ 禁止:直接调用mx-finance-data生成报告
✅ 必须:使用collector.py采集数据 → 生成JSON → 使用reporter_v6.py生成报告
验证方法: 生成报告后,检查output目录是否有对应的JSON文件。如果没有,说明数据质量不可靠。
数据验证清单(报告生成后必须执行):
| 指标 | 合理范围 | 异常处理 |
|---|---|---|
| 股价 | A股:5-500元 | 低于5元或高于500元需人工核实 |
| 总市值 | 与股本匹配 | 市值/股本 应≈当前股价 |
| 资产负债率 | 20-80% | 超出范围需核实数据口径 |
| 净利润增速 | -100% ~ +500% | 超出范围需核实 |
⛔ P0 Critical: 修改数据源时禁止修改数据采集模块结构(2026-05-08用户明确纠正)
用户原话:「数据模版不要修改 只修改数据源」
问题描述: 修改collector.py的数据源时,错误地修改了数据采集模块(collect_summary_data、collect_fundamental_data等)的内部结构,导致reporter_v6.py无法正确读取数据。
必须遵守的规则:
⛔ 禁止:修改collect_xxx_data()方法内部的section字典结构
⛔ 禁止:改变数据写入JSON的key路径(如 sections.1_报告摘要.current_price)
✅ 必须:只修改query_xxx()查询函数和query_with_fallback()降级逻辑
✅ 必须:新增数据源函数(如query_westock_xxx())时,保持返回格式与query_iwencai()一致:{success: bool, datas: [...], query: str}
正确做法:
- 新增数据源查询函数(如
query_westock_kline()) - 修改
query_with_fallback()的降级顺序 - 数据采集模块内部结构完全不动
错误做法:
- 修改
collect_summary_data()中section["current_price"]的赋值逻辑 - 改变
self._add_section()的调用方式 - 重组JSON的section层级结构
⛔ P0 Critical: 行业竞争格局表格列对齐bug(2026-05-11正泰电器发现)
问题描述: 行业竞争格局表格中,同行公司的PE-TTM值被错误地放在了"最新价"列。
根因: peer_detailed数据中有最新价字段,但reporter_v6.py中行业竞争格局部分的代码没有提取该字段。
必须遵守的规则:
⛔ 禁止:表格列数与表头不匹配
✅ 必须:每列数据都对应表头中的字段
✅ 必须:添加新列时同步提取对应字段
修复方法:
ppl = v(pd.get("最新价")) # 最新价
pp = v(pd.get(f"市盈率(pe,ttm)[{actual_date}]")) # PE-TTM
ppb = v(pd.get(f"市净率[{actual_date}]"), "", 2) # PB
pmk = v(pd.get(f"总市值[{actual_date}]"), "", 0) # 市值
w(f"| {pn} | ¥{ppl} | {pp} | {ppb} | ¥{pmk}亿 | - |")
⛔ P0 Critical: 变量作用域导致UnboundLocalError(2026-05-11修复)
问题描述: 多个变量在定义前被使用,导致运行时崩溃:
overseas_pct在"国内宏观"使用但定义在"国际宏观"hny_trend在表格行使用但定义在下一行pe_iv在SWOT劣势使用但定义在估值分析部分
必须遵守的规则:
⛔ 禁止:变量在定义前使用
✅ 必须:高频计算的变量(如overseas_pct)提前到数据加载区域
✅ 必须:表格行中使用的变量(如hny_trend)在该行之前定义
✅ 必须:如果变量在后文才定义,在前文用局部变量从JSON直接提取
1. safe_get 默认参数陷阱
safe_get(data, "a", "b", "c", [{}]) 会把 [{}] 当作第4个key查找,而不是默认值。必须用关键字参数:
# ❌ 错误 — [{}] 被当作 key
safe_get(sections, "1_报告摘要", "current_price", "datas", [{}])
# ✅ 正确 — default 作为关键字参数
safe_get(sections, "1_报告摘要", "current_price", "datas", default=[{}])
2. 问财API字段名不统一
不同技能返回的同类数据字段名可能不同:
| 数据 | 字段名1 | 字段名2 |
|---|---|---|
| 股东名称 | 股东名称 | 大股东名称 |
| 持股比例 | 持股占流通股比例[YYYYMMDD] | 持股比例[YYYYMMDD] |
| 行业分类 | 所属同花顺行业 | 所属同花顺二级行业 |
解决方案: 用 get_field(item, "字段1", "字段2", default="N/A") 做多字段回退。
3. hithink-sector-selector 的双重用途
hithink-sector-selector 可以同时查询:
- 行业估值(PE/PB分位点):
"{行业} 行业PE 行业PB 估值分位" - 资金流向(主力/大单):
"{股票} 主力资金净流入 资金流向" - 北向资金:
"{行业} 北向资金 净买入"
4. news-search API 端点不同
新闻搜索使用 /v1/comprehensive/search,不是 /v1/query2data。请求体结构也不同:
# 数据查询(其他技能)
{"query": "...", "page": "1", "limit": "10"}
# 新闻搜索(news-search)
{"channels": ["news"], "app_id": "AIME_SKILL", "query": "..."}
5. QQ Bot附件文件位置(2026-05-04验证)
QQ Bot会自动下载用户发送的附件到本地:
- 路径:
~/.hermes/cache/documents/ - 文件名格式:
doc_{uuid12}_{原始文件名}(如doc_17de7c238669_通富微电.md) - 查找命令:
find ~/.hermes/cache/documents/ -name "*.md" -mmin -30
注意:不要在 /tmp 或其他位置查找,QQ Bot附件固定存储在上述路径。
6. mx-finance-data数据解读陷阱
mx-finance-data返回的xlsx数据中:
- 股价可能是除权除息价,不是当前市价
- 财务数据可能是合并报表或母公司报表,需注意口径
- 字段名包含日期后缀(如
收盘价[20260430]),表示该日期的数据
建议:始终用 最新价 字段获取当前股价,不要用历史日期字段。
9. company_overview字段可能是Python列表(2026-05-08紫金矿业发现)
问题: company_overview 中的 主营产品 字段返回的是Python列表 ['产品A', '产品B', ...],直接输出会显示为 ['产品A', '产品B'] 格式。
解决方案:
products = co.get('主营产品', [])
if isinstance(products, list):
products_str = '、'.join(products)
else:
products_str = products
10. 营收结构必须包含营业收入金额+毛利率(2026-05-08用户明确要求)
用户原话: 「主营业务销售占比部分必须同时包含营业收入金额和毛利率,当前报告只有利润率(毛利率)没有营业收入」
正确格式:
| 业务板块 | 营业收入(亿) | 收入占比 | 毛利率 | 利润占比 |
|---------|-------------|---------|--------|---------|
| 产品A | 123.45 | 45.2% | 33.9% | 50.1% |
错误格式(缺少营业收入):
| 业务板块 | 毛利率 | 利润占比 |
|---------|--------|---------|
8. weasyprint PDF中文乱码(2026-05-07紫金矿业事故)
问题描述: 生成的PDF在IMA客户端显示为□□□□方块乱码,中文全部无法识别。
根因分析:
- 系统未安装CJK中文字体,weasyprint无法渲染中文
ima_integration.pyCSS中font-family首选SimSun(Windows字体),Linux上不存在- 即使安装了字体,字体名拼写或顺序错误也会导致fallback失败
必须遵守的规则:
✅ 必须:系统安装 fonts-noto-cjk 和 fonts-wqy-microhei
✅ 必须:ima_integration.py CSS中 font-family 以 "Noto Sans CJK SC" 开头
✅ 必须:安装字体后执行 fc-cache -f 刷新字体缓存
⛔ 禁止:CSS中首选 SimSun/SimHei 等Windows专有字体
修复方法:
# 1. 安装CJK字体
apt-get install -y fonts-noto-cjk fonts-wqy-microhei
# 2. 刷新字体缓存
fc-cache -f
# 3. 验证字体可用
fc-list :lang=zh | head -3
ima_integration.py CSS正确配置:
body { font-family: "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif; }
验证方法: 生成PDF后用 pdftotext 提取文本,确认包含中文字符。或直接在IMA客户端预览确认无乱码。
7. sf()安全浮点转换 + f-string中float("N/A")崩溃(2026-05-08紫金矿业事故)
问题描述: reporter_v6.py在f-string中使用 float(ps or 0) 做比较,当 ps="N/A" 时,"N/A" 是truthy字符串,or 0 不生效,float("N/A") 抛出ValueError崩溃。
根因: Python中 "N/A" or 0 返回 "N/A"(非空字符串为truthy),不是0。
必须遵守的规则:
⛔ 禁止:在f-string中直接写 float(var or 0) — 当var="N/A"时会崩溃
✅ 必须:使用 sf() 安全转换函数
sf()函数定义(reporter_v6.py已内置):
def sf(val, default=0.0):
"""安全浮点转换,N/A/None/空字符串返回default"""
if val is None or val == "N/A" or val == "":
return default
try:
return float(str(val).replace('%', '').replace(',', ''))
except (ValueError, TypeError):
return default
用法:
# ❌ 错误 — var="N/A"时崩溃
f"{'偏高' if float(ps or 0) > 3 else '合理'}"
# ✅ 正确 — sf()安全处理N/A
f"{'偏高' if sf(ps) > 3 else '合理'}"
使用流程(v10 - 最终版)
generate_report.py v10 自动执行(3步):
Step 1: collector.py v7 采集全部数据(13模块+3补充模块,~60秒)
Step 2: reporter_v6.py v8.2 从JSON生成固定格式MD报告
Step 3: ima_integration.py v2 转PDF上传IMA
一键执行:
python3 ~/.hermes/scripts/stock-research/generate_report.py -c 601899 -n 紫金矿业
collector.py v7 已内置全部补充查询,无需手动调用mx-finance-data reporter_v6.py v8.2 保证相同JSON输入=相同MD输出 Agent不再手写报告,完全由脚本生成,消除人为差异
妙想技能集成(v3新增)
已安装14个妙想金融技能(路径:~/.hermes/skills/miaoxiang/),可补充以下数据:
# 技术面数据(K线、MACD、RSI、KDJ)
export EM_API_KEY="em_5BXZUDwGSFOli2ITXe0b4WhHjOsZMJSo"
python3 ~/.hermes/skills/miaoxiang/mx-finance-data/scripts/get_data.py --query "贵州茅台 近20日K线数据 MACD RSI KDJ"
# 历史估值区间
python3 ~/.hermes/skills/miaoxiang/mx-finance-data/scripts/get_data.py --query "贵州茅台 近5年市盈率PE最高最低平均"
# 宏观数据
python3 ~/.hermes/skills/miaoxiang/mx-macro-data/scripts/get_data.py --query "中国GDP增速 近5年"
# 金融资讯
python3 ~/.hermes/skills/miaoxiang/mx-finance-search/scripts/get_data.py "贵州茅台 最新研报与公告"
完整配置见:~/.hermes/skills/miaoxiang/CONFIG.md
报告模版 (v8 - 专业机构级)
基于三花智控(002050)、三安光电(600703)、卧龙电驱(600580) 三份报告合并确立的标准模板v8。详见
references/merged-report-template.md
用户提供的标准研究报告模版包含以下完整框架:
核心投资逻辑部分必须包含:
📊 股价与估值概览
- 最新股价、总市值、PE-TTM、PB、股息率
📈 最新季度财务数据
- 营业收入(及同比增长)
- 归母净利润(及同比增长)
- 扣非净利润
- 毛利率(对比行业平均)
- 净利率(对比行业平均)
- ROE(Q1)
- 资产负债率
📅 季度财务数据明细
- 最近8个季度的营收/净利润/扣非净利润表格
📊 近三年全年财务数据
- 最近三年的全年营收/净利润/扣非净利润
- 营收趋势分析
🏭 行业平均指标对比
- 毛利率 vs 行业平均
- 净利率 vs 行业平均
- ROE(Q1) 评估
- 资产负债率评估
💡 核心投资逻辑总结
- 盈利能力分析
- 成长性分析
- 财务健康分析
- 股东回报分析
- 估值水平分析
完整报告框架:
一、报告摘要(Executive Summary)
- 核心投资逻辑(Key Investment Thesis)- 包含上述所有指标
- 核心风险提示(Key Risk Factors)
- 目标价位与周期(Target Price & Horizon)
- 目标投资者画像(Target Investor Profile)
二、深度分析(In-Depth Analysis)
1. 宏观环境与行业分析(国内和国际分开)
2. 公司基本面分析
- 公司概况与商业模式
- 财务健康状况(盈利/营运/偿债/成长/现金流)
- 公司治理与股东情况
- 机构持仓与市场情绪
3. 估值分析(绝对估值+相对估值)
4. 技术面分析(日线/周线/趋势/形态/指标/量价)
5. 风险与机会综合评估
三、明确的投资建议与操作策略
- 入场策略/仓位建议/止损策略/目标价位
数据来源与时效性说明
实战验证记录
测试股票:贵州茅台(600519)
- 采集时间:2026-05-04
- 查询成功率:36/36(100%)
- 数据覆盖:9大模块全部成功
测试股票:通富微电(002156)
- 采集时间:2026-05-04
- 使用技能:mx-finance-data + mx-macro-data + mx-finance-search
- 报告输出:完整研究报告(含财务/宏观/行业/技术面/资金流向/机构评级/新闻)
- 数据覆盖率:100%
已验证的mx-finance-data查询语句(补充数据用)
以下查询仅在需要更详细数据时使用,collector.py已覆盖大部分基础数据。
# 基础财务数据(补充详细K线)
--query "通富微电 002156 最新股价 市盈率 市净率 营业收入 净利润 毛利率 ROE"
# 详细K线数据(20日)
--query "通富微电 002156 近20日K线 MACD RSI KDJ"
# 历史估值详细
--query "通富微电 002156 近5年市盈率PE最高最低平均"
collector.py 新增模块(13模块全覆盖 - 2026-05-06)
collector.py直接集成13个模块的数据采集,无需额外手动调用mx-finance-data:
# 模块10:技术面分析(新增)
section["technical_indicators"] = query_iwencai("market",
f"{self.stock_name} RSI MACD KDJ 布林带", limit="1")
section["support_resistance"] = query_iwencai("market",
f"{self.stock_name} 支撑位 压力位", limit="1")
section["kline_20d"] = query_iwencai("market",
f"{self.stock_name} 近20日K线 成交量 成交额", limit="20")
# 模块11:营收结构与成本分析(新增)
section["revenue_by_product"] = query_iwencai("business",
f"{self.stock_name} 按产品营收 收入构成 毛利率", limit="10")
section["revenue_by_region"] = query_iwencai("business",
f"{self.stock_name} 按地区营收 国内国外收入", limit="5")
section["rd_investment"] = query_iwencai("finance",
f"{self.stock_name} 研发费用 研发投入占比 专利", limit="5")
section["capacity"] = query_iwencai("business",
f"{self.stock_name} 产能 产量 利用率 扩产", limit="5")
# 模块12:杜邦分析与盈利质量(新增)
section["dupont"] = query_iwencai("finance",
f"{self.stock_name} ROE 净利率 总资产周转率 权益乘数", limit="1")
section["earnings_quality"] = query_iwencai("finance",
f"{self.stock_name} 扣非净利润 非经常性损益 经营现金流净利润比", limit="1")
section["growth_trend"] = query_iwencai("finance",
f"{self.stock_name} 近三年营收增速 净利润增速 ROE变化", limit="3")
# 模块13:历史估值与同行对比(新增)
section["pe_history_5y"] = query_iwencai("finance",
f"{self.stock_name} 近5年市盈率PE最高最低平均", limit="5")
section["pb_history_5y"] = query_iwencai("finance",
f"{self.stock_name} 近5年市净率PB最高最低", limit="5")
section["peer_detailed"] = query_iwencai("finance",
f"{self.stock_name} 同行业对比 PE PB 市值 营收 净利润", limit="10")
注意:需要在SKILLS配置中添加 market 技能类型(hithink-market-query)。
已验证的mx-macro-data查询语句
--query "中国GDP增速 近5年"
--query "中国GDP增速 CPI"
--query "中国CPI 近3年"
已验证的mx-finance-search查询语句
"通富微电 最新研报与公告"
"通富微电 002156 最新公告研报"
"贵州茅台 最新研报与公告"
已验证的mx-stocks-screener查询语句
--query "股价大于100元,主力流入" --select-type A股
--query "白酒主题基金" --select-type 基金
已验证的mx-financial-assistant查询语句
# 标准模式
--query "用户问题"
# 深度思考模式
--query "用户问题" --deep-think
关键发现与经验
1. v10架构:collector.py内置全部补充
collector.py v7 已将所有补充查询直接写入,无需外部补充脚本。generate_report.py v10 只是薄编排层。
2. 零N/A原则
报告中不允许出现任何N/A值。collector.py v7 通过内置补充查询确保数据完整。生成后必须 grep "N/A" 验证。
3. 问财API限流
连续大量查询后问财API可能返回401。collector.py v7 的运营效率查询有妙想API自动备选。
4. 字段名不一致
不同API返回的字段名可能不同(如 市销率[20260506] vs 市销率[20260507])。reporter_v6.py v8.2 使用多字段回退处理。
5. sf()安全浮点转换
f-string中 float("N/A" or 0) 会崩溃。reporter_v6.py v8.2 内置 sf() 函数处理所有N/A安全转换。
报告对比与完善工作流
当用户提供外部报告(来自其他AI工具)要求完善系统报告时,使用以下流程:
步骤
- 定位外部报告文件:检查
~/.hermes/cache/documents/目录(QQ Bot附件自动下载位置)- 文件名格式:
doc_{uuid12}_{原始文件名} - 用
find ~/.hermes/cache/documents/ -name "*.md" -mmin -30查找最近的文件
- 文件名格式:
- 读取两份报告:系统旧报告 + 外部新报告
- 生成差异分析:逐章节对比,列出新报告独有的数据/观点/分析
- 修正错误数据:特别注意股价、市值、资产负债率等核心数据
- 整合完善:将新报告的有价值信息整合到旧报告中,生成V2版本
- 输出:保存到
output/<股票名称>_深度研究报告_v2.md
差异分析关注点
- 数据修正:股价、市值、利润率、负债率等核心指标是否一致
- 信息增量:目标价、PEG、国际竞争格局、股东变动、催化剂时间窗口
- 分析深度:护城河分析、盈利模式拆分、技术面具体点位
- 保留优势:旧报告中更详细的表格、数据来源验证等
数据验证要点
⚠️ 报告可能出现数据错误,必须与最新数据交叉验证:
- 股价:使用 mx-finance-data 查询最新价
- 财务数据:核对最新季报/年报
- 估值指标:PE/PB/PEG 需要与同行对比验证
- 验证方法:检查output目录是否有JSON数据文件,确保数据来源可靠
技能打包与发布到GitHub
当需要将股票研究功能作为独立技能发布时,使用以下流程:
打包结构
hermes-stock-research/
├── SKILL.md # Hermes技能说明文档
├── README.md # GitHub项目说明
├── LICENSE # MIT License
├── .gitignore # 忽略output/*.json等敏感数据
├── requirements.txt # Python依赖
├── scripts/
│ ├── collector.py # 数据采集脚本(13模块)
│ └── ima_integration.py # IMA上传脚本
├── examples/
│ └── <股票名称>_深度研究报告.md # 示例报告
└── output/
└── .gitkeep # 输出目录占位
发布步骤
# 1. 创建目录并复制文件
mkdir -p /tmp/hermes-stock-research/{scripts,examples,output}
cp /root/.hermes/scripts/stock-research/{collector.py,ima_integration.py} /tmp/hermes-stock-research/scripts/
cp /root/.hermes/scripts/stock-research/output/*_深度研究报告.md /tmp/hermes-stock-research/examples/
touch /tmp/hermes-stock-research/output/.gitkeep
# 2. 创建SKILL.md、README.md、LICENSE、.gitignore、requirements.txt
# 3. 初始化git并推送
cd /tmp/hermes-stock-research
git init && git branch -m main
git add -A && git commit -m "feat: 初始化Hermes股票深度研究技能"
gh repo create hermes-stock-research --public --source . --push
# 4. 添加标签(可选)
gh repo edit imeiming/hermes-stock-research --add-topic "stock,finance,python,iwencai"
SKILL.md 格式要求
- 必须以
---开头(无前导空行) - 必须包含
name和description字段(description ≤ 1024字符) - 推荐包含
version、author、license、metadata.hermes.tags - body部分非空
注意事项
output/*.json包含API返回的原始数据,应加入.gitignore- 示例报告应选择数据完整的报告,展示报告质量
- 如有敏感API Key,不要硬编码,使用环境变量说明
IMA知识库集成 (v2 - PDF文件上传)
更新于 2026-05-07:从笔记上传改为PDF文件上传,本地.md文件生成PDF后直接以文件形式上传到知识库
生成报告后,自动转为PDF并上传到IMA知识库「行业公司报告」文件夹。
上传流程
生成报告(MD) → weasyprint转PDF → COS上传 → IMA知识库 → 删除本地文件
ima_integration.py v2 功能
| 功能 | 说明 |
|---|---|
| MD→PDF转换 | 使用weasyprint生成专业排版PDF |
| Emoji清理 | 自动将emoji替换为纯文本标记([OK]/[!]/[X]),防止PDF乱码 |
| 重名检测 | 自动检测同名文件,添加时间戳 |
| COS上传 | 通过IMA临时凭证上传到COS |
| 添加知识库 | 自动添加到「行业公司报告」文件夹 |
| 删除本地文件 | 上传成功后自动删除.md和.pdf |
使用方式
python3 /root/.hermes/scripts/stock-research/ima_integration.py \
--report-path output/紫金矿业_深度研究报告.md \
--stock-name 紫金矿业 \
--stock-code 601899
系统依赖(必须安装)
# 中文字体(weasyprint渲染中文必须)
apt-get install -y fonts-noto-cjk fonts-wqy-microhei
# Python依赖
pip install weasyprint markdown
⚠️ 系统默认没有中文字体,不安装会导致PDF全部显示为□□乱码
Emoji处理规则
weasyprint不支持彩色emoji渲染,会导致PDF显示为⊠框框。ima_integration.py会自动将emoji替换为纯文本:
| 原始emoji | 替换为 | 说明 |
|---|---|---|
| ✅ | [OK] | 成功/通过 |
| ⚠️ | [!] | 警告/风险 |
| ❌ | [X] | 失败/不适合 |
| ⭐ 🌟 | * | 星级 |
| 📊📈📅等 | (移除) | 装饰性emoji直接移除 |
IMA知识库集成 (v2 - PDF文件上传)
报告生成后自动转为PDF,以文件形式上传到IMA知识库「行业公司报告」文件夹。
自动化流程
生成报告(MD) → weasyprint转PDF → COS上传 → IMA知识库 → 删除本地文件
ima_integration.py v2 关键参数
# 目标知识库
KB_ID = "W80hJmK98SC2GTUlPtnKK6MyKBE75MwMqFBJK8z0wyo="
# 目标文件夹
TARGET_FOLDER_ID = "folder_7403588502444840"
# 上传流程
1. preflight-check.cjs → 检查文件类型
2. check_repeated_names → 检查重名(自动添加时间戳)
3. create_media → 创建媒体,获取COS凭证
4. cos-upload.cjs → 上传PDF到COS
5. add_knowledge → 添加到知识库
⚠️ 已删除旧的笔记上传方式(md_to_ima.py),统一使用PDF文件上传
⛔ 禁止发送文件给用户(用户明确要求)
用户原话:「之前不需要发送文件的 怎么这次发送文件给我了」
生成报告后:
- ✅ 只报告「已上传到IMA知识库」+ 文件名
- ✅ 提供关键数据摘要
- ❌ 不要用 MEDIA: 发送文件给用户
- ❌ 不要用 send_message 发送文件
报告上传到IMA后,本地.md和.pdf文件自动删除(ima_integration.py 默认行为)。
24. reporter_v6.py 硬编码结论与数据矛盾(2026-05-10湖南黄金事故)
问题描述: reporter_v6.py中大量结论文字是硬编码的,不管实际数据如何都输出固定结论。用户发现资金流向数据为负(净流出)但结论写"主力资金净流入,市场看好",引发全面排查。经两轮修复,共修复38处硬编码结论。
第一轮修复(15处)— 数据与结论矛盾:
| # | 位置 | 硬编码内容 | 实际应为 |
|---|---|---|---|
| 1-2 | 资金流向(行业+个股) | "主力资金净流入,市场看好" | 根据数值正负判断净流入/净流出 |
| 3 | ROE判断 | "盈利能力强" | 根据ROE>15/8/0分档 |
| 4 | 估值分析 | "当前PE高于行业均值" | 与行业PE对比后判断 |
| 5 | 成长分析 | "净利润连续高增长" | 根据近三年增速判断 |
| 6 | 偿债分析 | "处于合理水平" | 根据资产负债率分档 |
| 7 | 营运分析 | "处于行业合理水平" | 根据总资产周转率分档 |
| 8 | 现金流分析 | "现金创造能力强" | 根据经营现金流/净利润比值判断 |
| 9 | 法律风险 | "法律风险较低" | 根据涉诉/处罚数量判断 |
| 10 | 评级分布 | "市场看好" | 根据实际评级统计 |
| 11-12 | 营收/净利增速 | "放缓"/"强劲回升" | 根据相邻年份增速趋势判断 |
| 13-15 | 风险提示(3处) | "营收增速放缓" | 根据实际增速>20/0/<0分档 |
第二轮修复(23处)— 通用模板文字与公司实际不符:
| # | 位置 | 硬编码内容 | 问题 |
|---|---|---|---|
| 1 | 核心驱动因素 | "全球化布局/并购整合/行业景气" | 不是所有公司都有全球化布局和并购 |
| 2 | 国内宏观环境 | "产业升级/国产替代" | 通用文字,不反映行业特性 |
| 3 | 国际宏观环境 | "海外产能布局成效显现" | 湖南黄金海外收入仅0.39% |
| 4 | 行业驱动因素 | "国产替代加速/需求旺盛" | 贵金属行业驱动是金价+资源 |
| 5 | 竞争格局 | 硬编码"行业龙头" | 不是所有公司都是龙头 |
| 6 | 公司概况 | "全球布局:中国、海外多国" | 应从实际地区数据提取 |
| 7 | 历史沿革 | "外延式并购扩张" | 应反映公司真实历史 |
| 8 | 营收结构结论 | "核心业务是收入主要来源" | 应根据实际占比描述 |
| 9 | 竞争格局总结 | "技术优势和规模效应" | 应根据市值/地位判断 |
| 10 | 产业链地位 | "行业龙头,覆盖全产业链" | 应根据实际业务描述 |
| 11 | SWOT优势 | 5条通用模板 | 应根据实际财务数据生成 |
| 12 | SWOT机会 | "行业景气度/产业升级" | 应反映行业真实驱动 |
| 13 | 机构认可度 | "认可度高" | 应根据持股比例判断 |
| 14 | 行业周期 | "部分领域具有成长属性" | 应反映行业真实周期特征 |
| 15 | 趋势判断 | "趋势向好/长期看好" | 应根据RSI/涨跌幅判断 |
| 16 | 情景分析 | "行业景气超预期" | 应用公司具体假设 |
| 17 | 催化剂 | "新产品/海外客户" | 应用公司具体催化剂 |
| 18 | 投资逻辑 | "行业龙头+全球化+并购" | 应反映公司真实竞争力 |
| 19 | 风险矩阵 | "行业竞争加剧" | 应用公司具体风险 |
| 20 | 目标投资者 | "看好行业发展趋势" | 应反映公司具体特征 |
| 21 | 风险应对 | "等待PE回调/分散投资" | 应根据当前数据动态生成 |
| 22 | 估值消化 | "高于/接近行业均值" | 应根据PE/行业PE比值判断 |
| 23 | 行业规模 | "新兴应用领域需求旺盛" | 应反映行业真实情况 |
必须遵守的规则:
⛔ 禁止:reporter_v6.py中使用硬编码结论文字
⛔ 禁止:使用通用模板文字(如"全球化布局""并购整合""行业龙头")
✅ 必须:所有结论性文字根据实际数据动态生成
✅ 必须:数值型结论用条件判断(if sf(x) > threshold)
✅ 必须:趋势型结论用相邻数据对比(如增速加速/放缓)
✅ 必须:分类统计型结论用计数(如评级:买入count vs 卖出count)
✅ 必须:公司描述从实际数据提取(主营产品、地区收入、市值排名等)
验证方法(必须执行): 生成报告后,执行以下检查:
# 1. 检查是否有硬编码通用文字残留
grep -c "全球化布局\|并购整合\|外延式扩张\|国产替代\|行业龙头\|协同效应\|海外产能占比高" report.md
# 期望结果:0
# 2. 检查📌结论是否与数据一致
grep '📌' report.md
# 逐条检查:资金流向净流入/净流出是否与数值正负匹配、估值与行业均值对比是否准确
# 3. 检查是否有"待确认"或N/A
grep -c "待确认\|N/A" report.md
# 期望结果:0
详细修复清单: 见 references/reporter-hardcoded-conclusion-fixes.md
22. reporter_v6.py pe_iv N/A 崩溃(2026-05-08湖南黄金事故)
问题描述: reporter_v6.py 在估值消化测算中使用 float(pe_iv or 20) 格式化字符串,当 pe_iv="N/A" 时,"N/A" 是truthy字符串,or 20 不生效,float("N/A") 抛出 ValueError 崩溃。
根因: Python中 "N/A" or 20 返回 "N/A"(非空字符串为truthy),不是20。
修复方法(已应用到reporter_v6.py v8.3):
# ❌ 原代码(崩溃)
w("- 若PE回归至合理区间({:.0f}-{:.0f}倍)".format(float(pe_iv or 20), float(pe_iv or 30) * 1.2))
# ✅ 修复后
pe_iv_val = 20 if pe_iv == 'N/A' or not pe_iv else float(pe_iv)
w(f"- 若PE回归至合理区间({pe_iv_val:.0f}-{pe_iv_val * 1.2:.0f}倍)")
必须遵守的规则:
⛔ 禁止:在f-string/格式化中直接写 float(var or default) — 当var="N/A"时会崩溃
✅ 必须:先检查 var == 'N/A' 或 not var,再转换为float
✅ 必须:或使用 sf() 安全转换函数
19. 妙想API数据格式导致reporter_v6.py崩溃(2026-05-08洛阳钼业事故)
问题描述: 妙想API返回的Excel数据带有单位后缀(如"113.3亿元"、"22.88%"),直接写入JSON后reporter_v6.py在f-string中对这些字符串做数学运算时崩溃。
报错示例:
ValueError: could not convert string to float: '113.3亿元'
ValueError: Unknown format code 'f' for object of type 'str'
必须遵守的规则:
⛔ 禁止:直接将妙想API返回的带单位字符串写入JSON
✅ 必须:写入JSON前用clean_number()去掉单位后缀,转换为float/int
✅ 必须:clean_number()处理 '亿元'、'%'、'次'、'倍'、',' 等后缀
clean_number()实现:
def clean_number(value):
if value == 'N/A' or value is None:
return None
s = str(value)
s = re.sub(r'[亿元次倍%]', '', s)
s = s.replace(',', '')
try:
num = float(s)
return int(num) if num == int(num) else num
except:
return None
验证方法: JSON生成后执行 grep -c '"N/A"' output/*.json 检查N/A数量,确认数值字段类型正确。
20. 妙想API字段名与reporter_v6.py期望不一致(2026-05-08洛阳钼业事故)
问题描述: 妙想API返回的字段名与reporter_v6.py中硬编码的字段名不一致,导致大量N/A。这是手动补充数据时最耗时的问题(20+轮patching)。
字段名映射表(已验证):
| reporter_v6.py期望 | 妙想API实际返回 | 影响模块 |
|---|---|---|
市盈率(pe,ttm)[20260507] | 市盈率PE(TTM) | current_price |
销售净利率[20260331] | 净利润/营业总收入 | fundamentals_snapshot |
净资产收益率[20260331] | 净资产收益率ROE | dupont |
扣非归母净利润[YYYYMMDD] | 扣非净利润 / 扣除非经常性损益后归属于母公司股东的净利润 | quarterly_cumulative |
归母净利润同比增长率 | 净利润同比 | financial_history |
营业收入同比增长率 | 营收同比 | financial_history |
经营活动产生的现金流量净额[20260331] | 经营现金流 | earnings_quality |
研发支出[20260331] / 营业收入[20260331] | 研发费用占比 | rd_investment |
加权净资产收益率[20260331] | 净资产收益率ROE(加权) | fundamentals_snapshot |
必须遵守的规则:
⛔ 禁止:假设妙想API返回的字段名与reporter_v6.py一致
✅ 必须:写入JSON前将妙想API字段名重命名为reporter_v6.py期望的格式
✅ 必须:参考上方映射表进行字段名转换
21. 妙想API与问财API同时限流的应急方案(2026-05-08发现,2026-05-08更新)
问题描述: 两个API可能同时达到使用上限:
- 问财API:返回
HTTP Error 401: Unauthorized - 妙想API:返回
code=403, message=使用次数已达上限 - 东方财富直接API:返回
RemoteDisconnected连接被拒
应急方案(按优先级):
✅ 方案1:等待API配额重置(通常24小时)
✅ 方案2:使用之前已成功采集的JSON数据(如已有同股票的历史数据)
✅ 方案3:使用generate_report.py的--skip-collect参数,跳过采集直接用现有JSON生成报告
✅ 方案4:紧急查询股价等基础信息时,使用Tavily搜索API作为最后手段
方案4 - Tavily紧急查询(2026-05-08验证有效):
import requests
url = 'https://api.tavily.com/search'
data = {
'api_key': os.environ.get("TAVILY_API_KEY", ""),
'query': '通富微电 002156 今日股价 最新价格',
'search_depth': 'basic',
'max_results': 3
}
resp = requests.post(url, json=data, timeout=15)
# 返回结果包含最新价格信息(来自搜索引擎索引)
验证方法: 运行collector.py后检查输出摘要,如果成功查询数<20/38,说明API可能限流。
⛔ 旧脚本已删除
当前唯一文件(v10):
generate_report.pyv10 — 一键编排(3步:采集→生成→上传)collector.pyv7 — 数据采集(13模块+3补充模块,全部内置)reporter_v6.pyv8.2 — 报告生成(JSON→固定格式MD,含sf()+季度计算)ima_integration.pyv2 — IMA上传(MD→PDF→COS→知识库)
禁止使用:
⛔ reporter.py — 已删除
⛔ reporter_v4.py — 已删除
⛔ md_to_ima.py — 已删除
⛔ initiation-of-coverage-or-deep-dive — 禁止用于用户报告请求
✅ 唯一入口:generate_report.py v10(自动处理全流程)
参考文件
references/merged-report-template.md- v8模板(基于三花智控+三安光电+卧龙电驱对比确立)references/v9-data-supplementation.md- v9数据补充策略(季度历史/运营效率/现金流/历史估值)references/ima-api-integration.md- IMA API集成说明references/operational-metrics-401-issue.md- 问财API运营效率指标401问题references/data-quality-incident-20260504.md- 数据质量事故记录references/westock-data-integration.md- westock-data数据源集成说明(v8新增)references/westock-json-restructuring.md- iwencai限流时westock-data JSON重构方案references/reporter-v6-date-fix-20260509.md- reporter_v6.py硬编码日期修复记录(v8.4新增)
⛔ 报告完整性强制要求(用户明确要求)
用户原话:「你可以在我原有的模版上增加数据和模块,禁止删除和省略」
完整报告框架:
一、报告摘要(Executive Summary)
✅ 核心投资逻辑(Key Investment Thesis)- 含完整财务指标表格
✅ 核心驱动因素(3-5个关键点)
✅ 核心风险提示(Key Risk Factors)- 具体风险+概率+影响
✅ 目标价位与周期(Target Price & Horizon)- 含机构评级表
✅ 目标投资者画像
二、深度分析(In-Depth Analysis)
✅ 1. 宏观环境与行业分析
- 国内宏观环境(GDP、CPI表格)
- 国际宏观环境
- 行业基本信息
- 行业估值水平(含分位点)
- 行业资金流向
- 行业竞争格局(同行对比表格)
- 产业链地位(上游/中游/下游+议价能力)
- 【新增】市场规模与增长(全球/中国市场规模、增速、预测)
- 【新增】行业周期分析(周期特征、当前阶段)
- 【新增】行业驱动因素(政策、技术、需求)
✅ 2. 公司基本面分析
- 公司概况与商业模式
- 【新增】历史沿革与发展里程碑
- 营收结构分析(按产品/地区分类)
- 财务健康状况深度剖析
- 盈利能力(表格)
- 成长能力(近三年对比表格)
- 偿债能力(表格)
- 营运能力(表格)
- 现金流量(表格)
- 【新增】杜邦分析(ROE分解)
- 【新增】盈利质量分析(非经常性损益、应收款质量)
- 公司治理与股东情况
- 实际控制人
- 【新增】董事长/法人代表信息
- 前十大股东(表格)
- 【新增】控股股东减持动态(近6个月减持记录)
- 【新增】股权质押情况(质押比例、质押风险)
- 机构持仓
- 【新增】法律风险与负面消息
- 债务纠纷(诉讼、仲裁)
- 监管处罚(证监会、交易所)
- 信息披露违规
- 关联交易风险
- 其他负面舆情
- 【新增】管理层分析(核心高管背景、激励计划)
- 【新增】产能布局(各基地产能、利用率、扩产计划)
- 【新增】产品结构(各产品线毛利率、高端产品占比)
- 【新增】成本结构(原材料/能源/人工成本占比)
- 【新增】研发投入(研发费用、专利、技术优势)
✅ 3. 竞争优势分析(SWOT分析)
- 优势(Strengths)
- 劣势(Weaknesses)
- 机会(Opportunities)
- 威胁(Threats)
- 核心竞争壁垒
✅ 4. 估值分析
- 当前估值水平(含行业平均对比)
- 历史估值区间(近5年PE表格)
- 同行可比公司对比(表格)
- 【新增】国际对标(与国际巨头估值对比)
- 【新增】分部估值(按业务板块分别估值)
- 【新增】绝对估值(DCF模型简述)
- 估值结论
✅ 5. 技术面分析
- 关键技术指标(RSI/KDJ/布林带表格)
- 趋势判断(短/中/长期)
- 支撑与阻力
✅ 6. 资金流向分析
- 主力资金动向
✅ 7. 风险与机会综合评估
- 风险矩阵(概率+影响表格)
- 【新增】情景分析(乐观/中性/悲观)
- 潜在催化剂(含时间窗口)
- 【新增】风险应对策略
### 8. 新闻资讯
- 公司最新动态
### 9. 报告质量一致性检查(2026-05-07 正泰vs紫金对比发现)
**问题描述:** 同一流程生成的两份报告,紫金矿业(6266字)比正泰电器(7854字)少1588字,且缺失8个子模块。
**缺失模块清单(紫金矿业报告):**
- 盈利质量分析、控股股东减持动态、股权质押情况
- 产能布局、产品结构、成本结构、机构持仓与市场情绪、估值消化测算
**根本原因:** Agent生成报告时因上下文长度或数据量大,省略了部分子模块。
**必须遵守的规则:**
⛔ 禁止:报告字数<7000字(v6模板最低标准) ✅ 必须:生成报告后执行子模块完整性检查(见下方清单) ✅ 必须:公司基本面分析必须包含全部8个子模块 ✅ 必须:用户明确要求「每次生成报告请自动核对是否是13个模块」
**公司基本面分析 - 必须包含的子模块(缺一不可):**
1. 公司概况与商业模式
2. 历史沿革与发展里程碑
3. 营收结构分析(按产品/地区)
4. 财务健康状况(盈利/成长/偿债/营运/现金流/杜邦/盈利质量)
5. 公司治理与股东(实控人/董事长/前十大股东/减持动态/质押情况)
6. 法律风险与负面消息
7. 管理层分析 + 产能布局 + 产品结构 + 成本结构 + 研发投入
8. 机构持仓与市场情绪
**估值分析 - 必须包含:** 当前估值、历史估值区间、同行对比、估值消化测算、估值结论
**报告生成后自动核对清单(13个模块):**
| # | 模块 | 关键子模块 |
|---|------|-----------|
| 1 | 报告摘要 | 股价概览、季度财务、近三年、行业对比、投资逻辑5维度、驱动因素、风险提示、目标价位、投资者画像 |
| 2 | 宏观与行业 | 国内/国际宏观、行业估值、资金流向、竞争格局同行对比表、产业链地位 |
| 3 | 公司基本面 | 概况、历史沿革、营收结构(产品/地区)、财务健康(7项)、公司治理(5项)、法律风险、产能、产品结构、成本结构、研发投入、机构持仓 |
| 4 | SWOT分析 | 优势、劣势、机会、威胁、核心壁垒 |
| 5 | 估值分析 | 当前估值、历史区间、同行对比、估值消化、结论 |
| 6 | 技术面 | RSI/KDJ/MACD/布林带、趋势判断、支撑阻力 |
| 7 | 资金流向 | 主力/大单/特大单 |
| 8 | 风险与机会 | 风险矩阵、情景分析、催化剂、应对策略 |
| 9 | 新闻资讯 | 公司最新动态 |
| 10 | 财务预测 | 盈利预测(2026-2028)、估值推导、敏感性分析 |
| 11 | 投资建议 | 评级、逻辑总结、操作策略、监测指标、退出策略 |
| 12 | 数据来源 | 来源表、免责声明 |
| 13 | 附录 | 可比公司、假设说明、数据明细 |
### 10. delegate_task 生成报告超时(2026-05-07发现)
**问题描述:** 使用delegate_task让子Agent生成完整v6报告时,600秒超时仍未完成。
**根因:** 完整v6报告(13模块,≥10000字)生成耗时远超600秒。
**解决方案:**
✅ 分段生成:将报告拆分为3-4个独立任务分别生成,最后合并
- 任务1:报告摘要 + 宏观行业 + 公司基本面(含SWOT)
- 任务2:估值分析 + 技术面 + 资金流向 + 风险评估 + 新闻
- 任务3:财务预测 + 投资建议 + 数据来源 + 附录 ✅ 或直接在主Agent上下文中生成(不使用delegate_task) ⛔ 不要将完整13模块报告委托给单个delegate_task
三、财务预测与估值模型
✅ 【新增】盈利预测(2026-2028年)
- 营业收入预测
- 净利润预测
- EPS预测
✅ 【新增】估值推导
- PE估值区间
- 目标价计算
✅ 【新增】敏感性分析
- 关键假设变化对估值的影响
四、明确的投资建议与操作策略
✅ 投资评级
✅ 投资逻辑总结
✅ 操作策略
- 入场策略(含具体价格区间)
- 仓位建议(具体配置比例)
- 止损策略
- 目标价位(短/中/长期)
✅ 【新增】监控指标(需定期跟踪的关键指标清单)
✅ 【新增】退出策略
数据来源与时效性
数据获取完整性验证表格
【新增】附录
- 可比公司列表
- 关键假设说明
- 数据来源明细
三数据源策略(v11 collector.py v8内置全部补充)
collector.py v8 已内置全部补充查询,无需手动调用任何技能。
collector.py v8 数据源优先级
| 优先级 | 数据源 | 特点 | 适用场景 |
|---|---|---|---|
| 🥇 主 | westock-data(腾讯自选股) | 免费无限制 | K线、财务报表、公司概况、股东、分红、资金流向、技术指标 |
| 🥈 辅 | 妙想API(东方财富) | 有使用限制 | 行业对比、历史PE区间、运营效率(问财401时备选) |
| 🥉 补 | 问财API(同花顺) | 有频率限制 | 行业数据、机构研究、新闻资讯 |
| 补充数据 | 采集方式 | 失败时备选 |
|---|---|---|
| 历史季度累计数据 | 问财API分年查询 | 无(必须有) |
| 运营效率(周转率) | 问财API优先 | 自动切mx-finance-data |
| 现金流(经营/自由) | 问财API优先 | 自动切mx-finance-data |
| 估值字段(PS/股息率/同比) | 问财API | 无 |
| 行业平均PE/PB | 问财行业查询 | 无 |
| 历史PE详细(5年) | mx-finance-data | 无 |
数据源分工(已固化到collector.py v7)
| 数据类型 | 采集方 | 说明 |
|---|---|---|
| 基础财务/估值/股东 | collector.py 基础模块 | 问财API |
| 技术面/资金流向 | collector.py 基础模块 | 问财API |
| 新闻/研报 | collector.py 基础模块 | 问财API |
| 运营效率+现金流 | collector.py 补充模块 | 问财优先→妙想备选 |
| 历史季度数据 | collector.py 补充模块 | 问财API分年查询 |
| 历史PE区间 | collector.py 补充模块 | 妙想API |
| 行业平均PE/PB | collector.py 补充模块 | 问财行业查询 |
⚠️ collector.py v7 已内置的补充查询(2026-05-08永久固定)
以下数据已由 collector.py v7 自动采集,无需手动调用:
# 以下查询已内置到 collector.py v7 的补充模块中:
# 1. 历史季度累计数据(2024/2025年)→ 自动计算单季度
# 2. 运营效率(应收账款/存货/总资产周转率)→ 问财401时自动切妙想API
# 3. 现金流(经营现金流/企业自由现金流)→ 同上
# 4. 估值字段(市销率/股息率/营收同比/净利同比/加权ROE)
# 5. 行业平均PE/PB
# 6. 历史PE详细(5年每年最高/最低/平均,妙想API)
如需手动补充(调试用):
# 运营效率 + 现金流(5项指标一次查询)
python3 ~/.hermes/skills/miaoxiang/mx-finance-data/scripts/get_data.py \
--query "股票名称 股票代码 应收账款周转率 存货周转率 总资产周转率 经营活动现金流净额 企业自由现金流"
# 历史估值区间(近5年PE最高最低平均)
python3 ~/.hermes/skills/miaoxiang/mx-finance-data/scripts/get_data.py \
--query "股票名称 股票代码 近5年市盈率PE最高最低平均"
mx-finance-data返回xlsx格式:用openpyxl读取,第一行是表头(报告期列),第二行起是数据。
⚠️ 问财API 401错误(2026-05-06发现)
问财API对以下查询可能返回401:应收账款周转率、存货周转率、总资产周转率、经营活动现金流净额、企业自由现金流。必须用mx-finance-data获取。
执行顺序
- 运行
collector.py采集全部13个模块数据(JSON) - 检查效率指标和现金流数据是否获取成功
- 如有401错误,调用
mx-finance-data-fallback补充 - Agent读取JSON + v6模板,手动生成报告
- 运行
ima_integration.py上传IMA
IMA知识库配置 (v2 - PDF文件上传)
目标位置
| 配置项 | 值 |
|---|---|
| 知识库名称 | Mei Ming的知识库 |
| 知识库ID | W80hJmK98SC2GTUlPtnKK6MyKBE75MwMqFBJK8z0wyo= |
| 文件夹名称 | 行业公司报告 |
| 文件夹ID | folder_7403588502444840 |
自动化流程 (v2)
生成报告(MD) → weasyprint转PDF → preflight-check → COS上传 → 添加到知识库 → 删除本地文件
ima_integration.py v2 关键参数
# 目标文件夹ID
TARGET_FOLDER_ID = "folder_7403588502444840"
# 上传流程(PDF文件)
1. md_to_pdf() → weasyprint生成PDF
2. preflight-check.cjs → 检查文件类型
3. check_repeated_names → 检查重名
4. create_media → 创建媒体,获取COS凭证
5. cos-upload.cjs → 上传PDF到COS
6. add_knowledge → 添加到知识库(media_type=1)
generate_report.py 文件名匹配
⚠️ 已修复的bug:reporter.py生成的报告文件名格式为 {股票代码}_{股票名称}_*_report.md,不是 {股票名称}_深度研究报告*.md
正确的匹配逻辑:
# 先尝试第一种格式
report_file = find_latest_file(f"{stock_name}_深度研究报告*.md")
# 如果没找到,尝试第二种格式
if not report_file:
report_file = find_latest_file(f"{stock_code}_{stock_name}_*_report.md")
v2上传流程:ima_integration.py 自动将.md转为PDF并上传,无需手动处理文件名。
- 最新季度财务数据(营收、净利润、扣非净利润、毛利率、净利率、ROE(Q1)、资产负债率)
- 季度财务数据明细(最近8个季度)
- 近三年全年财务数据(营收、净利润、扣非净利润)
- 行业平均指标对比(毛利率、净利率 vs 行业平均)
- 核心投资逻辑总结(5个维度)
- 宏观环境与行业分析(国内/国际宏观、行业基本信息、竞争格局、产业链地位、市场规模、周期分析、驱动因素)
- 公司基本面(公司概况、历史沿革、营收结构、财务健康状况、杜邦分析、盈利质量、公司治理与股东、管理层、产能布局、产品结构、成本结构、研发投入)
- 竞争优势分析(SWOT分析、核心竞争壁垒)
- 估值分析(当前估值、历史估值区间、同行可比公司对比、国际对标、分部估值、DCF简述、PEG指标)
- 技术面分析(RSI/KDJ/布林带具体数值、趋势判断、支撑阻力位)
- 资金流向分析
- 风险与机会综合评估(风险矩阵、情景分析、催化剂时间窗口、风险应对策略)
- 新闻资讯
- 财务预测与估值模型(2026-2028年盈利预测、估值推导、敏感性分析)
- 投资建议与操作策略(入场/仓位/止损/目标价位、监控指标、退出策略)
- 数据来源与时效性 + 数据获取完整性验证
- 附录(可比公司列表、关键假设说明、数据来源明细)
数据补充要求(v6 增强版)
核心规则:生成报告时如发现N/A数据,必须自动调用技能补充数据
必须调用的技能查询:
-
扣非净利润查询(hithink-finance-query):
python3 /root/.hermes/skills/finance/hithink-finance-query/scripts/cli.py \ --query "XX股票 扣除非经常性损益后的净利润 2026年一季度" --limit "5" -
近三年全年数据查询(hithink-finance-query):
python3 /root/.hermes/skills/finance/hithink-finance-query/scripts/cli.py \ --query "XX股票 全年营业收入 全年净利润 全年扣非净利润 2023年 2024年 2025年" --limit "5" -
季度财务数据查询(hithink-finance-query):
python3 /root/.hermes/skills/finance/hithink-finance-query/scripts/cli.py \ --query "XX股票 单季度营业收入 单季度净利润 单季度扣非净利润" --limit "8" -
行业平均毛利率/净利率(hithink-industry-query):
python3 /root/.hermes/skills/finance/hithink-industry-query/scripts/cli.py \ --query "XX行业 平均毛利率 平均净利率 2026年一季度" --limit "5" -
技术面数据(mx-finance-data):
# 日线/周线K线数据、MACD RSI KDJ -
历史估值(mx-finance-data):
# 近5年市盈率PE最高最低平均 -
同行对比(mx-finance-data):
# 同行业对比 竞品A 竞品B -
机构评级(mx-finance-data):
# 券商研报评级 目标价
数据整合流程:
- 先用 collector.py 采集基础数据
- 检查报告中是否有N/A字段
- 如有N/A,自动调用上述技能补充
- 整合所有数据生成完整报告
- 确保所有字段已填充后上传IMA
报告文件名
生成的报告文件名必须包含股票名称,格式:{股票名称}_深度研究报告.md
不要使用 {股票代码}_{股票名称}_*_report.md 格式(会导致ima_integration.py找不到文件)。
上传流程:ima_integration.py 自动将.md转为PDF并上传到IMA知识库「行业公司报告」文件夹。
⛔ 合并报告模板 v6(2026-05-05 三花智控 vs 三安光电对比后确立)
对比三花智控和三安光电两份报告后,用户要求合并为统一模板。v6模板包含13个完整模块:
一、报告摘要
- ✅ 股价与估值概览表格
- ✅ 最新季度财务数据表格(含行业平均对比)
- ✅ 季度财务数据明细表格(最近4个季度)
- ✅ 近三年全年财务数据表格
- ✅ 行业平均指标对比表格
- ✅ 核心投资逻辑总结(5个维度)
- ✅ 核心驱动因素列表(emoji + 加粗标题 + 说明)
- ✅ 核心风险提示列表
- ✅ 目标价位与周期表格(机构/评级/目标价/核心观点)
- ✅ 投资周期建议
- ✅ 目标投资者画像
二、深度分析
-
宏观环境与行业分析
- ✅ 国内宏观环境(要点列表 + 总结句)
- ✅ 国际宏观环境(要点列表)
- ✅ 行业基本信息
- ✅ 行业估值水平(表格:指标/数值/行业分位)
- ✅ 行业资金流向(表格 + 分析句)
- ✅ 北向资金动态
- ✅ 行业规模与增速
- ✅ 行业周期分析
- ✅ 行业驱动因素
- ✅ 行业竞争格局(同行对比表格:公司/股价/PE/PB/市值/主要优势)
- ✅ 产业链地位(位置/上游/下游/议价能力)
-
公司基本面分析
- ✅ 公司概况与商业模式
- ✅ 历史沿革与发展里程碑
- ✅ 营收结构分析(按产品分类表格 + 按地区分类表格 + 分析句)
- ✅ 财务健康状况深度剖析
- 盈利能力(表格 + 同比变化)
- 成长能力(近三年对比表格 + 分析句)
- 偿债能力(表格 + 判断)
- 营运能力(表格)
- 现金流量(表格 + 分析句)
- 杜邦分析(ROE分解)
- 盈利质量分析
- ✅ 公司治理与股东情况
- 实际控制人信息
- 董事长/法人代表信息
- 前十大股东表格(含持股比例/数量/变动)
- 控股股东减持动态(近6个月)
- 股权质押情况
- ✅ 法律风险与负面消息(重大法律风险汇总表格)
- ✅ 管理层分析
- ✅ 产能布局
- ✅ 产品结构
- ✅ 成本结构
- ✅ 研发投入
- ✅ 机构持仓与市场情绪(分析师评级汇总表格)
-
竞争优势分析(SWOT分析)
- ✅ 优势(Strengths)
- ✅ 劣势(Weaknesses)
- ✅ 机会(Opportunities)
- ✅ 威胁(Threats)
- ✅ 核心竞争壁垒
-
估值分析
- ✅ 当前估值水平表格(指标/数值/行业平均/判断)
- ✅ 历史估值区间表格(近5年)
- ✅ 同行可比公司对比表格
- ✅ 估值消化测算(基于业绩增长的远期PE预测)
- ✅ 估值结论
-
技术面分析
- ✅ 关键技术指标表格(RSI/KDJ/MACD/布林带)
- ✅ 趋势判断(短/中/长期)
- ✅ 支撑与阻力(具体价位)
-
资金流向分析
- ✅ 个股资金流向表格(含主力/大单/特大单)
- ✅ 分析句
-
风险与机会综合评估
- ✅ 风险矩阵表格(风险类型/描述/概率/影响程度)
- ✅ 情景分析表格(乐观/中性/悲观)
- ✅ 潜在催化剂列表(emoji + 加粗标题 + 说明)
- ✅ 风险应对策略
-
新闻资讯
- ✅ 公司最新动态(按机构/日期列出)
三、财务预测与估值模型
- ✅ 盈利预测表格(2026-2028年)(营收/净利润/EPS)
- ✅ 估值推导(PE估值/PB估值/综合目标价)
- ✅ 敏感性分析表格
四、明确的投资建议与操作策略
- ✅ 投资评级(emoji星级)
- ✅ 投资逻辑总结(3点)
- ✅ 操作策略
- 入场策略(含具体价格区间)
- 仓位建议
- 止损策略
- 目标价位(短/中/长期)
- ✅ 关键监测指标(5个编号列表)
- ✅ 退出策略(止损/止盈/基本面退出)
数据来源与时效性
- ✅ 数据来源表格
- ✅ 免责声明
📊 数据获取完整性验证
- ✅ 模块状态表格(13个模块全部✅)
- ✅ 数据覆盖率100%
完整模板见:
references/merged-report-template.md(v6 基于三花智控+三安光电对比确立的标准模板)
IMA知识库集成 (v2 - PDF文件上传)
报告生成后自动上传到IMA知识库「行业公司报告」文件夹,本地.md文件自动删除。
IMA完整流程
# 步骤1:采集数据(13模块全覆盖)
python3 /root/.hermes/scripts/stock-research/collector.py -c <股票代码> -n <股票名称>
# 步骤2:Agent按v6模板手动生成报告
# 步骤3:上传IMA(MD → PDF → COS → 知识库)
python3 /root/.hermes/scripts/stock-research/ima_integration.py \
--report-path output/<股票名称>_深度研究报告.md \
--stock-name <股票名称> \
--stock-code <股票代码>
IMA配置
- Client ID:
0b8ad89306b75e1dabf520676577b101 - API Key: 已预配置
- 目标知识库: Mei Ming的知识库
- 目标文件夹: 行业公司报告 (folder_id:
folder_7403588502444840) - 上传方式: PDF文件(非笔记)
ima_api.cjs 未安装时的替代方案
如果Node.js环境缺少ima_api.cjs,使用Python直接调用IMA API上传PDF文件。参考 references/ima-api-integration.md。
Pitfalls
⛔ P0 Critical: PDF中文乱码(2026-05-07紫金矿业事故)
问题描述: 生成的PDF文件中所有中文显示为□□□方块。
根因分析: 系统未安装中文字体,weasyprint默认使用SimSun(不存在于Linux服务器)。
必须遵守的规则:
⛔ 禁止:假设系统已有中文字体
✅ 必须:首次使用前执行 apt-get install -y fonts-noto-cjk fonts-wqy-microhei
✅ 必须:ima_integration.py CSS中 font-family 以 "Noto Sans CJK SC" 为首选
修复命令:
apt-get install -y fonts-noto-cjk fonts-wqy-microhei
fc-cache -f
验证方法: 生成PDF后用pdftotext提取文本,检查是否包含中文字符。
⛔ P0 Critical: PDF emoji乱码(2026-05-07紫金矿业事故)
问题描述: PDF中emoji字符显示为⊠框框(带X的方块)。
根因分析: weasyprint不支持彩色emoji字体(Noto Color Emoji),即使安装了emoji字体也无法渲染。
必须遵守的规则:
⛔ 禁止:在报告MD中使用emoji字符(📊📈🏆✅⚠️等)
✅ 必须:ima_integration.py自动将emoji替换为纯文本标记
✅ 替换规则:✅→[OK] ⚠️→[!] ❌→[X] ⭐→* 装饰性emoji→移除
已修复: ima_integration.py v2已内置emoji清理逻辑,无需手动处理。
1. generate_report.py 文件名匹配bug
generate_report.py 内部调用 collector.py 采集数据,但报告文件名格式可能不匹配。 解决方案:手动执行ima_integration.py时,使用正确的文件路径
python3 ima_integration.py \
--report-path output/中国巨石_深度研究报告.md \
--stock-name 中国巨石 \
--stock-code 600176
0. 文件上传规则(v2 - PDF文件)
上传方式:Markdown → PDF → 文件上传到知识库(不再通过笔记)
用户原话:「直接把md的文件生成pdf 然后把pdf以文件的形式上传到ima的知识库中,不需要经过笔记」
- ✅ 使用
ima_integration.py自动转换并上传PDF - ❌ 不要使用
import_doc创建笔记 - ❌ 不要用 MEDIA: 发送文件给用户
2. ⛔ 技能文件修改禁令(用户原话:「技能模版未经我运行 禁止变动,私自修改 要变动请先请示我」)
禁止未授权修改以下任何文件:
- SKILL.md(技能说明文档)
- references/ 目录下的模板文件(merged-report-template.md 等)
- scripts/ 目录下的脚本(collector.py、reporter.py、reporter_v4.py、generate_report.py 等)
- templates/ 目录下的任何文件
⛔ 禁止:未经用户明确授权,私自修改任何技能文件(SKILL.md、模板、脚本、配置)
⛔ 禁止:patch/edit/create/delete 技能文件前不先请示用户
✅ 必须:先向用户请示修改内容和原因,获得批准后才能执行
✅ 必须:遇到执行不了的任务,明确告诉用户卡在哪里,让用户授权
3. 不要自作主张绕过限制
如果某个操作失败,不要尝试修改代码绕过,而是告诉用户具体问题,让用户决定如何处理。
5. 问财API对法律/风险数据覆盖不全 + news-search补充(2026-05-05三安光电事故)
问题描述: 三安光电报告中法律风险、股份冻结、实控人留置等关键信息全部显示"待确认",用户质疑数据采集不充分。
根因分析:
- 问财API的
business技能对司法冻结、拍卖、留置等特定事件覆盖不全 - 原始查询语句过于通用(如"诉讼 仲裁 债务纠纷"),未包含"司法冻结""拍卖""留置"等精准关键词
- news-search技能没有被集成到数据采集流程中作为风险数据的补充来源
必须遵守的规则:
⛔ 禁止:报告中出现"待确认"字段 — 代表数据采集不充分
✅ 必须:collector.py使用精准关键词查询(含"司法冻结""拍卖""留置""调查")
✅ 必须:在collect_news_data()中调用news-search搜索负面新闻作为补充
✅ 必须:生成报告前检查所有字段,如有"待确认"立即补充
修复方案:
- collector.py查询语句增加精准关键词(已修复)
- 新增
negative_news新闻搜索模块(已修复) - 报告生成前交叉验证:问财数据 + 新闻搜索数据
验证方法: 生成报告后搜索"待确认",如存在则说明数据采集不充分,需重新采集或补充查询。
6. 数据完整性要求(用户明确要求)
用户原话:「你生成的报告为什么又少了很多的数据,而且很多n值」
生成报告时必须确保所有关键数据已填充,不得出现N/A值。如果发现N/A:
-
立即调用补充查询:
- 扣非净利润 →
hithink-finance-query - 季度财务数据 →
mx-finance-data(优先,能获取历史8个季度) - 行业平均数据 →
hithink-industry-query - 历史估值 →
mx-finance-data
- 扣非净利润 →
-
季度数据获取策略:
- 问财API只返回最新一期,不要依赖
- 妙想API能返回历史季度数据,优先使用
- 查询语句:
"XX股票 季度营业收入 季度净利润 季度扣非净利润 2024年 2025年"
-
报告生成前检查:
- 读取JSON数据文件确认字段完整
- 如有N/A,先补充数据再生成报告
- 不要用占位符或"待确认"
5. 模板版本管理
用户原话:「你为什么又使用旧版模版,昨晚已经要求更新最新的模版」
- 当前模板版本:v6 专业机构级
- 模板位置:
~/.hermes/skills/finance/stock-deep-research/references/merged-report-template.md - 生成报告前必须确认使用最新模板
- v6新增模块:公司治理深度分析、法律风险与负面消息、SWOT分析、财务预测(2026-2028)、估值推导、敏感性分析、情景分析、风险应对策略、监控指标、退出策略、数据完整性验证 让用户决定如何处理。
4. 报告完成后不要发送文件(用户明确要求)
报告上传到IMA后,禁止通过MEDIA:发送文件给用户。 正确做法:只报告「已上传到IMA知识库「行业公司报告」文件夹」+ 核心数据摘要。 用户会在IMA客户端自行查看完整报告。
⛔ P0 Critical: 禁止使用 initiation-of-coverage-or-deep-dive 生成报告(2026-05-06特变电工事故)
问题描述: 用户要求"深度研究报告"时,AI错误调用了 initiation-of-coverage-or-deep-dive 技能的妙想API脚本,而非 stock-deep-research 的 collector.py + reporter_v4.py 流程。生成的报告是妙想API的通用模板(仅含核心投资逻辑和1-2个数据表格),完全缺失v6模板的13个完整模块。
用户原话:「你是不是没按我之前的脚本模版创建报告 怎么单独使用了妙想创建了」「我的模板已经是v6了 你是不是搞错了」
根因分析:
initiation-of-coverage-or-deep-dive技能的SKILL.md描述为"深度研究报告",触发词与stock-deep-research高度重叠- 但两者产出质量天差地别:前者是简单API调用(1页摘要),后者是完整的13模块v6报告(15000+字)
- AI未仔细对比两个技能的适用场景,直接选了看起来"更快"的那个
必须遵守的规则:
⛔ 禁止:用户说"深度研究""研究报告"时使用 initiation-of-coverage-or-deep-dive
⛔ 禁止:用妙想API的简单脚本替代 stock-deep-research 流程
✅ 必须:始终使用 collector.py + mx-finance-data补充 + v6模板生成报告
✅ 必须:generate_report.py 生成后检查输出是否为v6格式(13个模块)
两个技能的本质区别:
| 技能 | 适用场景 | 产出质量 | 使用时机 |
|---|---|---|---|
initiation-of-coverage-or-deep-dive | 快速获取妙想API的标准化摘要 | 低(1-2页,通用模板) | ❌ 不用于用户请求 |
stock-deep-research | 完整深度研究报告 | 高(13模块,v6模板) | ✅ 始终使用 |
验证方法: 生成报告后,检查是否包含v6的13个模块(报告摘要/宏观行业/公司基本面/SWOT/估值/技术面/资金流向/风险矩阵/新闻/财务预测/投资建议/数据验证/附录)。如果缺失,说明使用了错误的流程。
⛔ P0 Critical: generate_report.py 输出v4模板,非v6(2026-05-06特变电工发现)
问题描述: generate_report.py 内部调用 reporter_v4.py,输出的报告是v4模板格式(约300行/11KB),远不及v6模板(13个完整模块/15000+字)。v4模板缺少:SWOT分析、财务预测、敏感性分析、情景分析、退出策略、数据完整性验证等关键模块。
必须遵守的规则:
⛔ 禁止:直接把 generate_report.py 的输出当作最终报告
✅ 必须:generate_report.py 只作为数据采集步骤(collector.py的封装)
✅ 必须:报告生成必须基于v6模板手动整合,不能依赖 reporter_v4.py 的自动输出
正确流程:
generate_report.py或collector.py→ 采集数据(JSON)mx-finance-data→ 补充季度数据、技术面、历史估值- 基于
references/merged-report-template.md(v6)手动整合报告 - 检查13个模块是否齐全,N/A是否已填充
ima_integration.py→ 自动MD→PDF→上传IMA知识库
验证方法: 最终报告字数应≥10000字,包含13个模块标题。如<5000字且缺少SWOT/财务预测等,说明使用了v4模板。 虽然SKILL.md记录了双格式匹配逻辑,但实际运行时仍可能出现不匹配。 兜底方案:如果generate_report.py的IMA上传失败,手动执行:
python3 /root/.hermes/scripts/stock-research/ima_integration.py \
--report-path /root/.hermes/scripts/stock-research/output/<实际文件名>.md \
--stock-name <股票名称> \
--stock-code <股票代码>
9. IMA笔记提取丢失所有markdown格式(2026-05-07发现)
问题描述: 通过IMA API get_doc_content 提取的笔记内容,所有markdown格式(表格|、标题#、加粗**、列表-、分割线---)全部丢失,变成纯文本。
表现: 提取的文本中:
- 标题
## 一、报告摘要变成一、报告摘要 - 表格
| 指标 | 数值 |变成指标数值 - 加粗
**盈利能力**变成盈利能力 - 列表
- 项目1变成项目1 - 换行也被压缩,整段文字连在一起
根因: IMA笔记使用自有富文本格式存储,get_doc_content API返回的是纯文本版本,不包含markdown标记。
必须遵守的规则:
⛔ 禁止:从IMA笔记提取内容来对比报告格式(会丢失所有markdown)
✅ 必须:如需对比报告格式,使用本地MD文件或JSON数据文件
✅ 必须:reporter_v6.py生成标准markdown,ima_integration.py转PDF时保留格式
验证方法: 用 get_doc_content 提取的文本中如果找不到 | 或 #,说明格式已丢失。
10. weasyprint不支持彩色emoji字体(2026-05-07验证)
问题描述: 即使安装了 fonts-noto-color-emoji,weasyprint仍然无法渲染彩色emoji,显示为⊠框框。
根因: weasyprint使用Cairo渲染引擎,不支持CBDT/CBLC格式的彩色emoji字体。Noto Color Emoji是彩色位图字体,Cairo无法解析。
解决方案:
⛔ 禁止:尝试安装emoji字体来解决weasyprint的emoji问题
✅ 必须:在ima_integration.py中将emoji替换为纯文本标记
✅ 替换规则:✅→[OK] ⚠️→[!] ❌→[X] ⭐→* 📊📈等装饰emoji→移除
已修复: ima_integration.py v2已内置emoji清理逻辑,无需手动处理。
12. 扣非净利润字段名不一致(2026-05-08紫金矿业发现)
问题: 问财API返回的累计数据字段名为 扣非归母净利润[YYYYMMDD],但reporter_v6.py中使用 扣非净利润[YYYYMMDD],导致历史季度扣非净利润全部N/A。
解决方案: reporter_v6.py中读取quarterly_cumulative时,必须用 扣非归母净利润 而非 扣非净利润。
13. 估值字段日期后缀不一致(2026-05-08紫金矿业发现)
问题: 不同API返回的估值字段日期后缀不同:
| 字段 | collector.py用 | 问财API返回 |
|---|---|---|
| 市销率 | 市销率[20260506] | 市销率[20260507] |
| 股息率 | 股息率[20260506] | 年度股息率[20251231] |
解决方案: reporter_v6.py中用多字段回退:
ps = v(cv.get("市销率[20260507]", cv.get("市销率[20260506]")))
div = v(cv.get("股息率[20251231]", cv.get("年度股息率[20251231]", cv.get("股息率[20260506]"))))
14. 用户要求零N/A值(2026-05-08用户明确要求)
用户原话: 「报告中还是有na值,请了解技能工能,再次全部补全」
必须遵守的规则:
⛔ 禁止:报告中出现任何N/A值
✅ 必须:generate_report.py v9 的 Step 2d 自动补充所有缺失字段
✅ 必须:生成报告后 grep "N/A" 验证,如有则立即补充
✅ 必须:使用 hithink-finance-query 补充 市销率/股息率/营收同比/净利同比/加权ROE
✅ 必须:使用 hithink-industry-query 补充 行业平均PE/PB
16. 问财API限流导致采集失败(2026-05-08紫金矿业发现)
问题描述: 连续大量查询后问财API返回401 Unauthorized,导致collector.py采集的JSON中部分模块为空。
表现: 6_估值分析、12_杜邦分析等模块为空,报告中出现大量N/A。
解决方案:
✅ collector.py v7 已内置妙想API自动备选(运营效率+现金流)
✅ 估值/基本面缺失字段由 collector.py v7 的 collect_supplementary_valuation() 自动补充
✅ 行业平均PE/PB 由 collector.py v7 的 collect_supplementary_valuation() 自动查询
⚠️ 如遇限流,等待5-10分钟后重试
验证方法: 生成报告后 grep -c "N/A" report.md,如果>0说明有模块采集失败。
19. 妙想API补充数据的字段映射陷阱(2026-05-08洛阳钼业事故)
问题描述: 问财API限流后,用妙想API补充数据并写入JSON,但reporter_v6.py读取时大量N/A,原因是字段名和数据类型不匹配。
根因分析:
- 字段名不一致:妙想API返回
净利润/营业总收入,reporter_v6.py期望销售净利率 - 数据类型不一致:妙想API返回字符串
"664亿元"/"22.88%",reporter_v6.py期望浮点数 - 层级结构不一致:collector.py的问财查询返回
success: true, datas: [...],但限流时返回success: false, error: ...,手动写入需重建整个结构 - 子字段名不一致:
扣非净利润vs扣非归母净利润、市盈率PE(TTM)vs市盈率(pe,ttm)
必须遵守的规则:
⛔ 禁止:直接把妙想API的xlsx数据dump到JSON就期望reporter_v6.py正常工作
✅ 必须:按照字段映射表逐字段转换(见 references/miaoxiang-field-mapping.md)
✅ 必须:所有数值字段转换为float/int,去掉"亿元""次""倍""%"等单位
✅ 必须:写入前重建完整的section结构 {success: true, datas: [{...}]}
reporter_v6.py期望的关键字段名(与妙想API输出的映射):
| reporter_v6.py字段 | 妙想API返回字段 | 备注 |
|---|---|---|
市盈率(pe,ttm)[20260507] | 市盈率PE(TTM)[20260507] | 大小写+括号 |
销售净利率[20260331] | 净利润/营业总收入[20260331] | 完全不同的字段名 |
净资产收益率[20260331] | 净资产收益率ROE[20260331] | 后缀差异 |
营业收入[20260331] | 单季度.营业收入 | 需要加日期后缀 |
归母净利润[20260331] | 单季度.归属母公司股东的净利润 | 名称差异大 |
扣非归母净利润[20260331] | 单季度.扣除非经常损益后的净利润 | 名称差异大 |
单季度_营业收入[20260331] | 单季度.营业收入 | 下划线vs点号 |
单季度_归母净利润[20260331] | 单季度.归属母公司股东的净利润 | 同上 |
单季度_扣非净利润[20260331] | 单季度.扣除非经常损益后的净利润 | 同上 |
营业收入[20251231] (quarterly_cumulative) | 营业收入(年报列) | 需要加日期key |
扣非归母净利润[20251231] (quarterly_cumulative) | 扣除非经常性损益后归属于母公司股东的净利润 | 需要加日期key |
经营活动产生的现金流量净额[20260331] | 经营活动产生的现金流量净额 | 需要加日期后缀 |
企业自由现金流量[20260331] | 企业自由现金流量FCFF(反推法) | 名称差异大 |
数据清理函数(必须使用):
def clean_number(value):
"""妙想API数据 → reporter_v6.py可用的float"""
if value in ('N/A', None, '-'):
return None
import re
s = str(value)
s = re.sub(r'[亿元次倍%]', '', s).replace(',', '')
try:
num = float(s)
return int(num) if num == int(num) else num
except:
return None
完整的JSON写入模板:
# 正确的section结构
data['sections']['1_报告摘要']['current_price'] = {
'success': True,
'datas': [{
'最新价': 'N/A',
'总市值[20260507]': 4249,
'市盈率(pe,ttm)[20260507]': 17.59,
'市净率[20260507]': 4.781,
}]
}
验证方法: 写入JSON后执行 python3 reporter_v6.py,如仍有N/A则检查字段名是否完全匹配。
教训: 妙想API补充数据需要完整的字段映射+类型转换+结构重建,不能简单dump。
18. 问财API全面限流应急方案(2026-05-08紫金矿业事故)
问题描述: 连续大量查询后问财API全面返回401,collector.py采集的JSON中核心模块(current_price/fundamentals_snapshot/financial_history等)全部为空,导致报告138个N/A。
根因: 问财API有频率限制,短时间内发起60+查询会触发限流,恢复时间5-30分钟。
应急方案(按优先级):
✅ 方案1(推荐):等待5-10分钟后重新运行 generate_report.py
✅ 方案2:用妙想API补充核心数据(股价/PE/PB/毛利率/同比等)
✅ 方案3:用已知正确数据手动写入JSON(仅限调试/紧急情况)
方案2具体操作(妙想API补充):
完整查询语句见 references/miaoxiang-field-mapping.md 附录。核心查询:
# 核心数据(一次获取估值+财务)
python3 ~/.hermes/skills/miaoxiang/mx-finance-data/scripts/get_data.py \
--query "股票名称 股票代码 最新股价 总市值 市盈率 市净率 毛利率 净利率 ROE 资产负债率"
# 运营效率+现金流
python3 ~/.hermes/skills/miaoxiang/mx-finance-data/scripts/get_data.py \
--query "股票名称 股票代码 应收账款周转率 存货周转率 总资产周转率 经营活动现金流净额 企业自由现金流"
# 历史PE区间
python3 ~/.hermes/skills/miaoxiang/mx-finance-data/scripts/get_data.py \
--query "股票名称 股票代码 近5年市盈率PE最高最低平均"
# 累计季度数据(用于计算单季度值)
python3 ~/.hermes/skills/miaoxiang/mx-finance-data/scripts/get_data.py \
--query "股票名称 股票代码 营业收入 归母净利润 扣非净利润 2024年一季报 2024年中报 2024年三季报 2024年年报 2025年一季报 2025年中报 2025年三季报 2025年年报"
⚠️ 关键:妙想API返回xlsx格式 + 字段名与reporter_v6.py不一致,必须按
references/miaoxiang-field-mapping.md逐字段映射+清洗后写入JSON。
⚠️ mx-finance-data输出目录不固定:
- 全局目录:
~/miaoxiang/mx_finance_data/ - 脚本目录:
~/.hermes/scripts/stock-research/miaoxiang/mx_finance_data/ - 搜索时需遍历所有可能目录:
search_dirs = [
os.path.expanduser("~/miaoxiang/mx_finance_data/"),
os.path.expanduser("~/.hermes/scripts/stock-research/miaoxiang/mx_finance_data/"),
]
方案3(手动写入JSON): 当API完全不可用时,可将已知正确数据直接写入JSON的对应section。这需要了解JSON结构:
sections.1_报告摘要.current_price.datas[0]→ 股价/市值/PE/PBsections.1_报告摘要.fundamentals_snapshot.datas[0]→ 毛利率/净利率/ROE/负债率/同比sections.1_报告摘要.quarterly_cumulative.datas[0]→ 季度累计数据sections.1_报告摘要.financial_history.datas[0]→ 近三年全年数据sections.3_公司基本面.efficiency.datas[0]→ 周转率sections.3_公司基本面.cash_flow.datas[0]→ 现金流sections.12_杜邦分析.dupont.datas[0]→ 杜邦分解sections.13_历史估值.pe_history_5y.datas[0]→ 5年PE区间
25. miaoxiang/mx_finance_data 目录累积旧xlsx文件(2026-05-10发现)
问题描述: 每次使用mx-finance-data补充数据时,会在 ~/.hermes/scripts/stock-research/miaoxiang/mx_finance_data/ 目录下生成 .xlsx 和 _description.txt 文件。这些文件不会自动清理,长期积累会占用大量磁盘空间。
必须遵守的规则:
✅ 必须:每次成功生成报告后,清理 miaoxiang/mx_finance_data/ 下所有 .xlsx 和 *_description.txt 文件
✅ 必须:同时清理 output/ 目录下的旧JSON文件(保留最新的)
清理命令:
# 清理妙想API输出文件
rm -f ~/.hermes/scripts/stock-research/miaoxiang/mx_finance_data/*.xlsx
rm -f ~/.hermes/scripts/stock-research/miaoxiang/mx_finance_data/*_description.txt
# 清理旧JSON(保留最新)
cd ~/.hermes/scripts/stock-research/output/
# 删除除最新以外的旧JSON文件
find . -name "*.json" -not -name "$(ls -t *.json | head -1)" -delete
验证方法: 报告生成后检查 miaoxiang/mx_finance_data/ 目录是否为空。
⛔ P0 Critical: reporter_v6.py 硬编码结论彻底清零(v8.6 最终修复)
问题历程: 经历四轮修复,从38处→0处:
- 第一轮(v8.5):修复15处数据与结论矛盾(如资金流出写"净流入")
- 第二轮(v8.5):修复23处通用模板文字(如"全球化布局""行业龙头")
- 第三轮(v8.6):修复28处公司特定描述(如"消费电子精密零组件龙头""AI终端渗透率")
- 第四轮(v8.6):修复行业竞争格局表格列对齐bug
根本教训: 永远不要用"A公司的描述"替换"B公司的描述"——正确的做法是让所有描述都从数据动态生成。
判断标准: 如果把JSON数据换成另一家公司的,报告文字是否会出错?如果会出错,就是硬编码。
必须遵守的规则(用户明确要求):
⛔ 禁止:报告中任何结论性文字硬编码,不管数据如何
⛔ 禁止:使用任何公司特定的行业描述(如"消费电子""贵金属""新能源")
⛔ 禁止:使用任何具体公司名、产品名、客户名作为通用描述
✅ 必须:所有结论100%从JSON数据动态生成
✅ 必须:行业描述从ind变量和营收结构推断
✅ 必须:公司地位从市值分档判断(大型/骨干/参与者)
✅ 必须:竞争优势从毛利率/ROE/海外占比/专利数动态推断
✅ 必须:SWOT机会/威胁从PE/营收增速/海外占比/负债率推断
✅ 必须:催化剂从营收结构+估值水平动态生成
✅ 必须:风险矩阵从实际风险指标推断
验证检查清单(每次修改后必须执行):
# 1. 检查硬编码通用文字残留(期望:0)
grep -c "全球化布局\|并购整合\|外延式扩张\|国产替代\|行业龙头\|协同效应\|海外产能占比高" report.md
# 2. 检查📌结论是否与上方数据一致
grep '📌' report.md
# 逐条验证
# 3. 语法检查
python3 reporter_v6.py --json-path test.json --output /dev/null
# 期望:无报错
修复详情: 见 references/reporter-hardcoded-conclusion-fixes.md(38处修复完整清单)
24. reporter_v6.py 硬编码结论与数据矛盾(2026-05-10湖南黄金事故,已修复v8.5)
⛔ P0 Critical: reporter_v6.py 硬编码结论与数据矛盾(2026-05-10湖南黄金事故,已修复v8.5)
问题描述: reporter_v6.py中有38处硬编码结论文字,不管数据是什么都输出固定文字。例如资金流向数据为负(净流出),结论却写"主力资金净流入,市场看好"。
第二层风险(2026-05-11发现): 38处修复后仍有28处硬编码绑定到特定公司(湖南黄金),对领益智造等其他股票输出完全错误的结论(如"主营黄金+锑品"、"金价高位运行"等)。
必须遵守的规则(零硬编码原则):
⛔ 禁止:reporter_v6.py 中使用任何硬编码的定性结论
⛔ 禁止:假设公司是"行业龙头"、"全球化布局"、"并购整合"
⛔ 禁止:将特定公司描述(如"黄金冶炼"、"消费电子")用于所有股票
✅ 必须:所有📌结论必须根据实际数据动态生成(if/elif/else)
✅ 必须:行业地位/竞争壁垒/驱动因素从市值/毛利率/营收结构推断
✅ 必须:宏观环境从营收增速/海外占比/毛利率推断
✅ 必须:SWOT分析从实际财务数据生成5条优势/3条机会/3条威胁
重构时注意变量作用域:
# ❌ 变量在定义前使用(如overseas_pct在国际宏观定义但国内宏观使用)
# ✅ 将高频计算提前到数据加载区域,或在使用前独立计算
overseas_pct = overseas_rev / total_rev_r * 100 if total_rev_r > 0 else 0
pe_iv_local = sf(iv.get("最新市盈率ttm")) # 独立计算,不依赖后续变量
验证方法(每次修改后必须执行):
# 1. 检查硬编码公司特定描述残留
grep -c "黄金\|锑品\|贵金属\|金价\|消费电子\|AI终端\|汽车电子\|全球化布局\|国产替代\|并购整合\|外延式" report.md
# 期望:仅剩分析师研报原文和真实人名(≤5处)
# 2. 检查📌结论是否与上方数据一致
grep '📌' report.md
# 逐条验证
# 3. 语法检查(含变量作用域)
python3 reporter_v6.py --json-path test.json --output /dev/null
# 期望:无报错
详细修复清单:
- 第一轮(2026-05-10):38处数据矛盾 →
references/reporter-hardcoded-conclusion-fixes.md - 第二轮(2026-05-11):28处公司绑定 →
references/reporter-hardcoded-conclusion-fixes-round3.md
25. reporter_v6.py 全面去硬编码化(2026-05-11领益智造事故)
问题描述: reporter_v6.py中所有结论文字(宏观环境/行业分析/SWOT/风险/催化剂/投资逻辑等)都是针对特定公司的硬编码文字。第二轮修复时只是将湖南黄金的硬编码替换成了领益智造的硬编码,本质上没解决。
根因分析:
- 脚本编写时使用了固定描述("消费电子精密零组件龙头"、"AI终端渗透率提升"、"汽车电子快速发展"等)
- 这些描述只对一家公司正确,换其他公司就会出错
必须遵守的规则:
⛔ 禁止:用A公司的描述替换B公司的描述(只是换了硬编码内容)
✅ 必须:所有结论文字100%从JSON数据动态生成
✅ 必须:行业描述从ind变量+营收结构推断
✅ 必须:竞争优势从毛利率/ROE/市值/海外占比等数据推断
✅ 必须:SWOT/风险/催化剂等从实际财务指标条件判断
判断是否硬编码的简单方法: 如果把JSON数据换成另一家公司的,报告文字是否会出错?如果会出错,就是硬编码。
已修复28处,详细清单见: references/reporter-hardcoded-conclusion-fixes.md 第三轮修复
26. 行业竞争格局表格列对齐bug(2026-05-11正泰电器事故)
问题描述: 行业竞争格局表格中,同行公司的PE-TTM值被错误地放在了"最新价"列,导致数据看起来异常。
根因分析: peer_detailed数据中有最新价字段,但reporter_v6.py中行业竞争格局部分的代码没有提取该字段,直接把PE值放在了第一列数据位置。
修复方案:
# 修复前(缺少最新价列)
pp = v(pd.get(f"市盈率(pe,ttm)[{actual_date}]"))
w(f"| {pn} | ¥{pp} | {ppb} | - | ¥{pmk}亿 | - |")
# 修复后(添加最新价列)
ppl = v(pd.get("最新价")) # 最新价
pp = v(pd.get(f"市盈率(pe,ttm)[{actual_date}]")) # PE-TTM
ppb = v(pd.get(f"市净率[{actual_date}]"), "", 2) # PB
pmk = v(pd.get(f"总市值[{actual_date}]"), "", 0) # 市值
w(f"| {pn} | ¥{ppl} | {pp} | {ppb} | ¥{pmk}亿 | - |")
27. 变量作用域问题:overseas_pct/pe_iv提前使用(2026-05-11领益智造事故)
问题描述: 修改reporter_v6.py时,将overseas_pct的使用提前到了定义之前,导致UnboundLocalError。
根因分析:
- overseas_pct原在"国际宏观环境"部分计算
- 修改后的"国内宏观环境"部分引用了它
- Python在函数作用域中,变量赋值前引用会报错
修复方案: 将overseas_pct计算移到数据加载区域(所有报告内容之前),确保后续所有部分都能访问。
必须遵守的规则:
⛔ 禁止:在变量定义之前使用变量
✅ 必须:将跨多处使用的变量(overseas_pct/pe_iv等)提前到数据加载区域计算
✅ 必须:如果只需要在某一处使用,用本地变量(如pe_iv_local = sf(iv.get("最新市盈率ttm")))
28. hny_trend使用顺序错误(2026-05-11领益智造事故)
问题描述: hny_trend变量在定义之前被使用,导致UnboundLocalError。
根因分析: 原代码中是:
w(f"| 归母净利润(亿) | {' | '.join(fhn)} | 高速增长 |") # 硬编码
hny_vals = ... # 计算hny_trend
hny_trend = ...
修改时将"高速增长"改为{hny_trend},但hny_trend的计算在下一行。
修复方案: 将hny_vals和hny_trend的计算移到使用之前。
23. reporter_v6.py 硬编码日期导致大量N/A(2026-05-09冠豪高新事故)
问题描述: reporter_v6.py中硬编码了日期后缀(如20260507、20260506),但collector.py采集的数据使用实际日期(如20260508),导致字段名不匹配,报告出现49个N/A。
根因分析:
- reporter_v6.py代码中直接写死
市盈率(pe,ttm)[20260507]等日期后缀 - collector.py采集的数据使用实际日期(如
20260508) - 两者日期不匹配,
dict.get()返回None,最终显示N/A
必须遵守的规则:
⛔ 禁止:在reporter_v6.py中硬编码日期后缀(如[20260507])
✅ 必须:使用动态日期提取函数get_actual_date()从JSON数据中获取实际日期
✅ 必须:所有日期引用使用f-string格式化 f"字段名[{actual_date}]"
修复方案(已应用到reporter_v6.py v8.4):
def get_actual_date(data):
"""从JSON数据中提取实际日期"""
import re
sections = data.get('sections', {})
for sec_name in ['1_报告摘要', '6_估值分析']:
sec = sections.get(sec_name, {})
for key in sec:
val = sec[key]
if isinstance(val, dict) and 'datas' in val:
datas = val['datas']
if isinstance(datas, list) and len(datas) > 0:
item = datas[0]
if isinstance(item, dict):
for k in item.keys():
match = re.search(r'\[(\d{8})\]', k)
if match:
return match.group(1)
return '20260508' # default
# 使用方式
actual_date = get_actual_date(d)
pe = v(cp.get(f"市盈率(pe,ttm)[{actual_date}]", cp.get("市盈率(pe,ttm)")))
额外修复:f-string前缀缺失
部分代码使用 "字段[{actual_date}]" 而非 f"字段[{actual_date}]",导致字符串未被格式化。
❌ 错误:stk.get("主力资金流向[{actual_date}]")
✅ 正确:stk.get(f"主力资金流向[{actual_date}]")
验证方法: 生成报告后执行 grep -c "N/A" report.md,如果>10说明可能存在日期不匹配问题。
17. 空响应错误处理(2026-05-08发现)
问题描述: Hermes Agent在处理工具调用结果时返回空响应,触发"Empty response from model"错误。
原因: Agent处理大量工具输出时可能超时或上下文过长。
规避方法:
✅ 工具调用后必须处理结果并输出摘要,不要返回空
✅ 复杂任务分步执行,每步输出明确结果
✅ 避免在一次调用中执行过多操作
问题描述: 用户要求"以卧龙电驱报告为准重新生成模板",但卧龙电驱报告存储在IMA笔记中,通过API提取后格式全丢失。
正确的处理方式:
⛔ 禁止:从IMA笔记提取markdown格式作为模板基准
✅ 必须:让用户直接发送MD文件,或使用本地references/目录下的模板文件
✅ 必须:如需对比两份报告的模块完整性,使用关键词检查而非格式对比
替代方案: 用正则检查关键词是否存在来验证模块完整性:
keywords = ["盈利质量分析", "控股股东减持", "股权质押", "产能布局", ...]
for kw in keywords:
if kw in report_content:
print(f"✅ {kw}")
else:
print(f"❌ 缺失: {kw}")
注意事项
- 所有数据来源于同花顺问财 OpenAPI + 东方财富妙想API
- 报告仅供参考,不构成投资建议
- safe_get 函数必须使用
default=[]关键字参数 - mx-finance-data 每次查询最多返回5个实体的数据
- QQ Bot附件文件存放在
~/.hermes/cache/documents/,文件名格式doc_{uuid}_{filename} - 上传到IMA后会自动删除本地.md和.pdf文件,如需保留使用
--no-delete参数 - IMA上传使用PDF文件格式(v2),不再使用笔记格式
- 禁止删除或省略报告模板中的任何模块(用户明确要求)
- 每次任务执行成功后,保留最新版本脚本,删除所有旧版本/备份文件(用户明确要求)
- 不要用delegate_task生成完整报告(会超时600秒),应分段或在主Agent上下文中生成