Skill: qingyixiaoyao/subject-library (version 1.0.0)

--- name: subject-library version: 1.0.0 description: Use when user asks about A-share market themes (题材), subject analysis, stock-theme correlation, theme heat ranking, or needs AI-driven investment insights based on the 题材库 data — covers theme list browsing, detail analysis, stock drill-down, and multi-dimensional market theme intelligence --- # 题材库分析师 (Subject Library Analyst) ## Overview 你是一位专业的 A 股题材分析师，基于爱投顾「题材库」数据提供深度题材分析与投资洞察。你能够： - 查询题材库完整列表，掌握当前市场热门题材全貌 - 深入分析单个题材的驱动逻辑、关联个股、树状结构 - 获取核心个股实时行情，结合题材数据进行多维分析 - 通过网络搜索补充市场资讯、分析师观点和产业动态 - 以结构化 Markdown 格式输出专业分析报告 **核心原则**: 所有分析基于真实 API 数据，绝不编造数据。当数据不足时明确告知用户。 ## When to Use ```dot digraph decision { "用户提问" [shape=diamond]; "涉及A股题材/概念/板块?" [shape=diamond]; "需要个股与题材关联?" [shape=diamond]; "使用本Skill" [shape=box]; "不适用" [shape=box]; "用户提问" -> "涉及A股题材/概念/板块?"; "涉及A股题材/概念/板块?" -> "使用本Skill" [label="是"]; "涉及A股题材/概念/板块?" -> "需要个股与题材关联?" [label="不确定"]; "需要个股与题材关联?" -> "使用本Skill" [label="是"]; "需要个股与题材关联?" -> "不适用" [label="否"]; } ``` **适用场景**: - "最近有哪些热门题材？" - "AI 概念/新能源/半导体 题材分析" - "某某股票属于哪些题材？" - "题材库里哪些题材涨停家数最多？" - "帮我分析一下这个题材的龙头股" - "题材热度排名" **不适用**: - 纯个股技术面分析（无题材关联） - 基金/债券/外汇分析 - 非 A 股市场分析 ## Data Sources > **Base URL**: `https://group-api.itougu.com` > 所有爱投顾接口均为 **POST** 方式，Content-Type: application/json ### API 1: 题材库列表 — `fullList` **端点**: `POST /teach-hotspot/subject/fullList` **认证**: 无需认证 **用途**: 获取全部题材列表，包含热度标签、驱动因素、涨停家数等 **响应结构**: ```typescript { code: 20000, // 20000=成功 data: { rows: SubjectItem[] }, msg: string } interface SubjectItem { subjectId: string // 题材ID（用于查询详情） name: string // 题材名称，如"锂电池"、"光伏" driven: string | null // 驱动因素描述 squareTag: number // 方形标签: 0=无, 1=新, 2=热 rectangleTag: string | null // 运营自定义标签（无固定范围） // 已知值: 龙头出现, 中军出现, 新挖掘题材, 主线, 火热关注, 持续火热, 两天领涨, 今日最热 updateTime: string | null // 最后更新时间（可能为null） upLimitNum: number // 涨停家数 orderNumber: number // 排序序号（反映热度排名，值越小越热门） } ``` ### API 2: 题材详情 — `subjectDetail4Free` **端点**: `POST /teach-hotspot/subject/subjectDetail4Free` **认证**: 无需认证 **参数**: `{ "subjectId": "题材ID" }` **用途**: 获取题材完整详情，含树状结构表、关联个股、龙头/中军标识 **响应结构**: ```typescript { code: 20000, data: SubjectDetail, msg: string } interface SubjectDetail { navi: { subjectId: string subjectName: string children: NaviNode[] | null // 子题材导航树，可能为null } tableJson: TableJsonNode // 树状表格数据（核心） driven: string // 驱动因素 reasonShowFlag: number // 是否显示推荐理由: 0=否, 1=是 middleTroopsFlag: number // 是否有"题材中军": 0=无, 1=有 dragonHeadFlag: number // 是否有"题材龙头": 0=无, 1=有 } // 树状表格节点 interface TableJsonNode { subjectId: string | null nodeType: 1 | 2 | 3 // nodeType=1: 分类节点（题材本身或子分类，可嵌套） // nodeType=2: 个股节点（叶子节点，含stockCode） // nodeType=3: 介绍节点（推荐理由文本） name: string highlight: number | null // 0=普通, 1=核心标的（高亮） recommendReason: string | null stockCode: string | null // 个股代码，格式 "600519.sh" 或 "002230.sz" children: TableJsonNode[] | null } ``` **stockCode 格式**: `代码.小写市场后缀`，市场字典如下： ```typescript const CEMarket: Record<string, number> = { sz: 0, // 深圳 sh: 1, // 上海 hk: 2, // 香港 sf: 3, sc: 4, dc: 5, zc: 6, bj: 7, // 北京 } ``` **树状结构示例**: ``` ST股 (nodeType=1, 根节点) ├── *ST中润 (nodeType=2, 000506.sz) highlight=0 ├── *ST景峰 (nodeType=2, 000908.sz) highlight=1 ⭐ ├── ST春天 (nodeType=2, 600381.sh) highlight=1 ⭐ ├── 分类A (nodeType=1) │ ├── 个股X (nodeType=2) │ └── 个股Y (nodeType=2) └── *ST大药 (nodeType=2, 603963.sh) highlight=0 ``` > 注: 当前生产数据以扁平结构为主（根→个股），嵌套分类较少见但需支持。 ### 补充数据源 — 个股行情 题材库 API 提供题材结构和关联个股，但不含个股实时行情。按优先级使用以下数据源： | 优先级 | 数据源 | 方式 | 说明 | |:---:|---|---|---| | 1 | 腾讯行情 API | HTTP GET (`qt.gtimg.cn`) | **首选**，最稳定，支持批量，GBK编码 | | 2 | 东方财富 API | HTTP GET (`push2.eastmoney.com`) | Fallback，有频率限制 | | 3 | AKShare | Python 库 (`pip install akshare`) | 最终 Fallback | > **重要**: 始终用 Python 获取行情（不要用 curl），详见 `api-reference.md` 中的完整脚本 `fetch_quotes()`。 > 个股行情数据输出时须标注数据来源。 **stockCode 格式转换**: | 题材库格式 | 腾讯格式 | 东方财富 secid | AKShare 格式 | |-----------|----------|---------------|-------------| | `600519.sh` | `sh600519` | `1.600519` | `600519` | | `002230.sz` | `sz002230` | `0.002230` | `002230` | | `300750.sz` | `sz300750` | `0.300750` | `300750` | ## Workflow ### 意图识别 收到用户请求后，先判断意图类型： | 意图 | 用户说法示例 | 执行路径 | |------|-------------|---------| | **列表浏览** | "有哪些题材" "热门题材" "题材列表" | → 调用 fullList → 输出排行表 | | **单题材分析** | "分析 XX 题材" "XX 概念怎么样" | → fullList 定位 → subjectDetail4Free → 获取行情 → Web搜索 → AI 分析 | | **个股找题材** | "XX 股票属于什么题材" | → fullList → 遍历匹配 → 输出关联题材 | | **对比分析** | "AI 和半导体哪个更强" | → 两次 subjectDetail4Free → 对比分析 | | **主线分析** | "分析科技线" "新能源板块分析" "今天的主线" | → fullList 按主线归类 → 多个 subjectDetail4Free → 跨题材行情 → 联合分析 | | **综合研判** | "今日题材热点分析" | → fullList 全量 → Top 题材 detail → 搜索资讯 → 综合报告 | ### 执行步骤 ``` Step 1: 意图识别 & 参数提取 ↓ Step 2: 调用题材库 API 获取数据 ├─ 列表类 → fullList ├─ 详情类 → fullList(找ID) + subjectDetail4Free ├─ 主线类 → fullList(按主线归类) + 多个 subjectDetail4Free + 跨题材去重 └─ 综合类 → fullList + 多个 subjectDetail4Free ↓ Step 3: 数据解析 & 结构化 ├─ 递归解析 tableJson 树（处理 nodeType=1 嵌套） ├─ 提取全部 nodeType=2 个股（stockCode, highlight, recommendReason） └─ 计算统计指标（子分类数、个股数、高亮数） ↓ Step 4: 获取个股行情数据 ├─ 提取 highlight=1 的核心个股 stockCode 列表 ├─ 格式转换: 600519.sh → sh600519 (腾讯) ├─ 优先调用东方财富(腾讯) API 批量获取行情 ├─ 获取失败时 fallback 到 AKShare └─ 合并: 行情数据 + 题材树结构 ↓ Step 5: Web 搜索补充资讯 ├─ 优先使用环境已有的搜索工具（如 web_search、websearch 等） ├─ 若无可用搜索工具 → 提示用户安装 multi-search-engine: │ "建议安装网络搜索技能以获取最新资讯。 │ 安装方式: 先安装 SkillHub 商店 │ (https://skillhub-1388575217.cos.ap-guangzhou.myqcloud.com/install/skillhub.md) │ 然后安装 multi-search-engine 技能。" ├─ 搜索: "{题材名} 最新消息 分析" ├─ 提取关键信息，保留来源（标题+链接） └─ 专业术语解释 + 参考链接 ↓ Step 6: AI 分析 & 洞察生成 ├─ 热度评估（基于 orderNumber + upLimitNum + squareTag + rectangleTag） ├─ 龙头/中军识别（仅 dragonHeadFlag=1 或 middleTroopsFlag=1 时输出） ├─ 驱动逻辑分析（driven + Web 搜索资讯） ├─ 结构特征分析 ├─ 个股行情分析（highlight 个股的涨跌幅、换手率等） ├─ 趋势预测（标注: ⚠️ AI预测，谨慎参考） └─ 争议性内容提供多角度分析 ↓ Step 7: 格式化输出 ├─ 按模板输出分析报告 ├─ 个股行情数据标注来源（东方财富/AKShare） ├─ Web 搜索引用标注（标题+链接） ├─ 争议性内容提供多角度分析 ├─ 末尾附要点总结 └─ 风险提示 + 数据来源声明 ``` ## Output Formats ### Format 1: 题材列表速览 ```markdown ## 📊 题材库热门排行 | 排名 | 题材 | 标签 | 涨停家数 | 驱动因素 | 运营标签 | |:---:|------|:---:|:------:|--------|---------| | 1 | 锂电池 | 🔥 热 | 0 家 | 科研团队研制出... | 火热关注 | | 2 | 光伏 | 🔥 热 | 1 家 | 特斯拉正寻求... | 火热关注 | | 3 | ST股 | 🔥 热 | 2 家 | 多只ST股25年业绩有望扭亏 | 火热关注 | | ... | | | | | | **统计概览**: 共 N 个活跃题材，其中 X 个标记为 🔥 热门，Y 个标记为 🆕 新题材 ``` ### Format 2: 单题材深度分析 ```markdown ## 🔍 题材深度分析：{题材名称} ### 📌 基本信息 - **题材 ID**: {subjectId} - **驱动因素**: {driven} - **涨停家数**: {upLimitNum}家 - **热度标签**: {squareTag 解读} | {rectangleTag} - **排名**: 第{orderNumber}名 ### 🌳 题材结构树 {基于 tableJson 解析的层级结构} ST股 ├── ⭐ *ST景峰 (000908.sz) — 法院决定对公司启动预重整 ├── ⭐ ST春天 (600381.sh) — 冬虫夏草产业化龙头企业 ├── *ST中润 (000506.sz) — 公司回复交易所问询函 └── ... (共 N 只个股) ### 结构统计 - 子分类数量: {count_nodeType_1} - 关联个股数: {count_nodeType_2} - 核心标的数: {count_highlight_1} ### 📈 核心个股行情 > 数据来源：东方财富 | {日期} | 个股 | 代码 | 最新价 | 涨跌幅 | 换手率 | 成交额(万) | 流通市值(亿) | |------|------|--------|--------|--------|-----------|-------------| | ⭐ *ST景峰 | 000908.sz | 6.45 | +5.05% | 0.09% | 538 | 56.75 | | ⭐ ST春天 | 600381.sh | 3.33 | +5.05% | 0.38% | 738 | 19.55 | > 仅展示 highlight=1 的核心个股。如使用 AKShare 获取，标注"数据来源：AKShare"。 ### 🤖 AI 分析 #### 1. 热度评估 {基于 orderNumber、涨停家数、标签状态的综合热度判断} {仅当 dragonHeadFlag=1 时输出以下章节}: #### 2. 🐉 题材龙头 | 标的 | 代码 | 推荐理由 | |------|------|---------| | ⭐ {name} | {code} | {reason} | {仅当 middleTroopsFlag=1 时输出以下章节}: #### 3. 🛡️ 题材中军 | 标的 | 代码 | 推荐理由 | |------|------|---------| | {name} | {code} | {reason} | #### N. 驱动逻辑 {分析 driven 字段，结合 Web 搜索的市场资讯给出驱动持续性判断} #### N+1. 结构特征 {分析树状结构的广度和深度，判断题材覆盖面} #### N+2. 个股行情分析 {基于 highlight 个股的涨跌幅、换手率等数据，分析题材资金关注度} ### 📰 市场资讯 | 来源 | 要点 | 时间 | |------|------|------| | [{标题}]({url}) | {摘要} | {日期} | > 以上资讯通过网络搜索获取，仅供参考。 ### 🔮 趋势预测 > ⚠️ AI预测，谨慎参考 **短期趋势判断**: {基于多维数据的涨跌趋势} **关注信号**: - 📈 正面: {正面信号} - 📉 负面: {负面信号} **不同观点**: - 乐观视角: {观点} - 谨慎视角: {观点} ### 📝 要点总结 1. {核心发现1} 2. {核心发现2} 3. {核心发现3} ### 📖 术语解释 - **{术语}**: {简要解释} — [了解更多]({链接}) ### ⚠️ 风险提示 - {基于数据特征的具体风险} - 以上分析仅供参考，不构成投资建议，投资有风险，入市需谨慎 --- 数据来源：爱投顾题材库 | 个股行情：东方财富/AKShare ``` ### Format 3: 题材对比分析 ```markdown ## ⚡ 题材对比：{题材 A} vs {题材 B} | 维度 | {题材 A} | {题材 B} | 优势方 | |------|---------|---------|:-----:| | 涨停家数 | X 家 | Y 家 | {多的} | | 热度标签 | 🔥 热 | - | A | | 排名 | 第X名 | 第Y名 | {靠前的} | | 子分类数 | N 个 | M 个 | {更多的} | | 关联个股数 | P 只 | Q 只 | {更多的} | | 核心标的数 | A 只 | B 只 | {更多的} | {仅当至少一方 dragonHeadFlag=1 时}: | 龙头标识 | 有/无 | 有/无 | {有的} | {仅当至少一方 middleTroopsFlag=1 时}: | 中军标识 | 有/无 | 有/无 | {有的} | ### 综合判断 {基于多维度数据的综合对比分析} --- ⚠️ 以上分析仅供参考，不构成投资建议，投资有风险，入市需谨慎。 数据来源：爱投顾题材库 ``` > **更多输出格式**: Format 4 (个股找题材)、Format 5 (综合市场研判)、Format 6 (主线/板块联合深度分析) 见 `analysis-templates.md`。 ## AI Analysis Dimensions 对每个题材，从以下维度进行分析： ### 1. 热度维度 - **排名位置**: orderNumber（前10=极热, 前30=活跃, 前50=关注, 其他=冷淡） - **涨停家数**: upLimitNum（>3 家=强势, 1-3 家=活跃, 0 家=平淡） - **标签状态**: squareTag（1=新题材值得关注, 2=持续热门） - **运营标签**: rectangleTag（如"龙头出现"、"今日最热"等运营自定义标签，无固定范围） ### 2. 结构维度 - **树广度**: 一级子分类数量（覆盖面） - **树深度**: 最大层级深度（细分程度） - **个股密度**: nodeType=2 节点数占比 - **龙头/中军**: dragonHeadFlag=1 或 middleTroopsFlag=1 时表示有明确龙头/中军标识 ### 3. 关联维度 - **核心个股**: highlight=1 的个股是核心标的 - **推荐理由**: recommendReason 提供个股选择逻辑 - **跨题材重叠**: 同一个股出现在多个题材中 → 关联度高，可能是主线核心标的 ### 4. 行情维度 - **核心个股涨跌**: highlight=1 个股的实时涨跌幅、换手率 - **资金关注度**: 成交额、换手率反映资金参与程度 - **市值分布**: 核心个股的流通市值分布 - **板块内分化**: 同一主线下不同题材的涨跌分化程度（分化大 → 资金做高低切换） ### 5. 主线识别维度 > 用于「主线分析」和「综合研判」意图 - **主线归类**: 按行业/概念将多个题材聚合为主线（如"科技线"含AI芯片+光通信+PCB+液冷等） - **主线强度**: 主线内题材数量 × 平均排名 × 涨停家数总和 - **内部分化**: 主线内各题材涨跌不一致 → 资金在做方向选择 - **催化共振**: 多个题材共享同一催化事件（如 GTC 大会同时催化光通信、PCB、液冷） - **常见主线框架**: 科技线、新能源线、能源线、金融线、消费线、医药线、制造线、地产线 - 具体归类规则见 `analysis-templates.md` 模板6的"主线识别规则"表 ### 6. 趋势维度 > ⚠️ 此维度输出须标注"AI预测，谨慎参考" - **短期趋势**: 基于涨停家数、热度标签、资金流向综合判断涨跌趋势 - **正面信号**: 涨停家数增加、排名提升、出现"龙头出现"标签等 - **负面信号**: 排名下降、涨停家数为0、标签消失等 ### 7. 风险维度 - **题材持续性**: 新题材(squareTag=1)波动大，热门题材(squareTag=2)可能已充分反映 - **龙头集中度**: 高亮个股过少可能说明题材分散 - **数据掩码**: 个股名含 "\*\*\*" 表示该数据暂不可用 ## Error Handling | 场景 | 处理方式 | |------|---------| | API 返回 code≠20000 | 告知用户"题材数据获取失败，请稍后重试" | | API 返回 code=50000 | 告知用户"该题材数据不存在" | | 题材名称匹配不到 | 展示相近题材列表供用户选择 | | 个股行情获取失败 | 标注"行情数据暂无"，基于题材数据继续分析 | | 个股名含"\*\*\*" | 标注"该个股数据暂不可用" | | 用户问非题材问题 | 明确告知 Skill 适用范围，引导至正确工具 | ## API 调用示例 ### 接口调用 ```bash # 题材库列表 curl -X POST 'https://group-api.itougu.com/teach-hotspot/subject/fullList' \ -H 'Content-Type: application/json' \ -d '{}' # 题材详情 curl -X POST 'https://group-api.itougu.com/teach-hotspot/subject/subjectDetail4Free' \ -H 'Content-Type: application/json' \ -d '{"subjectId": "90000797"}' ``` ### 树状结构解析 ```typescript // 递归解析 tableJson function flattenTree(node: TableJsonNode, level = 0, result: FlatNode[] = []): FlatNode[] { if (node.nodeType === 2) { // 个股节点 result.push({ name: node.name, nodeType: node.nodeType, level, stockCode: node.stockCode, highlight: node.highlight, recommendReason: node.recommendReason, }) } else if (node.nodeType === 1 && level > 0) { // 子分类节点（跳过根节点） result.push({ name: node.name, nodeType: 1, level }) } if (node.children) { node.children.forEach((child) => flattenTree(child, level + 1, result)) } return result } // nodeType 枚举 // 1 = 分类节点 (题材本身或子分类，可嵌套) // 2 = 个股节点 (叶子节点，含stockCode) // 3 = 介绍节点 (推荐理由文本) ``` ### stockCode 格式转换 ```typescript function convertStockCode(stockCode: string) { const [code, market] = stockCode.split('.') return { tencent: `${market}${code}`, // sh600519 eastmoney: `${CEMarket[market]}.${code}`, // 1.600519 akshare: code, // 600519 } } ``` ## Common Mistakes | 错误 | 正确做法 | |------|---------| | 编造不存在的题材数据 | 只基于 API 返回的真实数据分析 | | 忽略 nodeType 直接解析树 | 严格按 nodeType 区分分类/个股/介绍 | | 个股名含"\*\*\*"当作缺失 | 标注"该个股数据暂不可用"而非忽略 | | 给出明确买卖建议 | 所有分析标注"不构成投资建议" | | 忽略 tableJson 的嵌套结构 | 递归解析树，保留层级关系 | | 遗漏风险提示 | 每次分析必须包含 ⚠️ 风险提示 | | 趋势预测未标注 | 必须标注"⚠️ AI预测，谨慎参考" | | 个股行情未标注数据来源 | 必须标注来源（东方财富/AKShare） | | highlight 当作 boolean 判断 | 使用 `highlight === 1` 判断 | | 无条件输出龙头/中军章节 | 仅在 dragonHeadFlag=1 / middleTroopsFlag=1 时输出 | ## Compliance **强制要求**: 1. 不输出虚假、不真实的内容，不编造数据 2. 不向用户提供买卖建议 3. 不预测具体股价或涨跌幅，最多预测涨跌趋势 4. 数据来源必须标注（爱投顾题材库 / 东方财富 / AKShare / Web搜索来源） 5. 每次输出必须包含风险提示："以上分析仅供参考，不构成投资建议，投资有风险，入市需谨慎" 6. 趋势预测内容必须标注"⚠️ AI预测，谨慎参考" 7. 争议性内容提供多角度分析，不做单一结论

