edit | blame | history | raw

股票估值端到端流水线 V2 编码方案 V001

创建人员:dev.developer.ana.cai
文件职责:冻结股票估值端到端流水线 V2 的需求边界、模块接口、缓存与失败语义、完整报告、全链路耗时和验收方法。
关联事项:DEV-ANA-STOCK-VALUATION-PIPELINE-V2-20260801-001
上游依据:用户在当前会话确认“按照这个思路去做”;股票价格合理性评估操作手册_v1.0.md 文件内版本 v1.1;V1 流水线及铖昌科技实际评估耗时复盘。
管理规范/模板:../../../../common/dev-doc/编码规范.md../../../编码规范.md../../../开发审计规范.md
引用文件:../股票估值流水线说明.md../../../../dev/ana-dev/stock_valuation_pipeline/README.md../../../../outputs/20260730_stock_valuation_guide/股票价格合理性评估操作手册_v1.0.md
记录方式:重型编码方案;方案审核通过前不得进入实现。

1. 问题与目标

V1 只自动化“标准快照完成以后”的机械计算,不能解释从用户发出请求到交付报告的完整耗时。铖昌科技评估的 57 分钟主要消耗在人工取数、数据库差异追查、手工扩写完整报告和重复终检,V1 的毫秒级运行时间并未覆盖这些环节。

V2 的目标是把入口提前到“股票代码 + 估值日”,把出口扩展为“证据包 + 标准快照 + 完整 Markdown 报告 + 自动 QA + 全链路耗时”。

目标时限:

  1. 冷启动公开网络采集的机械阶段目标不高于 90 秒;网络异常时按明确超时降级,不无限等待。
  2. 有效缓存复评的机械阶段目标不高于 5 秒。
  3. 首次完整分析的客户端总耗时目标为 12~20 分钟,其中人工只处理利润持续性、场景倍数和结论边界。
  4. 已建立公司基线后的复评总耗时目标为 3~8 分钟。

速度目标不能取消原始披露优先、估值日、TTM、归一化利润、机构时效、现金流、三情景、反向估值、交叉验证、复算和风险边界。

2. 范围与非目标

2.1 本期范围

  1. 保持 V1 --input 入口和结果合同向后兼容。
  2. 新增 --ticker--as-of--cache-dir--judgment--task-start--fixture-dir 端到端入口。
  3. 并发采集行情、法定公告索引、结构化财务数据和机构预测。
  4. 保存原始响应、来源元数据、内容哈希和请求索引。
  5. 建立公司基线与增量水位,只重取估值日以后发生变化的模块。
  6. 将采集结果转换为 V1 标准快照;不可自动确认的字段进入缺口清单。
  7. 用统一数据和最小人工判断覆盖层生成固定 16 节完整 Markdown 报告。
  8. 自动检查公式、日期、来源、Markdown、链接、占位符和报告关键数字一致性。
  9. 记录从 task_start 到最终产物提交的总耗时及各阶段耗时。

2.2 非目标

  1. 不连接付费数据库,不绕过登录、验证码、访问控制或反爬限制。
  2. 不承诺任意网页永久可用;适配器失败时输出可定位缺口。
  3. 不自动推断未披露客户、型号、订单或敏感军工信息。
  4. 不输出交易指令、收益承诺或自动批准的投资结论。
  5. 不用单一通用 PE 替代人工行业与周期判断。
  6. 不在本期引入 GUI、服务端、常驻数据库或定时任务。

3. 用户入口与状态

3.1 向后兼容入口

python -m stock_valuation_pipeline `
  --input <valuation_snapshot.json> `
  --output-dir <output-dir>

V1 行为和产物继续可用。

3.2 端到端入口

python -m stock_valuation_pipeline `
  --ticker 001270 `
  --as-of 2026-08-01 `
  --output-dir <output-dir> `
  --cache-dir <cache-dir> `
  --judgment <judgment_overlay.json> `
  --task-start 2026-08-01T16:45:22+08:00

--judgment 可省略。省略时仍生成数据就绪报告,但状态必须是 DATA_READY_NEEDS_JUDGMENT,不得把机械情景冒充最终研究结论。

3.3 终态

