Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Security scan passed
Scanned at: 2026-08-13T11:12:48
Tool: gitleaks + pattern-based validation
Content hash: e18d4a8dc35e1e45b86649e751b8b6f9cb9b23d83a4088c66b9cd4c11cf56a87
109 changes: 109 additions & 0 deletions daymade-financial/daymade-sector-research/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
---
name: daymade-sector-research
description: |-
A股行业投研工作流:全板块 Top N 涨幅标的计算、公告窗口检索(周/月)、市场情绪证据分级判断,并以 Agent Team 并行执行 + fresh-context 对抗验证。

触发场景(命中任一即读本 skill):
- 「XX 行业 Top N / Top 10 标的」(如「医药行业今天的 Top 10 标的」)
- 「这些标的最近一周 / 一个月发过哪些公告」
- 「判断 XX 行业 / 板块现在的市场情绪怎么样」
- 「用 Agent Team / 多 agent 做行业投研」或要求对行业研究结论做对抗性验证
- 需要「基于证据、基于数据」的板块级研究交付(成分股 → 行情 → 公告 → 情绪 → 验证 → 报告)

核心能力:东财 push2 成分股 → 新浪实时快照涨幅排序(scripts/top_n_pipeline.py);巨潮 cninfo + 东财公告双源交叉,沪深+北交所统一通道(scripts/ann_query.py);情绪证据 L1(一手行情)/L2(带时间戳媒体)/L3(未核实标题)分级;Agent Team 并行编排与验证纪律。全程国内公开数据源,无付费依赖;Gangtise 官方 skill 为可选增强(需积分,缺失时走公开源 pivot)。

最高纪律(用户原话):没有十足把握的事,宁可标注不确定,不可给错误答案。
---

# A股行业投研 Skill

对某个申万行业/东财板块做一次完整投研交付:**Top N 涨幅标的 → 公告窗口检索 → 市场情绪判断 → Agent Team 对抗验证 → 综合报告**。

## 铁律(每次执行都必须遵守,违反代价最高)

1. **宁可标注不确定,不可给错误答案**(用户原话,最高纪律)。没有十足把握的事实写「不确定/未核实」,不编、不猜、不省略来源。推断与观察必须分开表述。
2. **基于证据、基于数据**。每个结论 trace 到一手数据源(API 返回 / CSV 落盘 / 官方公告);汇报数值时从工具输出原文照抄,禁凭印象转写。
3. **证据分级 L1–L3**:L1 一手行情(交易所/行情接口实时值);L2 带时间戳的媒体/公告报道;L3 未核实标题或传闻。判断情绪时只允许 L1/L2 承重,L3 只能作为「待核实线索」列出。
4. **0 条双向读**:月窗口公告 0 条 ≠ 真无公告。必须扩宽窗(90 天)+ 第二数据源核对,证明「真无」或发现参数错误,才能下结论。
5. **双源交叉**:公告检索必须巨潮 + 东财两源对照;单一数据源发现的「重要公告」也要在另一源确认存在,不一致必须如实标注。
6. **盘中快照标注漂移**:盘中取的行情数值是瞬时快照会漂移,任何引用必须带快照时间戳,报告里注明「盘中快照」。
7. **数值照抄落盘 CSV**:中间数值必须落盘(脚本输出 CSV / agent 落盘文件),报告引用时照抄 CSV 值,不凭对话记忆。
8. **Agent Team 编排纪律**:见 [references/agent-orchestration.md](references/agent-orchestration.md)——子代理显式 `model:'sonnet'`;SendMessage 交付协议;每条 finding 带可证伪锚点;验证用 fresh-context 对抗性 agent;禁 spawn 重复 agent。

## 工作流(五阶段)

```
Phase 0 数据能力侦察 → 必要时 pivot 公开源
Phase 1 并行三 agent:Top N 名单 / 涨跌幅分桶分布 / 情绪证据清单
Phase 2 公告检索:Top N 全标的 × 周窗口 + 月窗口,双源交叉
Phase 3 对抗验证:fresh-context agent 复核假设(用户原话:「看哪些假设是错的」)
Phase 4 综合报告:名单 + 公告 + 情绪分级 + 显式不确定标注
```

### Phase 0 — 数据能力侦察(Gangtise pivot 决策)

若用户点名 Gangtise(或其官方 skill),先侦察可用性再决定数据源:

1. **对照实验判「额度」**:同一凭据某些端点可用(如 `quote.py`、`stockpool.py`、`get_industries.py`)而内容搜索端点全报 `POINT_NOT_ENOUGH` → 这是积分不足的整体性解释,同一凭据一通一挂已否定「网络/配置问题」;若不同端点表现不一致,别急着下「额度耗尽」结论,做对照实验(换端点/换参数/最小请求)。
2. **pivot 决策表**:内容搜索不可用 → Top N 改东财成分股+新浪快照;公告改 cninfo+东财;情绪改公开行情+媒体。侦察结论与 pivot 决策**必须告知用户**,不静默切换数据源。
3. 完整侦察矩阵(各端点实测形态、积分报错、对照实验)→ [references/gangtise-scout.md](references/gangtise-scout.md)

### Phase 1 — 并行三 agent

派 3 个并行 agent(显式 sonnet),每个 prompt 附可证伪锚点要求:

| Agent | 交付物 | 数据链 |
|---|---|---|
| Top N 名单 | `top{N}_{board}_{日期}.csv` | `scripts/top_n_pipeline.py`(东财成分股 → 新浪快照 → 涨幅排序) |
| 涨跌分桶分布 | `distribution_{board}_{日期}.csv` + 市场宽度结论 | 全板块快照按 6 分桶(>5%/2-5%/0-2%/0%/-2-0%/<-2%)+ up/down/flat 汇总,六桶 count 加和必须等于 total |
| 情绪证据清单 | 分层证据表(L1/L2/L3 各列) | 一手行情 + 媒体检索 |

行情与板块接口细节 → [references/market-data.md](references/market-data.md);情绪证据方法与信源 → [references/sentiment-evidence.md](references/sentiment-evidence.md)。

### Phase 2 — 公告检索

对 Top N 全标的查公告,周窗口(近 7 天)与月窗口(近 31 天)互斥分桶:

```bash
# 脚本路径按本 skill 安装目录(SKILL.md 同级目录下的 scripts/)执行,示例用相对路径仅指 skill 包内
cd <本 skill 安装目录>
env -u http_proxy -u https_proxy -u all_proxy -u HTTP_PROXY -u HTTPS_PROXY -u ALL_PROXY \
python3 scripts/ann_query.py --codes 002219,600613,920946 \
--end 2026-08-13 --out-dir /path/out \
--universe-csv /path/top10_xxx.csv
```

脚本内置:巨潮 orgId 一律 topSearch 解析(禁按市场自拼,深市双形态/沪市前导零/科创板 gfbj 均实测拼错即假阴)、B 股(900/200 开头)自动转对应 A 股代码检索、双源交叉与类型回填、两源翻页、月窗 0 条自动扩宽窗判据(宽窗最新日期 vs 月窗起点)、URL 抽查。orgId 陷阱与接口形态 → [references/cninfo-announcements.md](references/cninfo-announcements.md)。

**分桶规则**:公告日期落在周窗口内标 `1周`,否则(仍在月窗口内)标 `1月`,互斥不重复。输出表头:`股票代码,股票名称,公告标题,公告日期,公告类型(如有),公告URL,时间窗口(1周|1月)`。

**必做验证**:① 双源交叉(巨潮 vs 东财)计数一致;② 0 条标的扩宽窗确认「真无」;③ 两源覆盖不完全一致(部分投关类公告仅东财有、部分巨潮也收录),东财独有条目补并集并按 URL 域名标注来源。

### Phase 3 — 对抗验证(用户原话:「看哪些假设是错的」)

派 2 个 **fresh-context** 对抗性 agent(不 fork,不共享本会话上下文),各自带验证轴:

- **验证轴 1 · 方法论与数值**:Top N 名单重算(独立重跑数据链)、分桶统计重算(六桶 count 加和 = total)、快照时间戳核对
- **验证轴 2 · 公告完整性与情绪证据强度**:抽查公告月窗口是否漏检、情绪结论逐条检查是否 L1/L2 承重、有无未标注的推断

每个 agent 的 finding 必须带可证伪锚点(具体数值/URL/命令输出),prompt 中明令「编造不如标不确定」。验证结果在综合报告中单独成节:**哪些假设被推翻、哪些被确认、哪些无法验证**。编排细节 → [references/agent-orchestration.md](references/agent-orchestration.md)。

### Phase 4 — 综合报告

