360 Secure SkillHub
360 安全技能中心

股票深度研究报告

股票深度研究 Skill v11:以腾讯自选股、东方财富妙想、同花顺问财为数据源,用 collector.py 采集13个模块的行情与财务数据,reporter_v6.py 从 JSON 动态生成 Markdown 报告,再经 weasyprint 转 PDF 上传 IMA 知识库,并清理本地中间文件。

imeiming
imeiming
热度 25.57
最近更新 2026-05-11 22:26:47
分类:数据依赖:代码执行 / 读写文件 / 第三方 API应用场景:市场分析 / 报告撰写 / 研究 / 财务

安装技能

复制下面的话术发给你的 Agent,它会通过 secure-skills 检索并安装该技能。

执行命令安装此 skill: npx secure-skills-cli add stock-deep-research
Metadata
name
stock-deep-research
description
股票深度研究工具 v11 - 基于westock-data(腾讯自选股,主)+妙想API(辅)+问财API(补)的专业级研究报告生成器。 当用户要求分析某只股票、生成股票研究报告、进行股票深度研究时使用此技能。 一键执行:generate_report.py 自动完成采集→补充→生成→上传IMA。 报告以PDF文件上传到IMA知识库「行业公司报告」文件夹,本地文件自动删除。 关键特性:collector.py v8 westock-data为主数据源(免费无限制),妙想/问财自动备选。
version
11.2.0

股票深度研究报告

股票深度研究报告

基于同花顺问财 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与修复记录

  1. safe_get函数默认值bug:safe_get(sections, "key1", "key2", "key3", []) 中 [] 被当作key而非default,必须用 default=[] 关键字参数
  2. 股东字段名不一致:大股东名称 vs 股东名称,需同时兼容两个字段名
  3. 持股比例字段名:持股比例[20260331] vs 持股占流通股比例[20260331],需兼容
  4. croniter依赖:Hermes venv需要单独安装croniter包
  5. 季度数据缺口(2026-05-05,已修复):collector.py已直接采集季度财务数据(模块1),通过 quarterly_financials 查询获取。如仍需更详细的8季度历史数据,可用mx-finance-data补充。
  6. PDF中文乱码(2026-05-07,已修复):系统缺少中文字体,安装 fonts-noto-cjk + fonts-wqy-microhei 解决。CSS font-family 以 "Noto Sans CJK SC" 为首选。
  7. PDF emoji乱码(2026-05-07,已修复):weasyprint不支持彩色emoji,ima_integration.py自动将emoji替换为纯文本标记([OK]/[!]/[X])。

报告结构

生成的报告严格遵循以下框架:

  1. 报告摘要 - 核心投资逻辑、风险提示、目标价位
  2. 深度分析
    • 宏观环境与行业分析
    • 公司基本面分析(财务、治理、股东)
    • 估值分析(PE/PB/同行对比)
    • 技术面分析(需额外数据)
    • 风险与机会评估
  3. 投资建议 - 操作策略、入场/止损/目标价位

文件结构(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自动执行以下补充:

  1. 分两次查询获取2024年和2025年的累计数据
  2. 从累计值计算单季度值(Q1=累计, Q2=H1-Q1, Q3=9M-H1, Q4=FY-9M)
  3. 写入JSON的quarterly_cumulative字段
  4. 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}

正确做法:

  1. 新增数据源查询函数(如 query_westock_kline())
  2. 修改 query_with_fallback() 的降级顺序
  3. 数据采集模块内部结构完全不动

错误做法:

  • 修改 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修复)

问题描述: 多个变量在定义前被使用,导致运行时崩溃:

  1. overseas_pct 在"国内宏观"使用但定义在"国际宏观"
  2. hny_trend 在表格行使用但定义在下一行
  3. 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.py CSS中 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) 评估
  • 资产负债率评估

💡 核心投资逻辑总结

  1. 盈利能力分析
  2. 成长性分析
  3. 财务健康分析
  4. 股东回报分析
  5. 估值水平分析

