rq-idea-generation
RQ 股票研究 - 投资创意生成
核心原则
- 所有内容必须遵循三阶段流程:数据采集 -> LLM 生成正文 -> HTML 渲染
assets/template.md是唯一报告模板来源;Python 只做数据归一化、指标计算、结构化快照生成、占位符填充和结构校验- Python 只输出结构化 facts / tables / thresholds,不在代码里硬写推荐语、主题判断或客户可读结论
- 报告必须严格使用真实
rqdata原始文件,不得在代码里硬写候选名单、日期、行业结论或投资判断 - 候选名单只代表“进入下一轮研究池的线索”,不代表最终投资结论
- 缺少数据时必须明确写“无数据 / 未启用该策略 / 未验证”,不能留空
数据源分工
RQData CLI 负责
- 股票池、公司名称、行业归属
- 财务快照、历史财务、同比增速
- ROE、市值、PE、PB 等定量筛选指标
- 候选排序、覆盖率、行业分布、交叉命中等结构化事实
web_search 负责
- 量化结果出来后的主题验证
- 行业景气、政策变化、监管动态
- 候选池相关的最新新闻、会议、产业催化
web_search 禁止替代的内容
- 财务数字、估值指标、股票池和公司基础信息
- 正式公告、价格、成交额、一致预期等结构化金融数据
- 任何候选排序、阈值判断和基础量化筛选结果
web_search 使用规则
详细字段、来源等级、落盘示例和 fallback 规则见 references/web_search.md。
允许补充的内容:
- 某条主题线索是否存在最新政策或产业催化
- 候选集中行业的景气验证和关键争议点
- 候选公司是否存在影响研究优先级的最新公开事件
落盘要求:
- 所有
web_search结果必须先写入web_search_findings.json - 只写结构化记录,不把自然语言草稿直接塞进报告
generate_report.py不直接消费该文件;当前 LLM 应在回写idea_screening_snapshot.json -> summaries.*前读取它- 若未做
web_search,报告必须保持“量化候选池”定位,不能伪装成已完成主题验证
硬性规则
以下任一条违反,视为输出失败:
[MUST-1]所有定量筛选指标必须来自RQData CLI[MUST-2]web_search只用于第二阶段主题验证,不能替代量化主数据[MUST-3]金额类数据在正文和表格中必须换算为“亿元”等客户可读口径[MUST-4]候选池不是最终结论;正文必须写清筛选逻辑、催化剂线索和关键风险,不能把候选直接写成“推荐买入”[MUST-5]idea_screening_snapshot.json -> summaries.*必须由当前 LLM 直接回写;Python 不负责代写正文[MUST-6]每个关键数据点或关键结论都要标数据来源:XXX,置信度X[MUST-7]若某策略未启用或未形成候选,仍要由 LLM 明确写清该章节当前用途和缺口,不能留空[MUST-8]低置信度外部信息不得改写量化筛选结论或候选优先级[MUST-9]最终输出必须严格来自模板,不得在脚本中自由拼写整篇报告
确信度评级
5:RQData CLI、交易所公告、上市公司官网、官方监管披露4:政府 / 监管 / 行业协会 / 官方机构、权威财经媒体3:一般媒体或二手整理,但来源清晰且与其他来源一致2:单一来源、细节不完整、时点未充分验证1:推断、估算窗口、未验证信息
使用规则:
- 混合结论的置信度取关键来源中的最低值
- 推断、主题映射或媒体传闻不得标成高置信度
- 低置信度信息只能作为跟踪线索,不能直接升级为核心投资判断
图表 / 图片需求
当前脚本以表格交付最小可用版本,但本 skill 仍必须定义达标报告所需的视觉载体;若未生成图表,必须由等价表格降级,不能省略关键问题。
-
图表名称:股票池覆盖与行业分布
-
图表目的:说明股票池规模、最新财报季度覆盖和行业集中情况
-
使用的数据文件:
stock_pool.json、instrument_meta.json、financials_history.json -
关键字段:
order_book_id、quarter、sector_code_name/industry_name -
建议图表类型:柱状图或分布表
-
回答问题:当前筛选结果是否受样本覆盖或行业集中度影响
-
放置位置:
## 股票池与筛选框架 -
若图表缺失:保留覆盖率表、财报季度分布表、行业分布表
-
图表名称:指标看板与候选对比
-
图表目的:比较全池中位数与各策略候选的关键指标
-
使用的数据文件:
idea_screening_snapshot.json -
关键字段:
universe.median_metrics、strategies.*.median_metrics、strategies.*.candidate_count -
建议图表类型:分组柱状图、雷达图或对比表
-
回答问题:价值 / 成长 / 质量三组候选的主要特征差异是什么
-
放置位置:
## 指标看板 -
若图表缺失:保留指标看板说明与候选表格
-
图表名称:交叉命中与风险暴露
-
图表目的:展示多策略共振程度与候选集中风险
-
使用的数据文件:
idea_screening_snapshot.json -
关键字段:
overlap.display_candidates、risk_flags.* -
建议图表类型:交叉矩阵、热力表或风险摘要表
-
回答问题:哪些候选值得优先进入下一轮研究,当前结果的主要结构性风险是什么
-
放置位置:
## 候选组合与交叉验证、## 风险与跟踪重点 -
若图表缺失:保留交叉命中表和风险事实表
目标产出
- 报告长度:8-12 页
- 正文目标:约
3000-5000中文字符 - 输出文件:
- Markdown 报告
- HTML 报告(若本地已安装渲染器)
- 输出目录必须由
--data-dir/--output指定,不能写死固定路径
目录结构
idea-generation/
├── SKILL.md
├── scripts/
│ ├── build_screening_snapshot.py
│ └── generate_report.py
├── assets/
│ └── template.md
└── references/
├── data_contract.md
└── web_search.md
输入文件契约
原始数据目录由 --data-dir 指定,脚本会按下列文件名查找输入:
stock_pool.jsoninstrument_meta.jsonlatest_financials.jsonfinancials_history.jsonroe.jsonmarket_cap.jsonpe_ratio.jsonpb_ratio.jsonweb_search_findings.json(可选,仅供 LLM 回写 summary 前读取)
这些文件都允许以下结构:
{ "data": [...] }{ "data": { ... } }[...]{ ... }
其中:
stock_pool.json用于定义股票池instrument_meta.json用于公司名称和行业字段补充latest_financials.json用于读取每只股票最近一期财务快照financials_history.json用于计算同比增长roe.json、market_cap.json、pe_ratio.json、pb_ratio.json用于估值与质量筛选web_search_findings.json只作为第二阶段主题验证输入,不参与 Python 打分或排序
完整字段说明见 references/data_contract.md。
工作流
步骤 1:准备参数
REPORT_DATE="${REPORT_DATE:-$(date +%F)}"
TOP_N="${TOP_N:-10}"
STRATEGY="${STRATEGY:-all}"
START_QUARTER="$(python3 - <<PY
from datetime import date
report_date = date.fromisoformat("${REPORT_DATE}")
print(f"{report_date.year - 2}q1")
PY
)"
END_QUARTER="$(python3 - <<PY
from datetime import date
report_date = date.fromisoformat("${REPORT_DATE}")
print(f"{report_date.year}q4")
PY
)"
DATA_DIR="${DATA_DIR:-$HOME/rq_equities_reports/idea_generation}"
SNAPSHOT_JSON="${SNAPSHOT_JSON:-$DATA_DIR/idea_screening_snapshot.json}"
OUTPUT_MD="${OUTPUT_MD:-$DATA_DIR/idea_generation_${STRATEGY}_${REPORT_DATE}.md}"
步骤 2:采集全市场股票池
mkdir -p "$DATA_DIR"
rqdata stock cn list --payload "{
\"date\": \"$REPORT_DATE\",
\"type\": \"CS\"
}" --format json > "$DATA_DIR/stock_pool.json"
步骤 3:分批采集基础信息、财务和估值指标
python3 - "$DATA_DIR" "$REPORT_DATE" "$START_QUARTER" "$END_QUARTER" <<'PY'
import json
import subprocess
import sys
from pathlib import Path
data_dir = Path(sys.argv[1])
report_date = sys.argv[2]
start_quarter = sys.argv[3]
end_quarter = sys.argv[4]
stock_pool = json.loads(data_dir.joinpath("stock_pool.json").read_text(encoding="utf-8"))
rows = stock_pool if isinstance(stock_pool, list) else stock_pool.get("data", [])
ids = [row["order_book_id"] for row in rows if isinstance(row, dict) and row.get("order_book_id")]
def fetch_batches(command_prefix, payload_builder, output_file):
collected = []
for start in range(0, len(ids), 800):
chunk = ids[start:start + 800]
payload = json.dumps(payload_builder(chunk), ensure_ascii=False)
output = subprocess.check_output([*command_prefix, "--payload", payload, "--format", "json"], text=True)
batch = json.loads(output)
collected.extend(batch if isinstance(batch, list) else batch.get("data", []))
data_dir.joinpath(output_file).write_text(json.dumps(collected, ensure_ascii=False, indent=2), encoding="utf-8")
fetch_batches(
["rqdata", "stock", "cn", "instruments"],
lambda chunk: {"order_book_ids": chunk},
"instrument_meta.json",
)
fetch_batches(
["rqdata", "stock", "cn", "financial"],
lambda chunk: {
"order_book_ids": chunk,
"fields": ["revenue", "net_profit", "total_assets", "total_liabilities"],
"start_quarter": start_quarter,
"end_quarter": end_quarter,
"statements": "all",
},
"financials_history.json",
)
data_dir.joinpath("latest_financials.json").write_text(
data_dir.joinpath("financials_history.json").read_text(encoding="utf-8"),
encoding="utf-8",
)
for factor, output_file in [
("return_on_equity_weighted_average", "roe.json"),
("market_cap", "market_cap.json"),
("pe_ratio", "pe_ratio.json"),
("pb_ratio", "pb_ratio.json"),
]:
fetch_batches(
["rqdata", "stock", "cn", "financial-indicator"],
lambda chunk, current_factor=factor: {
"order_book_ids": chunk,
"factor": current_factor,
"start_date": report_date,
"end_date": report_date,
},
output_file,
)
PY
说明:
idea-generation默认以全市场 A 股作为筛选覆盖范围,不再优先局限于单一指数成分股financial-indicator使用factor参数,不是fieldsfinancials_history.json与latest_financials.json可以复用同一份查询结果,脚本会自动按股票抽取最新季度并计算同比- 全市场数据量较大,必须按批次抓取,不能把全部
order_book_id一次性塞给单个命令
步骤 4:生成结构化筛选快照
python3 idea-generation/scripts/build_screening_snapshot.py \
--strategy "$STRATEGY" \
--data-dir "$DATA_DIR" \
--report-date "$REPORT_DATE" \
--top-n "$TOP_N" \
--value-pe-median-multiplier "${VALUE_PE_MEDIAN_MULTIPLIER:-1.00}" \
--value-pb-max "${VALUE_PB_MAX:-1.50}" \
--value-roe-min "${VALUE_ROE_MIN:-10.0}" \
--growth-revenue-yoy-min "${GROWTH_REVENUE_YOY_MIN:-15.0}" \
--growth-profit-yoy-min "${GROWTH_PROFIT_YOY_MIN:-20.0}" \
--growth-roe-min "${GROWTH_ROE_MIN:-15.0}" \
--quality-roe-min "${QUALITY_ROE_MIN:-15.0}" \
--quality-debt-ratio-max "${QUALITY_DEBT_RATIO_MAX:-50.0}" \
--output "$SNAPSHOT_JSON"
步骤 4.5:可选的主题 / 催化剂验证
当用户明确要求主题扫描,或量化结果需要实时外部语境时,才执行这一步。
- 先用
web_search收集主题、行业、政策或候选公司最新事件 - 结果写入
web_search_findings.json - 不得把
web_search结果直接喂给 Python 做打分、排序或阈值判断 - 若没有执行这一步,最终报告应保持“量化候选池 + 后续验证建议”的口径
步骤 5:当前 LLM 直接回写 summary
运行完快照脚本后,当前 LLM 必须直接读取 "$SNAPSHOT_JSON",并在存在时一并读取 "$DATA_DIR/web_search_findings.json",基于结构化数据和 template.md 回写:
summaries.exec_summarysummaries.universe_overviewsummaries.metric_scoreboardsummaries.value_sectionsummaries.growth_sectionsummaries.quality_sectionsummaries.overlap_sectionsummaries.risk_sectionsummaries.appendix
要求:
- 这些 summary 必须是客户可读正文,不得写“LLM 总结”“脚本生成”“流程说明”
- 文字结论只允许由当前 LLM 基于快照事实和可选
web_search_findings.json生成 - 未启用策略也要写清楚“本轮未启用,但保留该视角作为对照 / 后续扩池方向”
- 若只重复表格字段、输出项目符号堆砌或泄露文件名 /
summaries.*/ workflow 术语,视为未完成
步骤 6:渲染最终 Markdown 报告
常用参数:
--data-dir:原始 JSON 数据目录--snapshot:显式指定结构化快照路径;默认读取--data-dir/idea_screening_snapshot.json--output:输出 Markdown 路径--template:自定义模板路径,默认idea-generation/assets/template.md--no-render:不生成 HTML- 快照阶段阈值参数全部显式传入,例如
--growth-revenue-yoy-min、--quality-roe-min;这些阈值由用户决定,脚本只负责执行
步骤 7:渲染 HTML
脚本会优先尝试调用本地安装的 rq-report-renderer,若未安装则回退到仓库内 report-renderer/scripts/render_report.py;仍不可用时保留 Markdown 并打印警告。
阶段门控
Gate 1:数据采集完成
- 原始 JSON 文件齐全
- 股票池、财务、ROE、PE、PB 都有真实记录
- 没有用固定股票名单或手填候选替代数据采集
Gate 2:结构化快照完成
idea_screening_snapshot.json已生成strategies.*.thresholds记录了本次真实参数summaries.*仍为空,说明 Python 没有越界代写正文
Gate 3:LLM 正文完成
summaries.*已全部回写- 正文是客户可读内容,不是字段复读或内部流程描述
- 若使用
web_search,其信息只体现在总结与跟踪建议,不改写量化主结论
Gate 4:交付完成
- Markdown 已生成
- 若本地渲染器可用,HTML 已生成
- 报告长度、章节、来源标注和风险提示均达标
模板规则
- 报告必须严格基于 template.md 生成
- 占位符采用
[[TOKEN]]语法,不使用 Jinja - 当前模板仅允许以下占位符:
[[REPORT_DATE]][[STRATEGY]][[EXEC_SUMMARY]][[UNIVERSE_OVERVIEW]][[UNIVERSE_FACTS]][[QUARTER_TABLE]][[SECTOR_TABLE]][[METRIC_SCOREBOARD]][[METRIC_TABLE]][[VALUE_SUMMARY]][[VALUE_FACTS]][[VALUE_TABLE]][[GROWTH_SUMMARY]][[GROWTH_FACTS]][[GROWTH_TABLE]][[QUALITY_SUMMARY]][[QUALITY_FACTS]][[QUALITY_TABLE]][[OVERLAP_SUMMARY]][[OVERLAP_FACTS]][[OVERLAP_TABLE]][[RISK_SUMMARY]][[RISK_FACTS]][[APPENDIX_SUMMARY]][[APPENDIX_FACTS]]
报告质量要求
- 完整包含模板中的主章节
- 候选股票必须来自真实股票池与真实财务 / 估值指标
- 不得残留
[XX]、[需要补充]、[股票A]这类占位文本 - 文本必须说明筛选规则、覆盖范围、候选意义和关键风险,不能只有空表格
- 每个策略都要说明“启用 / 未启用”和结果数量
- 不能把量化候选直接写成确定性投资结论,必须保留“候选池 / 下一轮验证”边界
- 建议正文达到
3000-5000中文字符;单策略模式也应保留足够的筛选框架、预览和跟踪说明,不能退化成简表
阶段验收清单
-
idea_screening_snapshot.json成功生成,且summaries.*完整回写 - Markdown 文件存在
- 若本地渲染器存在则 HTML 文件存在
- 模板占位符无残留
- 主章节完整
- 报告长度达到 8-12 页的最低可交付标准
- 关键数据点与关键结论带
数据来源:XXX,置信度X - 至少一个启用策略生成非空候选表
- 未启用策略章节仍有合格说明,不是空白
- 若使用
web_search,相关记录已落盘且未越权替代 RQData 主数据
常见错误
- 把
financial-indicator返回字段错误地当成统一value - 直接在 Python 里硬写“推荐股票名单”或评论句,而不是让当前 LLM 基于快照生成正文
- 使用固定日期、固定季度、固定输出路径
- 只输出表格,不解释规则、覆盖率和风险
- 把候选池直接写成确定性结论,忽略第二阶段验证
- 继续依赖旧版
~/.claude/skills/...或仓库级utils
More from ricequant/ricequant-skills
rqdata-python
RQData数据API使用指南。当需要查询RQData数据接口、获取金融数据时使用。支持A股、港股、期货、期权、指数、基金、可转债等市场数据查询,包含HTTP API和Python API文档。
9ricequant
Ricequant量化平台文档阅读和API查询工具。当Claude需要访问Ricequant量化工具时使用,特别是提到某类金融相关数据或者RQ等字眼时:包括RQAlphaPlus回测框架、RQData数据API、RQFactor因子计算、RQOptimizer优化器、RQPAttr归因分析等文档的查询和阅读。
1rq-morning-note
|
1rq-earnings-preview
|
1rq-sector-overview
|
1rq-catalyst-calendar
|
1