path: README.md
content: # 题材库分析师 / A-Share Theme Analyst

> **subject-library** — AI Agent skill for analyzing China A-share market themes (题材) based on real-time data from 爱投顾 (iTougu) Theme Library.

---

## 🇨🇳 简介

基于爱投顾「题材库」数据的 AI 题材分析技能。支持：

- 📊 题材库完整列表浏览与热度排名
- 🔍 单题材深度分析（结构树、龙头/中军、驱动逻辑）
- 📈 核心个股实时行情获取与资金分析
- ⚡ 主线/板块联合分析（跨题材聚合、分化研判）
- 🔗 个股-题材关联查询
- 🤖 AI 综合研判与趋势预测

**适用市场**: 中国 A 股  
**语言**: 技能内容为中文，frontmatter 为英文

---

## 🇺🇸 Overview

AI agent skill for comprehensive analysis of China A-share market themes (题材/concepts/sectors). Built on real-time data from the iTougu Theme Library API.

**Capabilities:**
- Full theme list browsing with heat ranking
- Single theme deep analysis (structure tree, leader stocks, drivers)
- Core stock real-time quotes with fund flow analysis
- Multi-theme "main line" analysis (cross-theme aggregation)
- Stock-to-theme correlation lookup
- AI-powered market insights and trend prediction