完整报告框架:

一、报告摘要(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工具)要求完善系统报告时,使用以下流程:

步骤

  1. 定位外部报告文件:检查 ~/.hermes/cache/documents/ 目录(QQ Bot附件自动下载位置)
    • 文件名格式:doc_{uuid12}_{原始文件名}
    • 用 find ~/.hermes/cache/documents/ -name "*.md" -mmin -30 查找最近的文件
  2. 读取两份报告:系统旧报告 + 外部新报告
  3. 生成差异分析:逐章节对比,列出新报告独有的数据/观点/分析
  4. 修正错误数据:特别注意股价、市值、资产负债率等核心数据
  5. 整合完善:将新报告的有价值信息整合到旧报告中,生成V2版本
  6. 输出:保存到 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.py v10 — 一键编排(3步:采集→生成→上传)
  • collector.py v7 — 数据采集(13模块+3补充模块,全部内置)
  • reporter_v6.py v8.2 — 报告生成(JSON→固定格式MD,含sf()+季度计算)
  • ima_integration.py v2 — 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获取。

执行顺序

  1. 运行 collector.py 采集全部13个模块数据(JSON)
  2. 检查效率指标和现金流数据是否获取成功
  3. 如有401错误,调用 mx-finance-data-fallback 补充
  4. Agent读取JSON + v6模板,手动生成报告
  5. 运行 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个维度)
  1. 宏观环境与行业分析(国内/国际宏观、行业基本信息、竞争格局、产业链地位、市场规模、周期分析、驱动因素)
  2. 公司基本面(公司概况、历史沿革、营收结构、财务健康状况、杜邦分析、盈利质量、公司治理与股东、管理层、产能布局、产品结构、成本结构、研发投入)
  3. 竞争优势分析(SWOT分析、核心竞争壁垒)
  4. 估值分析(当前估值、历史估值区间、同行可比公司对比、国际对标、分部估值、DCF简述、PEG指标)
  5. 技术面分析(RSI/KDJ/布林带具体数值、趋势判断、支撑阻力位)
  6. 资金流向分析
  7. 风险与机会综合评估(风险矩阵、情景分析、催化剂时间窗口、风险应对策略)
  8. 新闻资讯
  9. 财务预测与估值模型(2026-2028年盈利预测、估值推导、敏感性分析)
  10. 投资建议与操作策略(入场/仓位/止损/目标价位、监控指标、退出策略)
  11. 数据来源与时效性 + 数据获取完整性验证
  12. 附录(可比公司列表、关键假设说明、数据来源明细)

数据补充要求(v6 增强版)

核心规则:生成报告时如发现N/A数据,必须自动调用技能补充数据

必须调用的技能查询:

  1. 扣非净利润查询(hithink-finance-query):

    python3 /root/.hermes/skills/finance/hithink-finance-query/scripts/cli.py \
      --query "XX股票 扣除非经常性损益后的净利润 2026年一季度" --limit "5"
    
  2. 近三年全年数据查询(hithink-finance-query):

    python3 /root/.hermes/skills/finance/hithink-finance-query/scripts/cli.py \
      --query "XX股票 全年营业收入 全年净利润 全年扣非净利润 2023年 2024年 2025年" --limit "5"
    
  3. 季度财务数据查询(hithink-finance-query):

    python3 /root/.hermes/skills/finance/hithink-finance-query/scripts/cli.py \
      --query "XX股票 单季度营业收入 单季度净利润 单季度扣非净利润" --limit "8"
    
  4. 行业平均毛利率/净利率(hithink-industry-query):

    python3 /root/.hermes/skills/finance/hithink-industry-query/scripts/cli.py \
      --query "XX行业 平均毛利率 平均净利率 2026年一季度" --limit "5"
    
  5. 技术面数据(mx-finance-data):

    # 日线/周线K线数据、MACD RSI KDJ
    
  6. 历史估值(mx-finance-data):

    # 近5年市盈率PE最高最低平均
    
  7. 同行对比(mx-finance-data):

    # 同行业对比 竞品A 竞品B
    
  8. 机构评级(mx-finance-data):

    # 券商研报评级 目标价
    