状态 含义 是否允许形成方向性结论
COMPLETE 采集、快照、计算、报告和 QA 完成 仅在判断覆盖层齐全且 QA 无阻断时允许研究草案结论
COMPLETE_WITH_GAPS 非核心数据或单个适配器缺失 视缺口影响决定;报告必须列出缺口
DATA_READY_NEEDS_JUDGMENT 机械数据完成,缺少人工情景或结论边界
BLOCKED_CORE_INPUT 股价、股本、核心财务等不能形成可信快照
FAILED 合同错误、输出提交失败或内部异常

4. 模块设计

4.1 cli.py

职责:解析两类互斥入口,保持 V1 兼容,将端到端请求交给 workflow.py

硬合同:

  1. --input--ticker 互斥。
  2. --ticker 模式必须给 --as-of--output-dir--cache-dir
  3. 日期、股票代码和路径错误必须在网络请求前失败。
  4. CLI 的 stdout 只输出结构化终态摘要;进度写 stderr 和运行日志。

4.2 telemetry.py

职责:记录用户可感知的全链路墙钟时间。

正式字段:

字段 含义
run_id 本次运行唯一 ID
task_start 用户任务起点;来自参数或进程起点
process_start CLI 启动时间
stage preflight/acquire/build_snapshot/calculate/render/qa/commit
started_at/finished_at 带时区时间
elapsed_seconds 单阶段墙钟
task_wall_seconds task_start 到提交完成
process_wall_seconds 从 CLI 启动到提交完成
status/error_code 阶段状态与错误码

产物:runtime_metrics.jsonruntime.log。每个阶段开始、完成和失败都要输出进度;单次网络等待不得超过配置上限。

4.3 http_client.py

职责:受控 HTTP GET/POST、超时、有限重试、响应大小限制和测试注入。

规则:

  1. 只访问 provider_registry.json 允许的域名和协议。
  2. 默认连接超时 8 秒、总读取超时 20 秒;临时网络错误最多重试 2 次,退避上限 2 秒。
  3. 4xx、解析错误、结构变化不盲目重试。
  4. 响应先写缓存临时文件,完成哈希后原子提交。
  5. --fixture-dir 时禁止真实网络,所有请求由固定夹具提供。

4.4 cache.py

职责:内容寻址原始缓存、请求索引、公司基线和增量水位。

目录合同:

<cache-dir>/
  blobs/<sha256>.bin
  requests/<provider>/<request_fingerprint>.json
  companies/<market-code>/baseline.json
  companies/<market-code>/source_index.json

请求索引至少记录:URL 或规范化请求、请求时间、响应时间、HTTP 状态、内容类型、字节数、SHA-256、来源发布日期、估值日、适配器版本和完成标记。

复用不能只看文件存在,必须同时验证请求指纹、响应哈希、适配器版本、as-of 安全和完成标记。价格、最新公告、机构预测按估值日刷新;未重述历史年报按内容哈希复用。

4.5 providers.py

V2 使用注册式适配器,不把 URL、缩放系数或字段路径散落到主流程。

第一期适配器:

适配器 用途 优先级 失败处理
法定公告索引 定位年报、季报、预告、修正和公司行动原文 A1 核心报告原文缺失则阻断或警告
行情适配器 as-of 收盘价、股本和平台市值 B1,价格×股本复核 无价格或股本则阻断
结构化财务适配器 三张表历史与本期累计数据 B1,须回链法定报告 与法定口径不一致则阻断
机构预测适配器 汇总、明细、日期、EPS和利润 B2 允许空,但显式 no_usable_forecasts

机构数据库最多核查两个。若“汇总数量”和“明细数量”不一致,保存原始汇总、可见明细和差异,最多做算术反推并标记 GAP,不得无限追查未知机构。

每个适配器返回统一 ProviderResult

provider_id, status, fetched_at, as_of_date,
records[], sources[], gaps[], warnings[], raw_artifact_hashes[]

4.6 acquisition.py

职责:用线程池并行执行相互独立的适配器,再串行执行来源优先级、as-of 和停止搜索判断。

并行上限默认 4。单个适配器失败不取消其他适配器;所有异常都转换为有来源、影响和重试建议的 gap。停止搜索条件为:取得法定原文、公司和报告期匹配、无后续修订、数字可勾稽且无数量级异常。

产物:acquisition_bundle.jsonsource_evidence.jsongap_list.json

4.7 snapshot_builder.py

职责:把统一采集结果映射到 V1 snapshot.schema.json,并保留字段级来源。