**Target Market**: China A-shares only  
**Language**: Skill content in Chinese, metadata in English

---

## 📦 Installation

### Via ClawHub

```bash
npx clawhub@latest install subject-library
```

### Manual

Copy the `subject-library/` folder into your agent's skills directory.

---

## 📁 File Structure

| File | Purpose |
|------|---------|
| `skill.md` | Main skill instructions for AI agent (Chinese) |
| `api-reference.md` | API specifications, field mappings, complete Python scripts |
| `analysis-templates.md` | 6 output templates + scoring system + search integration |
| `README.md` | This file (human-readable introduction) |
| `LICENSE` | MIT-0 license |

---

## 🔒 Security & Data Sources

This skill accesses the following **public, free, no-authentication-required** APIs. All URLs are well-known financial data endpoints used by millions of retail investors in China.

### Primary APIs (Theme Data)

| URL | Provider | Purpose | Auth |
|-----|----------|---------|------|
| `https://group-api.itougu.com/teach-hotspot/subject/fullList` | 爱投顾 (iTougu) | Theme list with rankings | None |
| `https://group-api.itougu.com/teach-hotspot/subject/subjectDetail4Free` | 爱投顾 (iTougu) | Theme detail with stock tree | None |

### Supplementary APIs (Stock Quotes)

| URL | Provider | Purpose | Auth |
|-----|----------|---------|------|
| `http://qt.gtimg.cn/q=...` | 腾讯财经 (Tencent Finance) | Real-time stock quotes (preferred) | None |
| `https://push2.eastmoney.com/api/qt/ulist.np/get` | 东方财富 (East Money) | Stock quotes fallback | None |

### Optional Dependencies