数据整合流程:

  1. 先用 collector.py 采集基础数据
  2. 检查报告中是否有N/A字段
  3. 如有N/A,自动调用上述技能补充
  4. 整合所有数据生成完整报告
  5. 确保所有字段已填充后上传IMA

报告文件名
生成的报告文件名必须包含股票名称,格式:{股票名称}_深度研究报告.md 不要使用 {股票代码}_{股票名称}_*_report.md 格式(会导致ima_integration.py找不到文件)。

上传流程:ima_integration.py 自动将.md转为PDF并上传到IMA知识库「行业公司报告」文件夹。

⛔ 合并报告模板 v6(2026-05-05 三花智控 vs 三安光电对比后确立)

对比三花智控和三安光电两份报告后,用户要求合并为统一模板。v6模板包含13个完整模块:

一、报告摘要

  • ✅ 股价与估值概览表格
  • ✅ 最新季度财务数据表格(含行业平均对比)
  • ✅ 季度财务数据明细表格(最近4个季度)
  • ✅ 近三年全年财务数据表格
  • ✅ 行业平均指标对比表格
  • ✅ 核心投资逻辑总结(5个维度)
  • ✅ 核心驱动因素列表(emoji + 加粗标题 + 说明)
  • ✅ 核心风险提示列表
  • ✅ 目标价位与周期表格(机构/评级/目标价/核心观点)
  • ✅ 投资周期建议
  • ✅ 目标投资者画像

二、深度分析

  1. 宏观环境与行业分析

    • ✅ 国内宏观环境(要点列表 + 总结句)
    • ✅ 国际宏观环境(要点列表)
    • ✅ 行业基本信息
    • ✅ 行业估值水平(表格:指标/数值/行业分位)
    • ✅ 行业资金流向(表格 + 分析句)
    • ✅ 北向资金动态
    • ✅ 行业规模与增速
    • ✅ 行业周期分析
    • ✅ 行业驱动因素
    • ✅ 行业竞争格局(同行对比表格:公司/股价/PE/PB/市值/主要优势)
    • ✅ 产业链地位(位置/上游/下游/议价能力)
  2. 公司基本面分析

    • ✅ 公司概况与商业模式
    • ✅ 历史沿革与发展里程碑
    • ✅ 营收结构分析(按产品分类表格 + 按地区分类表格 + 分析句)
    • ✅ 财务健康状况深度剖析
      • 盈利能力(表格 + 同比变化)
      • 成长能力(近三年对比表格 + 分析句)
      • 偿债能力(表格 + 判断)
      • 营运能力(表格)
      • 现金流量(表格 + 分析句)
      • 杜邦分析(ROE分解)
      • 盈利质量分析
    • ✅ 公司治理与股东情况
      • 实际控制人信息
      • 董事长/法人代表信息
      • 前十大股东表格(含持股比例/数量/变动)
      • 控股股东减持动态(近6个月)
      • 股权质押情况
    • ✅ 法律风险与负面消息(重大法律风险汇总表格)
    • ✅ 管理层分析
    • ✅ 产能布局
    • ✅ 产品结构
    • ✅ 成本结构
    • ✅ 研发投入
    • ✅ 机构持仓与市场情绪(分析师评级汇总表格)
  3. 竞争优势分析(SWOT分析)

    • ✅ 优势(Strengths)
    • ✅ 劣势(Weaknesses)
    • ✅ 机会(Opportunities)
    • ✅ 威胁(Threats)
    • ✅ 核心竞争壁垒
  4. 估值分析

    • ✅ 当前估值水平表格(指标/数值/行业平均/判断)
    • ✅ 历史估值区间表格(近5年)
    • ✅ 同行可比公司对比表格
    • ✅ 估值消化测算(基于业绩增长的远期PE预测)
    • ✅ 估值结论
  5. 技术面分析

    • ✅ 关键技术指标表格(RSI/KDJ/MACD/布林带)
    • ✅ 趋势判断(短/中/长期)
    • ✅ 支撑与阻力(具体价位)
  6. 资金流向分析

    • ✅ 个股资金流向表格(含主力/大单/特大单)
    • ✅ 分析句
  7. 风险与机会综合评估

    • ✅ 风险矩阵表格(风险类型/描述/概率/影响程度)
    • ✅ 情景分析表格(乐观/中性/悲观)
    • ✅ 潜在催化剂列表(emoji + 加粗标题 + 说明)
    • ✅ 风险应对策略
  8. 新闻资讯

    • ✅ 公司最新动态(按机构/日期列出)