规则:

  1. TTM 必须使用最近完整年度 + 本年累计 - 上年同期累计。
  2. 金额在正式快照中统一为元,股本为股,价格为元/股。
  3. 估值日以后发布的信息不得进入快照。
  4. 法定报告与结构化数据不一致超过容差时,不自动选择“看起来合理”的一个。
  5. 归一化调整、现金可支配性和情景倍数不从网页叙事自动猜测。

产物:valuation_snapshot.jsonsnapshot_build_report.json

4.8 judgment_overlay.schema.json

最小人工判断覆盖层只承载机器无法可靠替代的内容:

  1. 业务及利润来源摘要;
  2. 归一化调整及理由;
  3. 悲观、基准、乐观利润与倍数;
  4. 主模型和交叉验证选择;
  5. 关键风险、上调和下调触发器;
  6. 结论等级、置信度和边界。

覆盖层不能改写价格、股本、法定利润或来源日期。出现冲突时显式失败。其目标是把人工输入缩小到判断,而不是重新填写财务数据。

4.9 full_report.py

职责:从标准快照、统一计算结果、证据、缺口、覆盖层和耗时数据一次生成完整 Markdown。

固定章节:结论摘要;市场与资本结构;信源优先级;业务及利润来源;历史盈利;TTM 与归一化;机构预期;利润质量与现金流;模型选择;三情景;反向隐含条件;交叉验证;持有期测试;风险与触发器;复评清单;数据局限和复算摘要。

报告长度不设上限。所有数字表格只读取统一结果对象,不允许在模板中重复计算。无判断覆盖层时,相关段落明确标记 GAP/DATA_READY_NEEDS_JUDGMENT,不得出现 TODO、TBD 或伪结论。

4.10 report_qa.py

主流程硬 gate:

  1. Markdown 围栏成对;
  2. 表格列数一致;
  3. 无 TODO/TBD/待计算/NaN/Infinity;
  4. 本地产物链接存在;
  5. 报告关键数字与 valuation_results.json 一致;
  6. 结论、情景和当前价格位置一致;
  7. 不包含交易指令和收益承诺;
  8. 核心字段有来源,且来源日期不晚于 as-of。

外部 URL 的在线可达性只做警告,不得因临时网络抖动改写已经完成的正式结果。

4.11 workflow.py

职责:唯一端到端协调入口。

preflight
-> acquire concurrently
-> build snapshot
-> run V1 calculation core
-> apply judgment overlay
-> render full report
-> report QA
-> atomic commit

所有正式产物先进入本次运行暂存目录,全部硬 gate 通过后才原子提交到输出目录。失败包保留 failure.json、运行日志和已取得的原始缓存索引,但不得留下状态为 COMPLETE 的 manifest。

5. 数据优先级和修订规则

  1. A1 法定披露原文决定财务报告、预告、股本变化和公司行动事实。
  2. B1 结构化金融数据库用于加速取数,但必须回链匹配的 A1 报告。
  3. B2 机构数据库只代表市场预期,不能替代公司承诺。
  4. 财报、预告和快报存在修正时,旧版本标记 superseded,不得作为主输入。
  5. 缓存中的历史报告只有在报告期、公司、内容哈希和未重述状态仍匹配时复用。
  6. 价格、股本、最新报告状态、机构预测、现金债务和公司行动每次复评都检查增量。

6. 错误码与降级

错误码 类型 处理
E_INPUT_CONTRACT CLI 或 Schema 错误 fail-fast
E_ASOF_VIOLATION 混入未来信息 阻断
E_CORE_MARKET_DATA 股价或股本缺失 阻断
E_CORE_FINANCIAL_DATA TTM 所需核心财务缺失 阻断
E_SOURCE_CONFLICT A1 与结构化数据超容差 阻断受影响字段
W_PROVIDER_UNAVAILABLE 单个非核心来源不可用 gap 后继续
W_FORECAST_COVERAGE 机构预测为空或明细不全 警告后继续
W_STALE_FORECAST 机构预测早于最新经营信息 排除出时效一致预期
W_EXTERNAL_LINK 外部链接暂时不可达 警告,不改写结果

不得用默认 0、空字符串、伪造预测或测试数据掩盖正式输入缺失。

