创建人员: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。
记录方式:重型编码方案;方案审核通过前不得进入实现。
V1 只自动化“标准快照完成以后”的机械计算,不能解释从用户发出请求到交付报告的完整耗时。铖昌科技评估的 57 分钟主要消耗在人工取数、数据库差异追查、手工扩写完整报告和重复终检,V1 的毫秒级运行时间并未覆盖这些环节。
V2 的目标是把入口提前到“股票代码 + 估值日”,把出口扩展为“证据包 + 标准快照 + 完整 Markdown 报告 + 自动 QA + 全链路耗时”。
目标时限:
速度目标不能取消原始披露优先、估值日、TTM、归一化利润、机构时效、现金流、三情景、反向估值、交叉验证、复算和风险边界。
--input 入口和结果合同向后兼容。--ticker、--as-of、--cache-dir、--judgment、--task-start 和 --fixture-dir 端到端入口。task_start 到最终产物提交的总耗时及各阶段耗时。python -m stock_valuation_pipeline `
--input <valuation_snapshot.json> `
--output-dir <output-dir>
V1 行为和产物继续可用。
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,不得把机械情景冒充最终研究结论。
| 状态 | 含义 | 是否允许形成方向性结论 |
|---|---|---|
COMPLETE |
采集、快照、计算、报告和 QA 完成 | 仅在判断覆盖层齐全且 QA 无阻断时允许研究草案结论 |
COMPLETE_WITH_GAPS |
非核心数据或单个适配器缺失 | 视缺口影响决定;报告必须列出缺口 |
DATA_READY_NEEDS_JUDGMENT |
机械数据完成,缺少人工情景或结论边界 | 否 |
BLOCKED_CORE_INPUT |
股价、股本、核心财务等不能形成可信快照 | 否 |
FAILED |
合同错误、输出提交失败或内部异常 | 否 |
cli.py职责:解析两类互斥入口,保持 V1 兼容,将端到端请求交给 workflow.py。
硬合同:
--input 与 --ticker 互斥。--ticker 模式必须给 --as-of、--output-dir 和 --cache-dir。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.json 和 runtime.log。每个阶段开始、完成和失败都要输出进度;单次网络等待不得超过配置上限。
http_client.py职责:受控 HTTP GET/POST、超时、有限重试、响应大小限制和测试注入。
规则:
provider_registry.json 允许的域名和协议。--fixture-dir 时禁止真实网络,所有请求由固定夹具提供。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 安全和完成标记。价格、最新公告、机构预测按估值日刷新;未重述历史年报按内容哈希复用。
providers.pyV2 使用注册式适配器,不把 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[]
acquisition.py职责:用线程池并行执行相互独立的适配器,再串行执行来源优先级、as-of 和停止搜索判断。
并行上限默认 4。单个适配器失败不取消其他适配器;所有异常都转换为有来源、影响和重试建议的 gap。停止搜索条件为:取得法定原文、公司和报告期匹配、无后续修订、数字可勾稽且无数量级异常。
产物:acquisition_bundle.json、source_evidence.json、gap_list.json。
snapshot_builder.py职责:把统一采集结果映射到 V1 snapshot.schema.json,并保留字段级来源。
规则:
产物:valuation_snapshot.json 和 snapshot_build_report.json。
judgment_overlay.schema.json最小人工判断覆盖层只承载机器无法可靠替代的内容:
覆盖层不能改写价格、股本、法定利润或来源日期。出现冲突时显式失败。其目标是把人工输入缩小到判断,而不是重新填写财务数据。
full_report.py职责:从标准快照、统一计算结果、证据、缺口、覆盖层和耗时数据一次生成完整 Markdown。
固定章节:结论摘要;市场与资本结构;信源优先级;业务及利润来源;历史盈利;TTM 与归一化;机构预期;利润质量与现金流;模型选择;三情景;反向隐含条件;交叉验证;持有期测试;风险与触发器;复评清单;数据局限和复算摘要。
报告长度不设上限。所有数字表格只读取统一结果对象,不允许在模板中重复计算。无判断覆盖层时,相关段落明确标记 GAP/DATA_READY_NEEDS_JUDGMENT,不得出现 TODO、TBD 或伪结论。
report_qa.py主流程硬 gate:
valuation_results.json 一致;外部 URL 的在线可达性只做警告,不得因临时网络抖动改写已经完成的正式结果。
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。
superseded,不得作为主输入。| 错误码 | 类型 | 处理 |
|---|---|---|
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、空字符串、伪造预测或测试数据掩盖正式输入缺失。
task_wall_seconds 和 process_wall_seconds,不得再用计算引擎毫秒数代替完整任务耗时。acquisition_bundle.json 或 valuation_snapshot.json 独立重跑。--force 仍通过暂存和原子替换实现。py_compile/import 通过。使用固定网络夹具运行铖昌科技:
DATA_READY_NEEDS_JUDGMENT;本方案属于重型实现。状态为 PENDING_INDEPENDENT_DESIGN_REVIEW。只有 dev.reviewer.ana.cai 在 ana-doc/案例审计报告.md 给出方案 PASS 后,才进入代码实现;开发者不自审。