三、财务预测与估值模型

  • ✅ 盈利预测表格(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三安光电事故)

问题描述: 三安光电报告中法律风险、股份冻结、实控人留置等关键信息全部显示"待确认",用户质疑数据采集不充分。

根因分析:

  1. 问财API的 business 技能对司法冻结、拍卖、留置等特定事件覆盖不全
  2. 原始查询语句过于通用(如"诉讼 仲裁 债务纠纷"),未包含"司法冻结""拍卖""留置"等精准关键词
  3. news-search技能没有被集成到数据采集流程中作为风险数据的补充来源

必须遵守的规则:

⛔ 禁止:报告中出现"待确认"字段 — 代表数据采集不充分
✅ 必须:collector.py使用精准关键词查询(含"司法冻结""拍卖""留置""调查")
✅ 必须:在collect_news_data()中调用news-search搜索负面新闻作为补充
✅ 必须:生成报告前检查所有字段,如有"待确认"立即补充

修复方案:

  1. collector.py查询语句增加精准关键词(已修复)
  2. 新增 negative_news 新闻搜索模块(已修复)
  3. 报告生成前交叉验证:问财数据 + 新闻搜索数据

验证方法: 生成报告后搜索"待确认",如存在则说明数据采集不充分,需重新采集或补充查询。

6. 数据完整性要求(用户明确要求)

用户原话:「你生成的报告为什么又少了很多的数据,而且很多n值」

生成报告时必须确保所有关键数据已填充,不得出现N/A值。如果发现N/A:

  1. 立即调用补充查询:

    • 扣非净利润 → hithink-finance-query
    • 季度财务数据 → mx-finance-data(优先,能获取历史8个季度)
    • 行业平均数据 → hithink-industry-query
    • 历史估值 → mx-finance-data
  2. 季度数据获取策略:

    • 问财API只返回最新一期,不要依赖
    • 妙想API能返回历史季度数据,优先使用
    • 查询语句:"XX股票 季度营业收入 季度净利润 季度扣非净利润 2024年 2025年"
  3. 报告生成前检查:

    • 读取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 的自动输出

正确流程:

  1. generate_report.py 或 collector.py → 采集数据(JSON)
  2. mx-finance-data → 补充季度数据、技术面、历史估值
  3. 基于 references/merged-report-template.md(v6)手动整合报告
  4. 检查13个模块是否齐全,N/A是否已填充
  5. 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,原因是字段名和数据类型不匹配。

根因分析:

  1. 字段名不一致:妙想API返回 净利润/营业总收入,reporter_v6.py期望 销售净利率
  2. 数据类型不一致:妙想API返回字符串 "664亿元" / "22.88%",reporter_v6.py期望浮点数
  3. 层级结构不一致:collector.py的问财查询返回 success: true, datas: [...],但限流时返回 success: false, error: ...,手动写入需重建整个结构
  4. 子字段名不一致:扣非净利润 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/PB
  • sections.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上下文中生成