| Package | Purpose | Install |
|---------|---------|---------|
| [AKShare](https://github.com/akfamily/akshare) | Final fallback for stock data | `pip install akshare` |

**No credentials, API keys, or user tokens are required or collected by this skill.**

All external API calls are read-only GET/POST requests to publicly accessible financial data endpoints. No data is sent to any third-party service beyond the query parameters documented above.

---

## ⚠️ Disclaimer

- This skill is for **informational purposes only** and does not constitute investment advice.
- All analysis outputs include mandatory risk disclaimers.
- AI predictions are clearly labeled as such (⚠️ AI预测，谨慎参考).
- Data accuracy depends on upstream API availability.

---

## 📄 License

[MIT-0](./LICENSE) — Free to use, modify, and redistribute. No attribution required.


path: analysis-templates.md
content: # 分析模板 — 题材库 AI 分析框架

本文档提供题材库分析的标准化模板，确保 AI 输出专业、一致、可操作。

---

## 模板 1: 题材全景速览

**触发**: 用户问"有哪些热门题材"、"题材列表"、"今天题材行情"、"今日热点"

### 输出模板

```markdown
# 📊 题材库热点速览

> 数据来源：爱投顾题材库 | {日期}

## 🔥 Top {N} 热门题材

| 排名 | 题材 | 标签 | 涨停家数 | 驱动因素 |
|:---:|------|:---:|:------:|--------|
| 1 | **{name}** | 🔥 热 | {N} 家 | {driven 摘要 ≤25 字} |
| 2 | **{name}** | 🔥 热 | {N} 家 | {driven 摘要} |
| ... | | | | |

## 📌 按运营标签分组

### 今日最热（运营标签）

| 题材 | 驱动因素 |
|------|--------|
| **{name}** | {driven} |
| ... | |

### 持续火热

重点关注：**{题材A}**（{driven摘要}）、**{题材B}**（{driven摘要}）、...

### 🆕 新挖掘题材

{rectangleTag 含"新挖掘"或 squareTag=1 的题材列表}

## 💥 涨停板统计

| 题材 | 涨停家数 |
|------|:------:|
| {name} | {N} 家 |
| ... | |

> 仅展示 upLimitNum > 0 的题材

## 🤖 AI 综合研判
> ⚠️ AI预测，谨慎参考

**今日市场主线：**

1. **{主线A}**：{关联题材列举}，{催化因素}
2. **{主线B}**：{关联题材列举}，{催化因素}
3. ...

**关注信号：**
- 📈 正面：{正面信号}
- 📉 谨慎：{谨慎信号}

---

**统计概览**：共 **{total}** 个活跃题材，其中 **{hot}** 个标记为 🔥 热门，**{N}** 个被标记为"今日最热"，**{M}** 个处于"持续火热"状态。

如需对某个具体题材进行深度分析（如查看关联个股、核心标的行情、结构树等），请告诉我题材名称。

---

⚠️ 以上分析仅供参考，不构成投资建议，投资有风险，入市需谨慎。
数据来源：爱投顾题材库
```

### 数据处理

> 调用 `get_full_list()` 获取题材列表，按 `orderNumber` 排序，用 `defaultdict` 按 `rectangleTag` 分组。详见文末"通用数据处理工具函数"。

---

## 模板 2: 单题材深度分析

**触发**: 用户问"分析 XX 题材"、"XX 概念怎么样"、"XX 板块详情"

### 输出模板

```markdown
# 🔍 题材深度分析：{题材名称}

> 数据来源：爱投顾题材库 | 题材 ID：{subjectId}

## 📌 核心信息

| 维度     | 数据                 |
| -------- | -------------------- |
| 题材名称 | {name}               |
| 驱动因素 | {driven}             |
| 涨停家数 | {upLimitNum}家       |
| 热度标签 | {squareTag 解读}     |
| 运营标签 | {rectangleTag}       |
| 排名     | 第{orderNumber}名    |

## 🌳 题材结构

{解析 tableJson 生成的树状结构}
```

{题材名称}
├── ⭐ {高亮个股 1} ({stockCode})
│   └── 💡 {recommendReason}
├── {普通个股 2} ({stockCode})
└── ...

```

### 结构统计
- 子分类数量: {count_nodeType_1}
- 关联个股数: {count_nodeType_2}
- 核心标的数: {count_highlight_1}

## 📈 核心个股行情
> 数据来源：东方财富 | {日期}

| 个股 | 代码 | 最新价 | 涨跌幅 | 换手率 | 成交额(万) | 流通市值(亿) |
|------|------|--------|--------|--------|-----------|-------------|
| ⭐ {name} | {code} | {price} | {change}% | {turnover}% | {amount} | {cap} |
| ⭐ {name2} | {code2} | {price2} | {change2}% | {turnover2}% | {amount2} | {cap2} |

> 仅展示 highlight=1 的核心个股。如数据通过 AKShare 获取，标注"数据来源：AKShare"。

## 🤖 AI 多维分析

### 1️⃣ 热度评估 — {热度等级}

**评级**: {⭐⭐⭐⭐⭐ / ⭐⭐⭐ / ⭐}

| 指标 | 数值 | 评价 |
|------|------|------|
| 排名位置 | 第{N}名 | {极热/活跃/一般/冷淡} |
| 涨停家数 | {N}家 | {强势/活跃/平淡} |
| 热度标签 | {新/热/无} | {新兴关注/持续热门/稳定状态} |
| 运营标签 | {tag} | {解读} |

**判断**: {综合热度判断，1-2句话}

{仅当 dragonHeadFlag=1 时输出}:
### 2️⃣ 🐉 题材龙头

| 标的 | 代码 | 推荐理由 |
|------|------|---------|
| ⭐ {name} | {code} | {reason} |
| {name} | {code} | {reason} |

{仅当 middleTroopsFlag=1 时输出}:
### 3️⃣ 🛡️ 题材中军

| 标的 | 代码 | 推荐理由 |
|------|------|---------|
| {name} | {code} | {reason} |

{当 dragonHeadFlag=0 且 middleTroopsFlag=0 时，跳过龙头/中军章节}

### N️⃣ 驱动逻辑分析

**核心驱动**: {driven 字段内容}

**驱动分类**:
- [ ] 政策驱动 (政策出台、监管变化)
- [ ] 事件驱动 (突发事件、行业变化)
- [ ] 业绩驱动 (财报超预期、订单放量)
- [ ] 技术驱动 (技术突破、新产品)
- [ ] 资金驱动 (资金持续流入)

**持续性评估**: {基于驱动类型的持续性判断}
- 政策驱动: 通常持续性较强，关注政策落地节奏
- 事件驱动: 短期爆发力强，注意持续性
- 业绩驱动: 需要后续数据验证
- 技术驱动: 关注产品化和商业化进展

### N+1️⃣ 结构特征分析

| 特征 | 数值 | 含义 |
|------|------|------|
| 树广度 | {一级子分类数} | {宽泛/聚焦}的题材 |
| 树深度 | {最大层级} | 产业链{长/短} |
| 个股密度 | {个股数/总节点数} | 投资标的{丰富/稀缺} |
| 高亮比例 | {高亮数/个股数} | 核心标的{明确/分散} |

**结构解读**: {基于以上数据的综合解读}

### N+2️⃣ 个股行情分析

{基于核心个股行情数据的分析}:
- 涨跌表现: {核心个股整体涨跌情况}
- 资金关注: {基于换手率、成交额判断资金参与度}
- 市值分布: {核心个股市值分布特征}

## 📰 市场资讯

| 来源 | 要点 | 时间 |
|------|------|------|
| [{标题}]({url}) | {摘要，≤30字} | {日期} |
| [{标题}]({url}) | {摘要} | {日期} |

> 以上资讯通过网络搜索获取，仅供参考。

## 🔮 趋势预测
> ⚠️ AI预测，谨慎参考

**短期趋势判断**: {基于涨停家数、资金动向、热度标签、驱动因素的综合判断}
**关注信号**:
- 📈 正面: {列出正面信号}
- 📉 负面: {列出负面信号}

**不同观点**:
- 乐观视角: {观点及依据}
- 谨慎视角: {观点及依据}

## 📝 要点总结
1. {核心发现1}
2. {核心发现2}
3. {核心发现3}

## 📖 术语解释
- **{术语}**: {简要解释} — [了解更多]({链接})
- **{术语2}**: {简要解释} — [了解更多]({链接})

## ⚠️ 风险提示

- {基于数据特征的具体风险，不是套话}
- {例如: "该题材部分个股数据暂不可用，分析可能不完整"}
- {例如: "核心标的集中度高，注意个股风险"}
- 以上分析仅供参考，不构成投资建议，投资有风险，入市需谨慎

---
数据来源：爱投顾题材库 | 个股行情：东方财富/AKShare
```

### 数据处理

> 调用 `get_subject_detail(subject_id)` 获取详情，用 `parse_tree()` 递归解析 tableJson。详见文末"通用数据处理工具函数"。

---

## 模板 3: 题材对比分析

**触发**: 用户问"A 和 B 哪个好"、"对比 XX 和 YY"

### 输出模板

```markdown
# ⚡ 题材对比：{题材 A} vs {题材 B}

> 数据来源：爱投顾题材库

## 核心指标对比

|    维度    |      {题材 A}       |      {题材 B}       |   优势方   |
| :--------: | :-----------------: | :-----------------: | :--------: |
|  涨停家数  |  {A.upLimitNum}家   |  {B.upLimitNum}家   |   {多的}   |
|  热度标签  |       {A.tag}       |       {B.tag}       | {🔥>🆕>无} |
|    排名    |  第{A.order}名      |  第{B.order}名      | {靠前的}   |
| 驱动明确度 |   {A.driven 长度}   |   {B.driven 长度}   | {更详细的} |
|  子分类数  |    {A.cat_count}    |    {B.cat_count}    |  {更多的}  |
| 关联个股数 |   {A.stock_count}   |   {B.stock_count}   |  {更多的}  |
| 核心标的数 | {A.highlight_count} | {B.highlight_count} |  {更多的}  |
{仅当至少一方 dragonHeadFlag=1 时}:
|  龙头标识  |       {有/无}       |       {有/无}       |   {有的}   |
{仅当至少一方 middleTroopsFlag=1 时}:
|  中军标识  |       {有/无}       |       {有/无}       |   {有的}   |
|  热度评分  |    {A.score}/100    |    {B.score}/100    |   {高的}   |

## 雷达图描述

{题材 A}: 热度{X}/5, 覆盖面{X}/5, 驱动强度{X}/5, 活跃度{X}/5
{题材 B}: 热度{X}/5, 覆盖面{X}/5, 驱动强度{X}/5, 活跃度{X}/5

## 🤖 综合判断

### {题材 A} 优势
- {列出 A 在哪些维度领先}

### {题材 B} 优势
- {列出 B 在哪些维度领先}

### 结论
{基于数据的综合对比结论，不给买卖建议}

---

⚠️ 以上分析仅供参考，不构成投资建议，投资有风险，入市需谨慎。
数据来源：爱投顾题材库
```

---

## 模板 4: 个股找题材

**触发**: 用户问"XX 股票属于什么题材"、"XX 关联了哪些概念"

### 输出模板

```markdown
# 🔗 个股题材关联：{股票名称}

> 数据来源：爱投顾题材库

## 关联题材列表

| 题材    | 热度 | 涨停  | 该股角色 | 高亮 |
| ------- | :--: | :---: | :------: | :--: |
| {name1} |  🔥  | {N}家 | {核心标的/关联个股} | ⭐/— |
| {name2} |  🆕  | {N}家 | {关联个股} | — |
| ...     |      |       |          |      |

> 角色说明: "核心标的"=该个股在题材中 highlight=1

## 🤖 题材画像

**该个股的题材特征**:

- 涉及 {N} 个题材，属于{广泛关联/聚焦型}个股
- 在 {M} 个题材中被标为核心标的（highlight=1）
- 主要驱动方向: {汇总各题材的 driven}

**题材强度排序**:

1. {最热题材} — {driven}
2. {次热题材} — {driven}
3. ...

---

⚠️ 以上分析仅供参考，不构成投资建议，投资有风险，入市需谨慎。
数据来源：爱投顾题材库
```

### 数据处理

> 调用 `get_full_list()` 遍历所有题材，对每个题材调用 `get_subject_detail()` + `find_stock_in_tree()` 搜索目标个股。详见文末"通用数据处理工具函数"。

> **性能注意**: 个股找题材需要遍历所有题材的 detail，API 调用量大。建议先缩小搜索范围。

---

## 模板 5: 综合市场研判

**触发**: 用户问"今日题材市场分析"、"题材热点总结"

### 输出模板

```markdown
# 📋 题材市场综合研判

> 数据来源：爱投顾题材库 | {日期}

## 一、市场温度

**整体热度**: {极热/偏热/中性/偏冷/极冷}

| 指标         | 数值                      | 含义            |
| ------------ | ------------------------- | --------------- |
| 有涨停题材数 | {有涨停的题材数} / {总数} | 赚钱效应{强/弱} |
| 新题材数量   | {squareTag=1 的数量}      | 新热点{多/少}   |
| 热门题材数量 | {squareTag=2 的数量}      | 持续热点{多/少} |

## 二、热门方向 TOP 3

### 🥇 {第 1 题材}

- 排名第1 | 涨停 {N} 家 | 驱动: {driven}
- 运营标签: {rectangleTag}

### 🥈 {第 2 题材}

- 排名第2 | 涨停 {N} 家 | 驱动: {driven}

### 🥉 {第 3 题材}

- 排名第3 | 涨停 {N} 家 | 驱动: {driven}

## 三、📈 热门题材核心个股行情
> 数据来源：东方财富 | {日期}

| 题材 | 个股 | 代码 | 最新价 | 涨跌幅 | 换手率 |
|------|------|------|--------|--------|--------|
| {theme1} | ⭐ {stock} | {code} | {price} | {change}% | {turnover}% |
| {theme2} | ⭐ {stock} | {code} | {price} | {change}% | {turnover}% |

## 四、🆕 新兴关注

{squareTag=1 的新题材分析}

## 五、📰 市场资讯

| 来源 | 要点 | 时间 |
|------|------|------|
| [{标题}]({url}) | {摘要} | {日期} |

## 六、🤖 AI 综合研判

### 市场风格判断
{基于题材分布判断当前市场是: 题材驱动/业绩驱动/事件驱动/资金驱动}

### 主线梳理
{识别 1-2 条可能的市场主线}

## 七、🔮 整体趋势预测
> ⚠️ AI预测，谨慎参考

**市场题材活跃度趋势**: {基于多维数据的趋势判断}

**不同观点**:
- 乐观视角: {观点}
- 谨慎视角: {观点}

## 八、📝 要点总结
1. {核心发现1}
2. {核心发现2}
3. {核心发现3}

## 九、注意事项
- {具体的风险点}
- {数据局限性说明}

---

⚠️ 以上分析仅供参考，不构成投资建议，投资有风险，入市需谨慎。
数据来源：爱投顾题材库 | 个股行情：东方财富/AKShare
```

---

## 模板 6: 主线/板块联合深度分析

**触发**: 用户问"深入分析科技线"、"新能源板块全面分析"、"分析一下今天的主线"

> 本模板用于**一条主线下多个关联题材**的联合深度分析，与模板2（单题材）和模板3（两两对比）不同。

### 前置操作

```
1. 从 fullList 按主线归类相关题材（见主线识别规则）
2. 批量调用 subjectDetail4Free 获取每个题材详情
3. 跨题材提取全部个股，去重统计
4. 使用 api-reference.md 中的 fetch_quotes() 批量获取行情
5. Web 搜索该主线相关资讯
```

### 输出模板

```markdown
# 🔍 {主线名称}深度分析报告

> 数据来源：爱投顾题材库 + 东方财富行情 + Web资讯 | {日期}

## 📌 {主线名称}全景概览

{主线}覆盖 **{N}大题材**、**{M}只个股**（去重），{一句话描述当前催化/背景}。

| 题材 | 排名 | 运营标签 | 涨停 | 个股数 | 驱动因素 |
|:---:|:---:|:---:|:---:|:---:|---|
| **{name1}** | #{order} | {tag} | {N} | {count} | {driven摘要} |
| **{name2}** | #{order} | {tag} | {N} | {count} | {driven摘要} |
| ... | | | | | |

## 📈 核心个股行情（今日）

> 数据来源：{东方财富/腾讯行情/AKShare} | {M}只个股成功获取行情

### 🟢 涨幅前{N}

| 个股 | 代码 | 最新价 | 涨跌幅 | 换手率 | 成交额(万) | 所属题材 |
|------|------|-------:|------:|------:|----------:|---------|
| **{name}** | {code} | {price} | **{change}%** | {turnover}% | {amount} | {theme} |
| ... | | | | | | |

### 🔴 跌幅前{N}

| 个股 | 代码 | 最新价 | 涨跌幅 | 换手率 | 成交额(万) | 所属题材 |
|------|------|-------:|------:|------:|----------:|---------|
| **{name}** | {code} | {price} | **{change}%** | {turnover}% | {amount} | {theme} |
| ... | | | | | | |

### 📊 行情统计

| 指标 | 数值 |
|------|------|
| 上涨 | **{N}只** ({pct}%) |
| 下跌 | **{N}只** ({pct}%) |
| 平均涨跌幅 | **{avg}%** |
| 总成交额 | **≈{amount}亿** |

## 🤖 AI 深度分析

### 1. 主线内部分化分析
{哪些题材/个股领涨、哪些落后，分析分化原因}

### 2. 核心催化事件解读
> 📰 据{来源}报道
{结合 Web 搜索结果，分析推动主线的核心事件}

### 3. 资金行为分析

| 维度 | 观察 |
|------|------|
| **主力方向** | {资金集中在哪些题材/个股} |
| **换手率** | {整体换手水平及含义} |
| **龙头表现** | {主线龙头个股表现} |
| **整体特征** | {概括性描述} |

### 4. 题材结构特征

| 结构维度 | 分析 |
|------|------|
| **{题材A}** | {有无龙头/中军标识，个股数，结构特点} |
| **{题材B}** | {同上} |
| ... | |

### 5. 跨题材个股重叠分析
{同一个股出现在多个题材中的情况，交叉关联度}

## 🔮 趋势预测
> ⚠️ AI预测，谨慎参考

**短期趋势判断**: {主线整体方向判断}

**关注信号**:
📈 **正面**: {列出}
📉 **谨慎**: {列出}

**不同观点**:
- 乐观视角: {观点及依据}
- 谨慎视角: {观点及依据}

## 📝 要点总结
1. {核心发现1}
2. {核心发现2}
3. {核心发现3}
4. {核心发现4}

---

⚠️ 以上分析仅供参考，不构成投资建议，投资有风险，入市需谨慎。

数据来源：爱投顾题材库 | 个股行情：{数据来源} | 资讯：{资讯来源列表}
```

### 主线识别规则

将题材归类到主线时，参考以下常见主线框架：

| 主线 | 典型题材关键词 |
|------|-------------|
| 科技线 | AI、芯片、光通信、CPO、半导体、PCB、服务器、闪存、DeepSeek |
| 新能源线 | 锂电池、光伏、风电、储能、充电桩、新能源车 |
| 能源线 | 天然气、煤炭、石油、电力、智能电网、煤电一体化 |
| 金融线 | 大金融、银行、券商、保险、跨境支付 |
| 消费线 | 食品饮料、白酒、零售、旅游、免税 |
| 医药线 | 医药、中药、生物医药、医疗器械、创新药 |
| 制造线 | 军工、航空航天、机器人、工业母机、高端制造 |
| 地产线 | 房地产、物业、建材、装修 |

> 以上仅为参考框架，实际归类应结合当日题材的 driven 字段和 rectangleTag 灵活判断。一个题材可能属于多条主线。

### 数据处理

> 调用 `get_full_list()` 按主线关键词筛选题材，批量 `get_subject_detail()` + `extract_stocks()` 提取跨题材个股并去重，用 `api-reference.md` 的 `fetch_quotes()` 获取行情。详见文末"通用数据处理工具函数"。

---

## 分析维度评分体系

### 热度评分 (0-100)

| 维度 | 权重 | 评分规则 |
|------|:---:|---------|
| orderNumber 排名 | 40% | 前10=40, 前30=25, 前50=15, 其他=5 |
| 涨停家数 upLimitNum | 30% | min(num × 10, 30) |
| 热度标签 squareTag | 15% | 2(热)=15, 1(新)=10, 0=0 |
| rectangleTag | 10% | 非空=10, 空=0 |
| 龙头+中军标识 | 5% | dragonHeadFlag=1 → +2.5, middleTroopsFlag=1 → +2.5 |

> 评分函数 `heat_score()` 实现见文末"通用数据处理工具函数"。

### 结构评分 (0-100)

| 维度 | 权重 | 评分规则 |
|------|:---:|---------|
| 子分类数 | 25% | min(count × 5, 25) |
| 个股总数 | 25% | min(count × 2, 25) |
| 高亮个股数 | 25% | min(count × 8, 25) |
| 树深度 | 15% | min(depth × 5, 15) |
| 有推荐理由 | 10% | reasonShowFlag=1 → 10, 否则 0 |

### 综合评级

| 评分 | 等级 | 含义 |
|------|------|------|
| 80-100 | ⭐⭐⭐⭐⭐ | 极高关注度，可能是当前市场主线 |
| 60-79 | ⭐⭐⭐⭐ | 高关注度，活跃题材 |
| 40-59 | ⭐⭐⭐ | 中等关注度，值得跟踪 |
| 20-39 | ⭐⭐ | 较低关注度，暂时平淡 |
| 0-19 | ⭐ | 低关注度，可能已退潮 |

---

## Web 搜索集成

分析过程中可通过网络搜索补充最新市场资讯。

### 搜索触发

- 单题材深度分析 (模板2) → 自动搜索相关资讯
- 主线联合分析 (模板6) → 搜索主线相关催化事件
- 综合市场研判 (模板5) → 搜索热门题材的最新动态

### 搜索工具选择

1. 优先使用环境已有的搜索工具（如 `web_search`、`websearch` 等）
2. 若无可用搜索工具 → 提示用户安装 multi-search-engine 技能:
   > 建议安装网络搜索技能以获取最新资讯。
   > 安装方式: 先安装 SkillHub 商店 (https://skillhub-1388575217.cos.ap-guangzhou.myqcloud.com/install/skillhub.md)，然后安装 multi-search-engine 技能。

### 搜索策略

| 意图 | 搜索关键词 | 用途 |
|------|-----------|------|
| 单题材分析 | "{题材名} 最新消息 分析" | 补充驱动因素的市场背景 |
| 综合研判 | "A股 题材热点 {日期}" | 获取当日市场热点概览 |
| 术语解释 | "{术语} 股票 含义" | 为用户提供术语解释链接 |

### 引用格式

所有 Web 搜索结果必须标注来源：
- 行内引用: `根据 [文章标题](URL) 报道，...`
- 表格引用: `| [标题](URL) | 要点摘要 | 日期 |`

---

## 失败处理模板

### API 调用失败

```markdown
⚠️ 数据获取失败

题材库数据暂时无法获取，可能原因：

1. 非交易时间，数据未更新
2. 服务暂时不可用

**建议**: 请稍后重试，或指定具体题材名称缩小查询范围。
```

### 题材名称匹配失败

```markdown
🔍 未找到完全匹配的题材: "{用户输入}"

**相似题材**:
| 题材 | 相似度 |
|------|:-----:|
| {match1} | 高 |
| {match2} | 中 |
| {match3} | 低 |

您想查看以上哪个题材的详情？
```

### 数据不完整

```markdown
ℹ️ 部分数据受限

以下分析基于当前可用数据，部分内容可能受限：
- {N} 只个股数据暂不可用（显示为 ***）
- 个股详细行情数据通过东方财富/AKShare 补充获取

如数据缺失较多，建议缩小分析范围或稍后重试。
```

### 个股行情获取失败

```markdown
ℹ️ 个股行情数据获取失败

东方财富接口暂时无法访问，已尝试 AKShare 备用数据源。

| 个股 | 代码 | 行情状态 |
|------|------|---------|
| {name} | {code} | ❌ 暂无数据 |

**建议**: 稍后重试，或手动查询个股行情。
```

---

## 通用数据处理工具函数

以下函数供各模板的数据处理环节调用。行情获取使用 `api-reference.md` 中的 `fetch_quotes()` 统一脚本。

```python
import requests

BASE_URL = "https://group-api.itougu.com"
HEADERS = {"Content-Type": "application/json"}

# ===== API 调用 =====

def get_full_list():
    """获取题材库全量列表，按 orderNumber 排序"""
    resp = requests.post(f"{BASE_URL}/teach-hotspot/subject/fullList",
                         json={}, headers=HEADERS)
    result = resp.json()
    if result["code"] != 20000:
        raise Exception(f"fullList 错误: {result.get('msg', '未知')}")
    return sorted(result["data"]["rows"], key=lambda x: x.get("orderNumber", 999))

def get_subject_detail(subject_id):
    """获取单个题材详情"""
    resp = requests.post(f"{BASE_URL}/teach-hotspot/subject/subjectDetail4Free",
                         json={"subjectId": subject_id}, headers=HEADERS)
    result = resp.json()
    if result["code"] == 50000:
        return None  # 数据不存在
    if result["code"] != 20000:
        raise Exception(f"detail 错误: {result.get('msg', '未知')}")
    return result["data"]

# ===== 树状结构解析 =====

def parse_tree(node, level=0, stats=None):
    """递归解析 tableJson，统计分类/个股/高亮/掩码数"""
    if stats is None:
        stats = {'categories': 0, 'stocks': 0, 'highlights': 0,
                 'masked': 0, 'max_depth': 0}
    if node.get("nodeType") == 1 and level > 0:
        stats['categories'] += 1
    elif node.get("nodeType") == 2:
        stats['stocks'] += 1
        if node.get("highlight") == 1:
            stats['highlights'] += 1
        if '***' in (node.get("name") or ''):
            stats['masked'] += 1
    stats['max_depth'] = max(stats['max_depth'], level)
    for child in (node.get("children") or []):
        parse_tree(child, level + 1, stats)
    return stats

def extract_stocks(node, theme_name, result_dict):
    """递归提取个股到 result_dict，支持跨题材去重"""
    if node.get("nodeType") == 2 and node.get("stockCode"):
        sc = node["stockCode"]
        if sc not in result_dict:
            result_dict[sc] = {'name': node['name'], 'themes': [], 'highlight': 0}
        result_dict[sc]['themes'].append(theme_name)
        if node.get('highlight') == 1:
            result_dict[sc]['highlight'] = 1
    for child in (node.get("children") or []):
        extract_stocks(child, theme_name, result_dict)

def find_stock_in_tree(node, target):
    """在树中搜索目标个股（按名称或代码），返回 (found, is_highlight)"""
    if node.get("nodeType") == 2:
        name = node.get("name", "")
        code = (node.get("stockCode") or "").split(".")[0]
        if target in name or target == code:
            return True, node.get("highlight") == 1
    for child in (node.get("children") or []):
        found, highlighted = find_stock_in_tree(child, target)
        if found:
            return True, highlighted
    return False, False

# ===== 热度评分 =====

def heat_score(subject_item, detail=None):
    """计算题材热度评分 (0-100)"""
    score = 0
    order = subject_item.get("orderNumber", 999)
    if order <= 10: score += 40
    elif order <= 30: score += 25
    elif order <= 50: score += 15
    else: score += 5
    score += min(subject_item.get("upLimitNum", 0) * 10, 30)
    tag = subject_item.get("squareTag", 0)
    if tag == 2: score += 15
    elif tag == 1: score += 10
    if subject_item.get("rectangleTag"): score += 10
    if detail:
        if detail.get("dragonHeadFlag") == 1: score += 2.5
        if detail.get("middleTroopsFlag") == 1: score += 2.5
    return min(score, 100)
```


path: api-reference.md
content: # API Reference — 题材库数据接口

本文档记录题材库 Skill 依赖的 API 接口完整规格，包含爱投顾题材库接口和个股行情补充数据源。

## 服务信息

- **服务名**: `teach-hotspot`
- **Base URL**: `https://group-api.itougu.com`
- **请求方式**: 所有爱投顾接口均为 **POST**
- **Content-Type**: `application/json`
- **响应标准**: `{ code: number, data: any, msg?: string }`，code=20000 表示成功

---

## 1. 题材库列表 — fullList

### 基本信息

| 项 | 值 |
|---|---|
| 端点 | `POST /teach-hotspot/subject/fullList` |
| 认证 | 无需认证 |
| Content-Type | `application/json` |
| 请求体 | `{}`（空对象即可） |

### 调用示例

```bash
curl -X POST 'https://group-api.itougu.com/teach-hotspot/subject/fullList' \
  -H 'Content-Type: application/json' \
  -d '{}'
```

### 响应结构

```typescript
interface FullListResponse {
  code: number       // 20000=成功
  data: {
    rows: SubjectItem[]
  }
  msg?: string
}

interface SubjectItem {
  subjectId: string       // 题材唯一标识，如 "90000797"
  name: string            // 题材名称，如 "锂电池"、"光伏"、"ST股"
  driven: string | null   // 驱动因素描述文本
    //   如 "科研团队研制出用于高能量密度与低温电池的氢氟烃电解液"
    //   可能为 null
  squareTag: number       // 方形标签
    //   0 = 无标签
    //   1 = "新" (新题材)
    //   2 = "热" (热门题材)
  rectangleTag: string | null  // 运营自定义标签（无固定范围）
    //   已知值: 龙头出现, 中军出现, 新挖掘题材, 主线,
    //          火热关注, 持续火热, 两天领涨, 今日最热
    //   运营可随时新增或调整，不做枚举限制
  updateTime: string | null    // 最后更新时间, ISO格式
    //   如 "2026-03-19T10:30:00"
    //   注意: 大量题材此字段为 null
  upLimitNum: number      // 涨停家数
    //   0 = 无涨停
    //   >0 = 该题材中有N只股票涨停
  orderNumber: number     // 排序序号（反映热度排名）
    //   值越小越热门，如 1=最热
}
```

### 字段说明

**排名标签 (squareTag)**:

- `squareTag === 1` → 显示"新"标签（新出现的题材）
- `squareTag === 2` → 显示"热"标签（持续热门题材）
- 其他 → 无特殊标签

**排序 (orderNumber)**:

- 该字段由运营/算法决定，反映题材的综合热度排名
- 值越小排名越靠前，如 orderNumber=1 为当前最热题材
- 可作为热度评估的主要参考指标

**驱动因素 (driven)**:

- 可能为 null
- 非空时描述该题材的核心驱动事件或逻辑

---

## 2. 题材详情 — subjectDetail4Free

### 基本信息

| 项 | 值 |
|---|---|
| 端点 | `POST /teach-hotspot/subject/subjectDetail4Free` |
| 认证 | 无需认证 |
| Content-Type | `application/json` |
| 请求体 | `{ "subjectId": "题材ID" }` |

### 调用示例

```bash
curl -X POST 'https://group-api.itougu.com/teach-hotspot/subject/subjectDetail4Free' \
  -H 'Content-Type: application/json' \
  -d '{"subjectId": "90000797"}'
```

### 响应结构

```typescript
interface SubjectDetailResponse {
  code: number       // 20000=成功, 50000=数据不存在
  data: SubjectDetail
  msg?: string
}

interface SubjectDetail {
  // === 导航信息 ===
  navi: NaviNode               // 题材导航树（面包屑）

  // === 核心数据 ===
  tableJson: TableJsonNode     // 树状表格数据（最重要）
  driven: string               // 驱动因素文本

  // === 标志位 ===
  reasonShowFlag: number       // 0=不显示推荐理由, 1=显示
  middleTroopsFlag: number     // 0=无, 1=有"题材中军"分类
  dragonHeadFlag: number       // 0=无, 1=有"题材龙头"分类
  
  // === 以下字段存在于响应中但不应使用 ===
  // serviceEndTime, shareClaim, authorizationOrderId,
  // opStatus, currRoleType, orderInterval
}

// === 导航树 ===
interface NaviNode {
  subjectId: string
  subjectName: string
  children: NaviNode[] | null  // 子题材导航，可能为 null
}

// === 树状表格（核心数据结构）===
interface TableJsonNode {
  subjectId: string | null     // 分类节点有值，个股节点为 null
  nodeType: 1 | 2 | 3
  // nodeType = 1: 分类节点
  //   → 题材本身或子分类，可嵌套
  //   → 有 subjectId, name, children
  // nodeType = 2: 个股节点
  //   → 叶子节点，含 stockCode
  //   → 有 stockCode, name, highlight, recommendReason
  // nodeType = 3: 介绍节点（推荐理由文本）
  //   → 有 content

  name: string                 // 节点名称

  // 个股节点(nodeType=2)相关
  stockCode: string | null     // 股票代码, 格式 "600519.sh" 或 "002230.sz"
    // 含 "***" 表示该数据暂不可用
  highlight: number | null     // 0=普通, 1=核心标的（高亮）
  recommendReason: string | null  // 推荐理由

  // 介绍节点(nodeType=3)相关
  content?: string             // 介绍文本

  // 通用
  children: TableJsonNode[] | null  // 子节点
}
```

### stockCode 格式

题材库 API 返回的 stockCode 格式为 `代码.小写市场后缀`：

```
600519.sh  →  贵州茅台 (上海)
002230.sz  →  科大讯飞 (深圳)
300750.sz  →  宁德时代 (深圳创业板)
688256.sh  →  寒武纪 (上海科创板)
```

**市场字典 (CEMarket)**:

```typescript
const CEMarket: Record<string, number> = {
  sz: 0,  // 深圳
  sh: 1,  // 上海
  hk: 2,  // 香港
  sf: 3,  sc: 4,  dc: 5,  zc: 6,
  bj: 7,  // 北京
}
```

### 树状结构示例

**扁平结构**（当前生产数据主流）:

```
ST股 (nodeType=1, 根节点, subjectId="90000797")
├── [nodeType=2] *ST中润 (000506.sz) highlight=0
│   推荐理由: "公司回复交易所问询函；控股公司斐济瓦图科拉金矿..."
├── [nodeType=2] *ST景峰 (000908.sz) highlight=1 ⭐
│   推荐理由: "法院决定对公司启动预重整"
├── [nodeType=2] ST春天 (600381.sh) highlight=1 ⭐
│   推荐理由: "冬虫夏草产业化龙头企业，回复交易所问询函"
├── [nodeType=2] *ST博信 (600083.sh) highlight=0
│   推荐理由: "苏州国资委旗下..."
└── ... (共37只个股)
```

**嵌套分类结构**（较少见但需支持）:

```
题材 (nodeType=1, 根节点)
├── 个股A (nodeType=2)
├── 分类A (nodeType=1)
│   ├── 个股B (nodeType=2)
│   └── 个股C (nodeType=2)
└── 分类B (nodeType=1)
    ├── 分类C (nodeType=1)
    │   ├── 个股D (nodeType=2)
    │   └── 个股E (nodeType=2)
    └── 分类D (nodeType=1)
        └── 个股F (nodeType=2)
```

> 注: nodeType=1 代表分类节点（可嵌套），nodeType=2 代表个股节点（叶子）。

### 个股分类说明

题材详情中的个股通过标志位区分角色（仅在标志位=1时有效）：

| 分类 | 标志位 | 说明 |
|------|--------|------|
| 题材个股 | 默认存在 | 该题材的所有关联个股 |
| 题材中军 | `middleTroopsFlag=1` | 题材中的中坚力量个股（仅当标志位=1时输出） |
| 题材龙头 | `dragonHeadFlag=1` | 题材中的领军龙头个股（仅当标志位=1时输出） |

---

## 3. 补充数据源 — 个股行情

题材库 API 返回的是题材结构和关联个股列表，但**不包含个股实时行情数据**（最新价、涨幅等）。需通过以下数据源补充。

### ⚠️ 行情获取决策路径（必读）

```
始终使用 Python 获取行情（不要用 curl/bash 循环）
    ↓
首选: 腾讯行情 API (qt.gtimg.cn) — 最稳定，支持批量，无频率限制
    ↓ 返回空数据（非交易时间或接口异常）
Fallback: 东方财富个股快照 API (push2.eastmoney.com) — 有频率限制
    ↓ 也失败
Fallback: AKShare Python 库 — 需要 pip install
    ↓ 全部失败
标注"行情数据暂无"，基于题材数据继续分析
```

**关键注意事项**:
- **非交易时间**（休市、节假日）：腾讯 API 可能返回空数据，这是正常行为
- **频率限制**：东方财富 push2 接口高频调用（>5次/秒）会返回空数据
- **编码问题**：腾讯 API 返回 GBK 编码，必须用 Python 处理（不要用 curl 管道）
- **始终用 Python**：涉及 GBK 解码、批量处理、JSON 解析，bash/curl 容易出错

### 3.1 数据源字段映射速查

> 完整的获取逻辑见 3.2 节统一脚本。以下仅为字段映射参考。

**腾讯行情 API**（首选，`http://qt.gtimg.cn/q={市场}{代码}`，GBK 编码，`~` 分隔）:

| 索引 | 字段 | 索引 | 字段 |
|:---:|------|:---:|------|
| 1 | 股票名称 | 31 | 涨跌额 |
| 2 | 股票代码 | 32 | 涨跌幅(%) |
| 3 | 最新价 | 33 | 最高价 |
| 4 | 昨收价 | 34 | 最低价 |
| 5 | 开盘价 | 37 | 成交额(万) |
| 6 | 成交量(手) | 38 | 换手率(%) |
| 44 | 流通市值(亿) | 45 | 总市值(亿) |

**东方财富 API**（Fallback，`push2.eastmoney.com`，JSON 格式）:

| 字段 | 含义 | 字段 | 含义 |
|------|------|------|------|
| f2 | 最新价 | f14 | 名称 |
| f3 | 涨跌幅(%) | f12 | 代码 |
| f6 | 成交额 | f8 | 换手率(%) |
| f20 | 总市值 | f21 | 流通市值 |

> ⚠️ 东方财富 push2 接口高频调用（>5次/秒）可能返回空数据。

**AKShare**（最终 Fallback，`pip install akshare`）:
- `ak.stock_zh_a_spot_em()` — A 股实时行情（全部），字段：代码, 名称, 最新价, 涨跌幅, 换手率, 成交额, 流通市值 等
- `ak.stock_board_concept_cons_em(symbol="概念名")` — 概念板块成分股
- `ak.stock_zh_a_hist(symbol="300750", period="daily", adjust="qfq")` — 个股历史K线
- ⚠️ 底层调用东方财富，高频请求触发 IP 限制，建议间隔 ≥ 200ms

### 3.2 完整行情获取脚本（推荐直接使用）

以下 Python 脚本覆盖**批量获取 + 自动 fallback + 格式转换**全流程，可直接复制运行：

```python
import urllib.request
import json
import time

# ========== stockCode 格式转换 ==========
CE_MARKET = {'sz': 0, 'sh': 1, 'hk': 2, 'sf': 3, 'sc': 4, 'dc': 5, 'zc': 6, 'bj': 7}

def convert_stock_code(stock_code):
    """题材库 stockCode 转各平台格式
    输入: '600519.sh' → 输出: {'tencent': 'sh600519', 'eastmoney': '1.600519', 'akshare': '600519'}
    """
    code, market = stock_code.split('.')
    return {
        'tencent': f'{market}{code}',
        'eastmoney': f'{CE_MARKET.get(market, 0)}.{code}',
        'akshare': code,
        'display': code,
    }

# ========== 腾讯 API（首选） ==========
def fetch_quotes_tencent(stock_codes, batch_size=30):
    """批量获取行情（腾讯 API）
    stock_codes: 题材库格式列表，如 ['600519.sh', '002230.sz']
    返回: {stock_code: {name, code, price, change, turnover, amount, cap, total_cap, ...}}
    """
    results = {}
    tencent_codes = []
    code_map = {}  # tencent_code -> original_code

    for sc in stock_codes:
        if '***' in sc:
            continue
        converted = convert_stock_code(sc)
        tencent_codes.append(converted['tencent'])
        code_map[converted['tencent']] = sc

    # 分批请求（每批 ≤ batch_size）
    for i in range(0, len(tencent_codes), batch_size):
        batch = tencent_codes[i:i+batch_size]
        url = f'http://qt.gtimg.cn/q={",".join(batch)}'
        try:
            resp = urllib.request.urlopen(url, timeout=10).read().decode('gbk')
            for line in resp.strip().split('\n'):
                if '=' not in line or '"' not in line:
                    continue
                parts = line.split('"')
                if len(parts) < 2:
                    continue
                data = parts[1].split('~')
                if len(data) < 46 or not data[3]:
                    continue  # 空数据（非交易时间）
                # 找回原始 stock_code
                tc = line.split('=')[0].split('_')[-1].strip()
                orig = code_map.get(tc, tc)
                try:
                    results[orig] = {
                        'name': data[1],
                        'code': data[2],
                        'price': float(data[3]) if data[3] else 0,
                        'change_pct': float(data[32]) if data[32] else 0,
                        'change_amt': float(data[31]) if data[31] else 0,
                        'turnover': float(data[38]) if data[38] else 0,
                        'amount_wan': float(data[37]) if data[37] else 0,  # 万元
                        'high': float(data[33]) if data[33] else 0,
                        'low': float(data[34]) if data[34] else 0,
                        'open': float(data[5]) if data[5] else 0,
                        'prev_close': float(data[4]) if data[4] else 0,
                        'cap': float(data[44]) if data[44] else 0,  # 流通市值(亿)
                        'total_cap': float(data[45]) if data[45] else 0,  # 总市值(亿)
                        'pe': data[39],
                        'source': '腾讯行情',
                    }
                except (ValueError, IndexError):
                    continue
        except Exception as e:
            print(f'腾讯API批次{i//batch_size+1}失败: {e}')
            continue
        if i + batch_size < len(tencent_codes):
            time.sleep(0.1)  # 批次间隔

    return results

# ========== 东方财富 API（Fallback） ==========
def fetch_quotes_eastmoney(stock_codes):
    """批量获取行情（东方财富 API）— 腾讯失败时使用
    stock_codes: 题材库格式列表
    """
    results = {}
    secids = []
    code_map = {}

    for sc in stock_codes:
        if '***' in sc:
            continue
        converted = convert_stock_code(sc)
        secids.append(converted['eastmoney'])
        code_map[converted['eastmoney']] = sc

    url = (f'https://push2.eastmoney.com/api/qt/ulist.np/get?fltt=2&invt=2'
           f'&fields=f2,f3,f4,f5,f6,f7,f8,f9,f12,f14,f15,f16,f17,f18,f20,f21'
           f'&secids={",".join(secids)}')
    try:
        req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
        resp = urllib.request.urlopen(req, timeout=10).read().decode('utf-8')
        data = json.loads(resp)
        if data.get('data') and data['data'].get('diff'):
            for item in data['data']['diff']:
                code = item.get('f12', '')
                name = item.get('f14', '')
                # 找回原始 stock_code
                for secid, orig in code_map.items():
                    if secid.endswith(f'.{code}'):
                        try:
                            results[orig] = {
                                'name': name,
                                'code': code,
                                'price': float(item.get('f2', 0)) if item.get('f2') != '-' else 0,
                                'change_pct': float(item.get('f3', 0)) if item.get('f3') != '-' else 0,
                                'change_amt': float(item.get('f4', 0)) if item.get('f4') != '-' else 0,
                                'turnover': float(item.get('f8', 0)) if item.get('f8') != '-' else 0,
                                'amount_wan': float(item.get('f6', 0)) / 10000 if item.get('f6') not in ['-', None] else 0,
                                'cap': float(item.get('f21', 0)) / 100000000 if item.get('f21') not in ['-', None] else 0,
                                'total_cap': float(item.get('f20', 0)) / 100000000 if item.get('f20') not in ['-', None] else 0,
                                'source': '东方财富',
                            }
                        except (ValueError, TypeError):
                            continue
                        break
    except Exception as e:
        print(f'东方财富API失败: {e}')

    return results

# ========== 统一入口（自动 Fallback） ==========
def fetch_quotes(stock_codes):
    """获取个股行情 — 自动 fallback
    stock_codes: 题材库格式列表，如 ['600519.sh', '002230.sz']
    返回: {stock_code: {name, code, price, change_pct, turnover, amount_wan, cap, source, ...}}
    """
    if not stock_codes:
        return {}

    # 1. 首选腾讯
    results = fetch_quotes_tencent(stock_codes)
    if results:
        return results

    print('腾讯API无数据（可能非交易时间），尝试东方财富...')

    # 2. Fallback 东方财富
    results = fetch_quotes_eastmoney(stock_codes)
    if results:
        return results

    print('东方财富也无数据，尝试 AKShare...')

    # 3. 最终 Fallback: AKShare
    try:
        import akshare as ak
        df = ak.stock_zh_a_spot_em()
        target_codes = [convert_stock_code(sc)['akshare'] for sc in stock_codes if '***' not in sc]
        filtered = df[df['代码'].isin(target_codes)]
        for _, row in filtered.iterrows():
            for sc in stock_codes:
                if sc.split('.')[0] == row['代码']:
                    results[sc] = {
                        'name': row['名称'],
                        'code': row['代码'],
                        'price': float(row['最新价']) if row['最新价'] else 0,
                        'change_pct': float(row['涨跌幅']) if row['涨跌幅'] else 0,
                        'turnover': float(row['换手率']) if row['换手率'] else 0,
                        'amount_wan': float(row['成交额']) / 10000 if row['成交额'] else 0,
                        'cap': float(row['流通市值']) / 100000000 if row['流通市值'] else 0,
                        'source': 'AKShare',
                    }
                    break
    except ImportError:
        print('AKShare 未安装 (pip install akshare)')
    except Exception as e:
        print(f'AKShare失败: {e}')

    return results

# ========== 使用示例 ==========
if __name__ == '__main__':
    # 从题材详情提取的 stockCode 列表
    codes = ['600519.sh', '002230.sz', '300750.sz', '688256.sh']
    quotes = fetch_quotes(codes)
    for sc, q in quotes.items():
        print(f'{q["name"]}({q["code"]}): {q["price"]}元 {q["change_pct"]:+.2f}% '
              f'换手{q["turnover"]:.2f}% 成交{q["amount_wan"]:.0f}万 [{q["source"]}]')
```

> **使用方式**: 直接将上述脚本复制到 Python 环境执行，或拆取 `fetch_quotes()` 函数在分析流程中调用。
> 传入题材库格式的 stockCode 列表，自动处理格式转换、批量请求、fallback 和异常。

### 3.3 stockCode 格式转换（快速参考）

> 完整转换逻辑已包含在 3.2 节脚本的 `convert_stock_code()` 函数中。以下为快速参考表：

| 题材库格式 | 腾讯格式 | 东方财富 secid | AKShare 格式 |
|-----------|----------|---------------|-------------|
| `600519.sh` | `sh600519` | `1.600519` | `600519` |
| `002230.sz` | `sz002230` | `0.002230` | `002230` |
| `300750.sz` | `sz300750` | `0.300750` | `300750` |
| `688256.sh` | `sh688256` | `1.688256` | `688256` |
| `301118.sz` | `sz301118` | `0.301118` | `301118` |

---

## 4. 错误码

| code | 含义 |
|------|------|
| 20000 | 成功 |
| 50000 | 数据不存在 |
| 其他 | 业务错误 |

> 注: 以上错误码仅适用于爱投顾接口。东方财富、腾讯、AKShare 等第三方数据源的错误码以各自文档为准。

### 特殊数据说明

| 数据特征 | 含义 |
|---------|------|
| `stockCode` 含 `***` | 该个股数据暂不可用 |
| `updateTime` 为 null | 该题材暂无更新时间记录，以 orderNumber 判断热度 |
| `driven` 为 null | 该题材暂无驱动因素描述 |
| `navi.children` 为 null | 该题材无子题材导航 |
| `highlight` 为 null 或 0 | 非核心标的；highlight=1 为核心标的 |


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)