交付结构:

1. **数据源与 pivot 披露**:用了哪些源、哪些不可用、为何 pivot
2. **Top N 名单**:表格(排名/代码/名称/涨幅/价格/成交额)+ 快照时间戳
3. **公告清单**:周/月分桶,按标的聚合,标注来源与交叉验证结果
4. **情绪判断**:L1–L3 分层呈现,结论明确标注证据等级;证据不足的维度写「不确定:无 L1/L2 证据」
5. **验证结果**:对抗验证发现、假设推翻清单
6. **不确定项清单**:所有未达「十足把握」的条目显式列出

报告数值一律照抄落盘 CSV,禁止凭记忆转写。

## 环境约束

- 国内站点(东财/新浪/巨潮)curl/脚本必须去代理:`env -u http_proxy -u https_proxy -u all_proxy -u HTTP_PROXY -u HTTPS_PROXY -u ALL_PROXY`
- Python 用 `uv run --no-project` 或系统 python3(脚本 stdlib only)
- 新浪快照返回 GBK 编码,需 Referer `https://finance.sina.com.cn`;东财公告接口可不带 Referer(实测);北交所公告不单独走 bse.cn(官网接口三重失效,走巨潮 gfbj 通道)
- 若 push2 域名解析进 198.18.0.0/15(代理 TUN fake-IP),去代理无效,须修代理分流或用 `curl --resolve` 直连真实 IP(见 references/market-data.md)
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Agent Team 编排纪律(本工作流的实测版)

派 Agent Team 前必须先加载 `daymade-agent-discipline` skill(CLAUDE.md 硬闸)。本文是它在行业投研工作流上的具体化 + 本会话实战校准。

## 派发矩阵(Phase 1 / Phase 3 专用)

| 阶段 | Agent 数 | 类型 | 验证轴 |
|---|---|---|---|
| Phase 1 数据采集 | 3 并行 | 普通 sonnet | Top N 名单 / 涨跌分桶分布 / 情绪证据 |
| Phase 3 对抗验证 | 2 并行 | **fresh-context**(禁 fork) | 方法论数值重算 / 公告完整性与证据强度 |

## 硬纪律

1. **子代理显式 `model:'sonnet'`**——省略 = 继承主会话模型,主会话在旗舰档时「不写」就是「最贵」
2. **prompt 末尾写交付协议**:「完成后必须调 SendMessage 把报告发回主会话,静默转 idle 视为未完成」+「开跑时先回一条『收到,预计 N 分钟』」(长任务必加后者,防催单与回信交叉)
3. **每条 finding 带可证伪锚点**:具体数值 / URL / 命令输出,禁止「整体感觉偏暖」式空泛结论;锚点使复核从「重查」降到「点验」
4. **数据采集 agent 必须落盘**:CSV 写文件 + SendMessage 只回路径与计数。断连不丢文件,报告引用照抄 CSV
5. **验证 agent 用 fresh-context**:prompt 只给「方法论 + 待验证数据路径 + 验证轴」,不给本会话的结论与推理——防反向锚定。fork 继承主会话盲区,禁止
6. **验证 prompt 明令「编造不如标不确定」**:对抗验证的产出是「哪些假设错了」,不是「确认全部正确」——一个诚实的「无法验证」比一个编的「已确认」有价值
7. **禁 spawn 重复 agent**:同名同任务的 agent 会互相覆盖产物路径
8. **agent 报告的数值不能直接进最终报告**:主会话照抄 agent 落盘 CSV,不照抄 agent 的 SendMessage 文本(文本转述可能失真,CSV 是权威)

## 验证结果处理(Counter-Review 纪律)

验证 agent 的 finding 是「风险假设」不是「判决」。每条过四问:真会发生吗 / 修复代价 / 现实场景会触发吗 / 能否 5 分钟证实。分级:✅真(低成本→直接修)/ ⚠️部分(给权衡)/ ❌噪音(明说拒绝)/ 🚫反而有害。

## 验证轴定义(用户原话:「来看一下你的哪些假设是错的」)

验证目标是**证伪假设**,不是走过场:

- **轴 1 · 方法论与数值**:Top N 名单用独立路径重算(重跑数据链脚本或手工抽样验证)、分桶统计重算(六桶 count 加和 = total、up/down/flat 与 total 一致)、快照时间戳与实际抓取时间一致
- **轴 2 · 公告完整性与证据强度**:抽查 N 只标的月窗口公告 vs 双源检索结果是否漏检;情绪结论逐条检查是否 L1/L2 承重、有无未标注的推断;0 条标的的「真无」证明是否完整