7. 性能与可观察性

  1. 相互独立的网络 I/O 使用最多 4 个线程并发。
  2. 同一 URL/请求只下载一次,多个消费者读取同一内容哈希。
  3. PDF 原文在 V2 只负责证据归档和必要字段复核;批量财务字段优先使用结构化数据,避免每次全文解析。
  4. 每个适配器有开始、完成、命中缓存、失败和耗时日志。
  5. 每次交付同时报告 task_wall_secondsprocess_wall_seconds,不得再用计算引擎毫秒数代替完整任务耗时。
  6. 到达网络预算后结束相应适配器并输出 gap,不做无上限搜索。

8. 重跑与恢复

  1. 相同 ticker、as-of、适配器版本和请求指纹可复用已校验原始响应。
  2. 新估值日从公司基线增量刷新价格、公告和预测,历史年报不重新下载。
  3. 适配器版本、请求参数、响应哈希、Schema 或关键规则改变时重建受影响模块。
  4. 计算和报告可从 acquisition_bundle.jsonvaluation_snapshot.json 独立重跑。
  5. 缓存损坏只删除逻辑索引并重新取得对应内容,不影响其他内容寻址对象。
  6. 输出目录已有完整结果时默认拒绝覆盖;显式 --force 仍通过暂存和原子替换实现。

9. 验收方案

9.1 L0

  1. 全包 py_compile/import 通过。
  2. V1 现有 10 项测试不回退。
  3. 新 Schema 和注册表可解析。

9.2 L1 模块测试

  1. HTTP 超时、4xx、5xx、超大响应和非法内容类型。
  2. 缓存命中、哈希篡改、适配器版本变化、as-of 不安全和未完成标记。
  3. 行情缩放、股价×股本勾稽、财务累计口径、机构汇总/明细不一致。
  4. 覆盖层禁止改写法定字段。
  5. Markdown 围栏、表格、占位符、本地链接和数字一致性。

9.3 L2 离线端到端

使用固定网络夹具运行铖昌科技:

  1. 单条 CLI 从 ticker/as-of 生成全部产物;
  2. 关键数值与 2026-08-01 已完成报告一致;
  3. 无判断覆盖层时为 DATA_READY_NEEDS_JUDGMENT
  4. 加覆盖层后生成完整研究草案;
  5. 夹具模式网络访问为 0;
  6. 冷夹具运行低于 5 秒,有效缓存复跑低于 2 秒。

9.4 L3 边界与回归

  1. 无机构预测仍可生成带 gap 的报告。
  2. 未来财报或研报不能进入历史 as-of。
  3. 汇总 4 家、明细 3 家只产生一个明确 gap,不触发无限搜索。
  4. 法定公告和结构化利润冲突时阻断正式结论。
  5. 中断、输出冲突和提交失败不留下伪 COMPLETE 产物。
  6. V1 长城军工回归和 V2 铖昌科技回归同时通过。

9.5 L4 受控真实网络 smoke

  1. 用铖昌科技或另一只深市股票执行一次真实采集。
  2. 核对原始响应哈希、官方公告链接、价格日期、股本、市值、财务报告期和机构预测日期。
  3. 网络机械链路目标不高于 90 秒;如外站异常,验证在预算内降级并形成 gap。
  4. 第二次运行只刷新规定的动态字段并证明历史报告缓存复用。

10. 高风险点与控制

  1. 网页字段或缩放系数变化:适配器版本化、夹具回归和数量级检查。
  2. 当前接口污染历史 as-of:所有记录按发布日期过滤,无法历史化的字段不得回填。
  3. 抓取结果冒充法定事实:字段级来源和 A1 回链是硬门禁。
  4. 机构预测样本不透明:汇总与明细分账,差异记 gap。
  5. 缓存复用错误:请求、代码、Schema、as-of、哈希和完成标记联合校验。
  6. 报告数字漂移:所有表格读取同一结果对象,最终 QA 逐项比对。
  7. 人工判断被自动化掩盖:无覆盖层不产生方向性最终结论。
  8. 复杂度反而拖慢:V2 只实现首期四类适配器和 16 节报告,不引入数据库、GUI或常驻服务。

11. 方案门禁

本方案属于重型实现。状态为 PENDING_INDEPENDENT_DESIGN_REVIEW。只有 dev.reviewer.ana.caiana-doc/案例审计报告.md 给出方案 PASS 后,才进入代码实现;开发者不自审。