最终报告必须有「验证结果」节:**假设被推翻清单 / 被确认清单 / 无法验证清单**,三栏都可能是空的但必须出现。
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# 公告检索接口(cninfo 巨潮 + 东财,实测形态 2026-08-13)

## 巨潮 cninfo(沪深 + 北交所统一主源)

```
POST http://www.cninfo.com.cn/new/hisAnnouncement/query
body(form-encoded):
pageNum=1&pageSize=30&column=szse|sse&tabName=fulltext
&stock=<代码>,<orgId>&searchkey=&seDate=<start>~<end>
```

- 返回 JSON:`totalAnnouncement` 总数、`announcements` 数组(`announcementTitle` / `announcementTime` 毫秒时间戳 / `adjunctUrl` / `announcementTypeName`)
- **announcementTime 是毫秒时间戳,按北京时间(UTC+8)换算**成 `YYYY-MM-DD`,不是 UTC
- 公告 URL = `http://static.cninfo.com.cn/` + `adjunctUrl`
- 深市 column=szse、沪市 column=sse

### ⚠️ orgId 陷阱(2026-08-13 当日实测修正:orgId 一律 topSearch,禁自拼)

**orgId 一律用 topSearch 接口返回值,禁止按市场规则自拼**——不同市场/板块的 orgId 形态不一致,且存在多个拼错点,自拼必踩「查 0 条」假阴:

| 市场 | 实测样本 | topSearch 返回的 orgId | 自拼为何错 |
|---|---|---|---|
| 深市主板 | 000001 平安银行 | `gssz0000001` | 深市存在**两种形态**:gssz+补零 与 `9900xxxxxx`(002219 → `9900004301`),按股票不同,无规律可自拼 |
| 沪市主板 | 600613 神奇制药 | `gssh0600613` | 7 位补零位置易拼错:自拼 `gssh6000613` 实测 0 条(前导零在「0600613」) |
| 沪市科创板 | 688265 南模生物 | `gfbj0839728` | 数字部分(0839728)与代码**无关**,自拼 `gssh0688265` 实测 0 条 |
| 北交所 | 920946 森萱医药 | `gfbj0830946` | 同左,gfbj 前缀 + 补零代码 |

**全市场查真实 orgId**(沪深主板/科创/北交所统一走此接口):

```
POST http://www.cninfo.com.cn/new/information/topSearch/query
body: keyWord=<6位代码>&maxNum=10
```

返回 JSON 数组,取 `code` 以目标代码开头的项的 `orgId` 字段。

- 标定实验:000001 能正常返回公告 = 接口本身正常;某股月窗 0 条先怀疑 orgId 参数错,不是「无公告」
- column 参数 sse/szse 实测对查询结果无影响(同 orgId 交叉测试结果相同),按市场填写即可
- **北交所(43/83/87/92 开头)巨潮覆盖**:topSearch 返回 `gfbj` 前缀 orgId(实测 920946 → `gfbj0830946`),与沪深同一查询通道。bse.cn 官网接口实测不可用(见下),勿再试
- 返回 `hasMore` 字段可判断翻页(pageSize=30);公告数超 30 条必须翻页取全,不能只取第一页

### ⚠️ B 股公告挂在对应 A 股代码下(2026-08-13 实测)

巨潮与东财的 stock 参数**都不接受 B 股代码**(900904/200028 实测恒 0 条,即使 orgId 正确)。B 股公司的公告以 A 股代码发布,须用对应 A 股代码检索:

- topSearch 对 B 股代码返回的 orgId 是其 A 股公司的,沪/深 B 的 orgId 为 `gssh`/`gssz` 前缀 + **A 股代码** 7 位补零,反推可得 A 股代码:
- 900904(神奇B股)→ orgId `gssh0600613` → A 股 **600613**(神奇制药),巨潮/东财月窗各 2 条 ✓
- 200028(一致B)→ orgId `gssz0000028` → A 股 **000028**(国药一致),月窗各 12 条 ✓
- 脚本 `ann_query.py` 已内置自动转换(`b_share_a_code`),输出 stderr 标注「公告经 A 股 XXXX 检索」;orgId 反推失败(非 gssh/gssz 前缀)显式报出需人工确认,不静默

## 东财公告(交叉验证 + 类型回填)

```
GET https://np-anotice-stock.eastmoney.com/api/security/ann
?sr=-1&page_size=50&page_index=1&ann_type=A&client_source=web&stock_list=<代码>
```

- 返回 `data.list[]`:`title` / `notice_date`(YYYY-MM-DD HH:mm:ss)/ `art_code` / `columns[]`(公告类型数组)
- **⚠️ 类型在 `columns[0].column_name` 里,顶层 `column_name` 字段恒为 null**(2026-08-13 实测)——多类型时多个 columns 元素用「、」连接(如「股东大会决议公告、高管人员任职变动」)
- 公告 URL = `https://data.eastmoney.com/notices/detail/<代码>/<art_code>.html`
- **巨潮 `announcementTypeName` 常为 null** → 用东财 columns[].column_name 按「日期 + 标题」匹配回填;标题比对前归一化(全/半角括号归一化 + 去空格 + **剥离东财「公司名:」前缀**),日期允许 ±1 天容差(实测样本多为同日,容差只防两源口径偶发差异)
- **投资者关系活动记录表:两源覆盖不完全一致**(2026-08-13 实测)——002437 的 07-23 投资者关系管理信息仅东财有;920946 的 05-14「投资者关系活动记录表」巨潮有收录(在 90 天宽窗之外、约 135 天窗口可得——巨潮也收录部分投关表)。东财独有条目补并集;来源区分看 URL 域名(cninfo.com.cn vs data.eastmoney.com),无需单独来源列
- 响应 `data.total_hits` 为总数,`page_size=50`;公告数超 50 条必须按 `page_index` 翻页取全(脚本已内置,上限 20 页保护)
- 2026-08-13 实测:东财公告接口可不带 Referer(带 `https://data.eastmoney.com/` 亦可)

## 北交所 bse.cn 官网接口(已知不可用,勿再试)

2026-08-13 实测三重失效,已弃用(北交所改走巨潮 gfbj 通道 + 东财交叉):

1. **WAF**:直接 POST 返回 403,需先 GET 拿 cookie 且稳定性差
2. **结构过期**:文档写 `data[0].listInfo.content[]`,实测返回结构已变
3. **参数被忽略**:`companyCd` 被服务端忽略,返回全市场公告流,无法按公司过滤

```
POST https://www.bse.cn/disclosureInfoController/initDisclosureList.do
...
```

另一端点 `companyAnnouncement.do` 多组参数组合均返回空。以上均为「已试过、不可用」的记录,不是可用路径。

## 0 条双向读(月窗口 0 条 ≠ 真无公告)

月窗口返回 0 条时,必须同时做两件事再下结论:

1. **扩宽窗**:同参数查 90 天窗口。**判据 = 宽窗最新公告日期 vs 月窗起点**:宽窗最新公告落在月窗内 → 月窗 0 条是参数/orgId 问题,不是「真无」;宽窗最新公告早于月窗起点(或宽窗也 0)→ 真无公告,继续第 2 步
2. **第二源核对**:东财接口查最新公告日期。两源都说「最近无公告」→ 才可写「该标的近一月无公告」

实战案例:002172 月窗 0 条,宽窗(90 天)仅 1 条(07-09 质押公告)、东财确认最新公告 07-09 → 真无公告,参数正确。920946 月窗 0 条,宽窗 8 条但最新 05-21(早于月窗起点)→ 同样是真无,不是参数错——**「宽窗有公告」本身不构成参数错误证据,必须看宽窗最新日期**。

## 脚本

`scripts/ann_query.py` 已内置以上全部逻辑(orgId 一律 topSearch 解析、B 股自动转 A 股代码、双源交叉、类型回填、两源翻页、0 条扩宽窗判据、URL 抽查)。调用前必须去代理环境变量(国内站点)。输出表头:`股票代码,股票名称,公告标题,公告日期,公告类型(如有),公告URL,时间窗口(1周|1月)`,utf-8-sig 编码(Excel 兼容)。

**分桶规则**:周窗口(近 7 天)内的标 `1周`,月窗口(近 31 天)其余标 `1月`,互斥不重复。注意:某些手动/半自动产物出现过同一公告同时标两个窗口的重复行(错误示例),分桶必须互斥。
Loading
Loading