← 返回模块
4.1.2.4beta 可读 · 未来付费内容校验中内容版本 2026-05-28

量化数据基础设施:数据湖与时点数据库

4.1.2 · 基本面、另类数据与数据基础设施 · 量化全流程

周四 09:15。某上海私募 200 亿规模的多空基金,风控研究员发现:实盘 PnL 比昨晚研究端对当日的回测 投影 落后 47 bp。同样的标的池、同样的持仓、同样的执行切片。差距太干净,不像噪声。数据团队的第一动作不是去翻策略代码、不是去看执行层、不是去查券商成交回报——而是查 ​数据血缘 图​​:回测看到的每个输入是哪个版本?实盘看到的每个输入是哪个版本?查询 30 秒内返回:回测读到的 fundamentals_pit 行带 cleaning_pipeline_version = v3.2.1;实盘读到的带 v3.2.0。清洗管线昨夜做了一次升级;回测在新版本上重跑;实盘已在老版本上执行完毕。从告警到定位根因总耗时:四分钟。​​没有 血缘 图,同一事件复盘需要团队连续 3 天 SQL 取证​​。本课是本模块的 capstone——把前三课的词汇转化为下游每一个 Track-4 量化课程都依赖的「基础设施基底」的仓库架构。数据湖(raw + 永久)、列式仓库(清洗 + 关联 + 快)、时点视图(双时间 + 重述感知)、血缘图(每一行 可追溯)、权限治理 层(每一次读取 都写审计日志)、SLA(07:00 PIT 就绪、loud 失败、5 个工作日内复盘)。

三层仓库架构

任何一家现代买方机构的仓库都有三层——物理隔离、运营独立——围绕一条规则组织:​​「raw 湖 永生;清洗 仓库 可从湖重建;PIT 视图 是研究面向的表面」​​。2024 年 CN 买方默认:

| tier               | technology                                                                                            | responsibility                                                                | canonical user                                              |
| data lake          | S3 / Aliyun OSS / Tencent COS / MinIO + Parquet                                                       | immortal raw vendor drops + audit copies; the rebuildable source              | data team operates; researchers query via ad-hoc lake-readers |
| query layer        | Snowflake / BigQuery / ClickHouse / Databricks / MaxCompute / StarRocks for production research + Athena / DuckDB / Spark-SQL for ad-hoc | cleaned + joined production datasets with predictable performance             | every research desk query                                   |
| point-in-time view | SCD-2 / Iceberg time-travel / Datomic-style append-only EAV                                           | bitemporal serving of restate-able data — fundamentals + alt-data             | every backtest + signal evaluation that depends on historical accuracy |

data lake 层。​ 廉价对象存储 持有 每一次供应商投递的不可变副本,按 lake/<vendor>/<dataset>/dt=YYYY-MM-DD/file.parquet 分区。CN 一侧:阿里云 OSS 是主流(MaxCompute 体系),腾讯云 COS(CDW 体系),华为云 OBS(DWS 体系),MinIO 用于私有云 / 本地化部署。Parquet 是规范化格式——列式(每列独立 block,支持列级压缩 + projection 下推)、schema-on-read(消费方指定要哪几列;写方 schema 在 footer)、压缩(基本面 + 另类数据 较 CSV 小 ~10 倍;Snappy 是默认 codec;ZSTD 用更高 CPU 换更高压缩比)、可切分(一个大 Parquet 文件可被 N 个 reader 并行处理)。审计副本 按合规要求保留——A 股 受监管数据 7 年起,未监管另类数据 3 年,自有衍生数据集 永久。​​raw 湖 永不删除;生产仓库 *可从湖重建​​*——清洗管线 可端到端重跑、把任意历史时点的仓库表 重新 reconstruct。​​分区主键​​:日期是顶层分区;超大量数据集(实时 行情)追加 hour 或 symbol-prefix 子分区。

query layer 层。​ 三个子层反映成本 / 性能权衡。(1) Ad-hoc 查询——研究员对湖直接做探索性查询。Aliyun DLA(湖 分析)/ DuckDB(笔记本上跑列式 SQL,「现代 SQLite for analytics」)/ Spark-SQL(分布式;当湖超出笔记本规模)——这些都能直接读 OSS / COS / S3 上的 Parquet。场景:探索、一次性回填、血缘 diff 查询。成本:按查询付费或按运行时付费,偶发使用便宜,生产规模昂贵。(2) 生产研究——研究台从一个可预测性能的列式仓库读取。​​MaxCompute(阿里云)​ 是 CN 买方机构的事实主流;​​Snowflake-via-Aliyun-marketplace​ 可用但受 PIPL 跨境限制;​​ClickHouse 自建​ 在中频 私募 里广泛使用;​​StarRocks​​(CN 开源列式仓库)2023-2024 急速兴起;​​Hologres / AnalyticDB / CDW(腾讯云)/ DWS(华为云)​ 各家都在打湖仓 一体(lakehouse)牌。场景:每一次生产查询(因子回测、信号评估、组合构建、风控)。成本:可预测的存储 + 按查询;仓库是大部分 CN 买方机构 单一最大 的基础设施成本项。(3) 低延迟 tick + 分钟线——TimescaleDB / KDB+ / QuestDB。4.1.1 配套层;基本面 + 另类数据 通常不需要这一延迟。

point-in-time view 层。​ 任何会被重述的数据——基本面、一致预期、另类信号——的研究面向表面。每一行同时携带 value_date(数值关于的日期)与 knowledge_date(数值被知晓的日期)——L1 的词汇从概念上升到 schema。

SCD-2 fundamentals_pit 表 schema

规范化的 SCD-2(Slowly Changing Dimension Type 2)模式:每一次基本面数值变化写一行新行,附带 effective_from + effective_to + is_current + 双时间对 + 数据列 + 用于血缘的 provenance JSON:

-- every fundamental table is bitemporal; SCD-2 with effective_from/effective_to is the canonical pattern
CREATE TABLE fundamentals_pit (
  symbol VARCHAR,
  value_date DATE,
  knowledge_date DATE,
  effective_from TIMESTAMP,
  effective_to TIMESTAMP DEFAULT '9999-12-31',
  is_current BOOLEAN DEFAULT TRUE,
  revenue NUMERIC,
  net_income NUMERIC,
  eps NUMERIC,
  total_assets NUMERIC,
  shareholders_equity NUMERIC,
  provenance JSON,
  PRIMARY KEY (symbol, value_date, knowledge_date)
);

在 快照 S 上读:WHERE knowledge_date <= S AND effective_from <= S AND effective_to > S。新重述到来时,写一条新行,同时把上一行的 effective_to = NOW()is_current = FALSE。SCD-2 模式被 MaxCompute / Snowflake / BigQuery / Postgres / SQL Server / Redshift / ClickHouse 原生支持——它是 80% 场景的默认。

双时间 P/E 查询

为 600519 贵州茅台 计算「2022-12-31 快照下的 P/E」:盈利数字必须取「快照已知 vintage」,价格必须取「快照之前」——两侧使用相同 snapshot 才能避免 look-ahead-bias:

-- compute P/E with both prices and earnings observed in their as-of-snapshot vintage; both sides must use the same snapshot date to avoid look-ahead-bias
WITH pit_view AS (
  SELECT symbol, value_date, eps
  FROM fundamentals_pit
  WHERE knowledge_date <= '2022-12-31'
    AND effective_from <= '2022-12-31'
    AND effective_to   >  '2022-12-31'
),
prices AS (
  SELECT symbol, date AS price_date, close
  FROM bars_1d
  WHERE date <= '2022-12-31'
)
SELECT p.symbol, p.price_date, p.close, v.eps,
       (p.close / v.eps) AS p_e
FROM prices p
JOIN LATERAL (
  SELECT eps FROM pit_view
  WHERE symbol = p.symbol AND value_date <= p.price_date
  ORDER BY value_date DESC
  LIMIT 1
) v ON TRUE;

LATERAL JOIN 对每个价格日期挑出「截至当时最近一个季度」的 EPS——也即实盘策略在快照日真正能看到的那个数。市场数据层(bars_1d)以单时间形式参与连接,因为 tick 不会被重述,时间戳本身就是 knowledge date。

PIT 三种实现模式

1. SCD-2 / Slowly Changing Dimension Type 2  — every change is a new row with effective_from + effective_to + is_current + bitemporal pair; SQL-native; choose for default 80% of cases
2. Iceberg / Delta time-travel               — append-only at the file level; SELECT * FROM tbl FOR SYSTEM_TIME AS OF '<snapshot>'; choose when the warehouse natively supports it and the workload is read-heavy with deep history
3. Datomic-style fully-append-only EAV       — every fact is [entity, attribute, value, tx_id]; bitemporal-by-default; choose only when bitemporal-by-default + extreme lineage-fidelity is worth the operational cost

生产规则:​​基本面 + 另类数据 必须 是双时间的(重述 + 迟到 + 修正);行情数据 可以 是单时间的(tick 来即来,不重述——时间戳就是 knowledge date)​​。

SCD-2 是任意 SQL 原生仓库(Snowflake / BigQuery / Postgres / Redshift / MaxCompute / ClickHouse)的默认。Iceberg / Delta time-travel 在文件层工作:表只追加、每次写产生 snapshot-id,读用 SELECT * FROM tbl FOR SYSTEM_TIME AS OF '<snapshot>'(Iceberg / SQL:2011 语法)或 SELECT * FROM tbl VERSION AS OF <snapshot_id>(Delta)。劣势:snapshot-id 是公司 自己 的时间观,不是供应商的时间观——你还得保留 knowledge_date 列才能区分「供应商发布版」与「公司存储版」。MaxCompute 与 StarRocks 都支持 Iceberg / Hudi。Datomic-style EAV(Datomic、XTDB / 旧名 Crux)保真度最高;劣势是运营成本(查询模型陌生、生态小、单位字节成本高)——只在「双时间是杀手级特性」的小型专精机构使用;CN 一侧生产中基本不见。

数据血缘 与 provenance 四元组

每一行研究表必须可追溯回它的原始供应商输入。​​OpenLineage​​(Linux 基金会项目)定义了 dataset-derivation 事件的 JSON event schema;现代编排器(Airflow / dbt / Dagster / Spark / DataWorks)都会发出 OpenLineage 事件。公司内规范:每张研究表上有一个 provenance 列,承载四元组:

1. vendor_drop_id            — the unique identifier of the specific vendor file or batch that originated this data — typically <vendor>.<dataset>.<vintage_id>
2. ingestion_batch_id        — the L3-pipeline batch identifier that landed the vendor drop in the lake
3. cleaning_pipeline_version — the semantic version of the cleaning + transform code (bumped on every meaningful logic change)
4. transform_job_id          — the specific job-run identifier that produced this row (for retro-diagnosis)

生产规则:​​每个研究数据集都通过 provenance 四元组回溯到它的原始供应商输入;当回测与实盘 PnL 不一致时,第一动作是 diff 血缘​​——bug 几乎总是「供应商 vintage 差异」(回测读了 current-vintage;实盘读了 PIT-as-of-then)或「管线版本回归」(清洗管线 上周升级到 v2,回测在 v2 上重跑、实盘已用 v1 处理过历史)。本课开篇的 4 分钟定位 就是这条查询。前向指引:4.5.1(回测方法论)正式化「回测 vs 实盘」对账纪律。

权限治理 与审计日志

供应商许可证把公司绑定在 账户 / IP / 业务单元 / 机构 维度规则上——参见 L3。数据团队的工作:每家供应商一个共享服务账号(一个 Wind 万得 server 账号,一个 Bloomberg B-PIPE 账号,一个 CRSP / WRDS 机构 账号);通过权限治理 组中转内部访问(阿里云 RAM 角色 / MaxCompute 角色 / OpenFGA / Casbin 策略——选择匹配仓库的技术)。每一次对权限受限数据集的读取都写日志 (user, dataset, columns_read, row_count, timestamp)——这是公司给供应商的「许可证被遵守」的证据。Wind / Bloomberg / CRSP / WRDS 都会做周期性的许可证合规审计;公司的审计日志是首要证据;数据团队拥有响应。SOX 风格的审计追踪纪律是更宽广的类比——审计日志之于数据团队,相当于交易审计日志之于合规团队。

SLA 与故障响应 runbook

数据团队把仓库作为生产服务运营,不是研究产物:

| sla                       | timing                                              | scope                                                                                                   | ownership                                          |
| vendor reconciliation     | completes by 06:00 local                            | manifest-verify + checksum match all overnight ingestions                                              | data team owns; alerts on miss                     |
| PIT view                  | query-ready by 07:00 local                          | bitemporal-as-of queries return correct values for snapshots up to 06:55                               | data team owns; staleness probe at 07:05 alerts on miss |
| lineage                   | queryable in real-time                              | the lineage graph reflects every ingestion + transform job within 5 minutes of completion              | data team owns                                     |
| morning research pipeline | runs at 07:30                                       | consumes the PIT view + market-data tier + alt-data tier; fails LOUD on missing dataset, never silent  | research-team-owned but data-team-supported        |
| incident response         | page within 5 minutes of staleness alert            | runbook: detect -> page -> diagnose-via-lineage -> roll-forward-or-back -> post-mortem within 5 business days | data team owns                                |

本地时间用北京时间(CST,UTC+8);告警通道是飞书 + 钉钉机器人,叠加内部值班排班系统。故障响应 runbook,五步:(i) 通过 PIT-view 陈旧 探针 检测;(ii) 呼叫值班数据工程师;(iii) 用 血缘 图 + 入库账本 诊断——起手查询 SELECT * FROM ingestion_log WHERE status != 'complete' AND scheduled_at > <last-known-good>;(iv) 上游解决后 roll forward 重跑失败的入库作业;或若上游短期无解,roll back 激活上一个 SCD-2 vintage;(v) 5 个工作日内复盘,把修复落到 schema 注册表、清洗管线 或 SLA 配置中的某一处。

端到端 capstone:贵州茅台 600519 跨 2022Q4 一次假设性 重述

L3 SFTP 入库把 Wind 当日基本面文件 wind_qf_20221115.zip 落到 lake/wind/fundamentals_quarterly/dt=2022-11-15/。manifest 通过;schema 注册表 通过;文件晋升到湖的 raw 分区,vendor_drop_id = wind.fundamentals_quarterly.20221115。清洗管线(版本 v3.2.0)读 raw 文件、归一化字段、计算衍生(TTM EPS),向 fundamentals_pit 写新 SCD-2 行——600519 的 2022Q3 营业收入,新行携带 value_date = 2022-09-30, knowledge_date = 2022-11-15, effective_from = 2022-11-15 03:00, effective_to = 9999-12-31, is_current = TRUE, revenue = 36298000000provenance 列携带 {vendor_drop_id: "wind.fundamentals_quarterly.20221115", ingestion_batch_id: "batch-2022-11-15-001", cleaning_pipeline_version: "v3.2.0", transform_job_id: "job-9f12a"}

2023Q4 Wind 推送了一次对 600519 2022Q3 的小幅收入确认 修正:营业收入 从 36298000000 改为 36285000000。新入库写一行新行 value_date = 2022-09-30, knowledge_date = 2023-11-08, effective_from = 2023-11-08 03:00, revenue = 36285000000;上一行 effective_to 被更新到 2023-11-08 03:00is_current = FALSE

2023-06-15 上以快照 2023-06-15 跑的回测正确读到 revenue = 36298000000(快照时点已知值,早于 2023-11-08 重述)。以快照 2024-01-15 跑的回测读到 revenue = 36285000000。当前 vintage 版本(不带双时间过滤)无条件读到 36285000000——正是 L1 那个 20-50% 回测高估的来源。权限治理 检查给出审计日志条目:{user: 'zhang_san', dataset: 'fundamentals_pit', columns_read: ['symbol', 'value_date', 'revenue'], row_count: 412, timestamp: '2023-06-15T09:14:22+08:00'}——公司给 Wind 的「许可证被遵守」证据。

五句话的纪律收尾:仓库是公司的记忆;双时间存储是回测「会被重述的数据」的唯一诚实方式;血缘 是「回测 vs 实盘」分歧 的唯一对账方式;权限治理 + 审计日志 是 守住 供应商许可证 的唯一方式;SLA + 故障 runbook 是把这个仓库当作生产服务而非研究产物来运行的唯一方式。

证监会 监管的 A 股 在 T+1 结算 节拍下运行;本仓库为下游的因子模型 + 夏普比率 / 信息比率 / Alpha 衰减 评估 提供 PIT-合规的输入。

练习(capstone)

Exercise

你为一家 200 亿规模、30 名研究员、12 条覆盖股票 + 期货生产策略的 CN 私募 量化 团队 设计生产仓库。给出四段交付。

(i) 三层拓扑图——底层 raw 湖(对象存储 上的 Parquet),中层列式仓库(用于生产研究),顶层 PIT 视图(研究面向);用 ASCII 草图或一页架构图。

(ii) 覆盖沪深300 标的池的 fundamentals_pit 表 SCD-2 schema——列出双时间对、SCD-2 生命周期列、两个示例基本面指标、provenance JSON 列、主键。

(iii) 还原「2022Q4 as-of 视图」下 600519 贵州茅台 EPS 的双时间 SELECT 模式——给出含 bind variables 的精确 SQL。

(iv) fundamentals_pit 中一行的血缘条目形态——写出 JSON 文档,把 provenance 四元组填上真实样本值。

(v) 一段 SLA + 故障响应 声明——覆盖 vendor recon、PIT 视图就绪、血缘 可查询、晨间管线失败模式、五步故障 runbook。

提示
拓扑图按三层垂直堆叠:底=按供应商分区的对象存储 + Parquet;中=列式仓库(MaxCompute / StarRocks / ClickHouse)承载清洗 + 关联后的表;顶=SCD-2 PIT 视图(建在仓库表之上)作为研究面向表面。注释数据流:入库 → 写湖;清洗管线 → 读湖 → 写仓库;SCD-2 转换 → 写 PIT 视图。
提示
血缘 JSON:{"vendor_drop_id": "wind.fundamentals_quarterly.20221115", "ingestion_batch_id": "batch-...", "cleaning_pipeline_version": "v3.2.0", "transform_job_id": "..."}。SLA:recon 06:00;PIT 07:00;血缘 实时;runbook 五步。

Formula Explorer

\text{P/E}_{\text{as-of}}(S) = \frac{\text{close}(S)}{\text{EPS}_{\text{TTM}}(\text{value\_date} \leq S,\ \text{knowledge\_date} \leq S)}

本课组装清单

本课按顺序组装的可核对件:

  • Inline-code table——三层仓库架构映射到 技术 / 职责 / 主要使用者。
  • Fenced ```sql 代码块——fundamentals_pit SCD-2 schema(含 value_date + knowledge_date + effective_from + effective_to + is_current + provenance)。
  • Fenced ```sql 代码块——双时间 as-of P/E 查询(SCD-2 PIT 视图 与 bars_1d 的 LATERAL JOIN)。
  • Inline-code listing——三种 PIT 实现模式(SCD-2Iceberg / Delta time-travelDatomic-style fully-append-only EAV)与选择规则。
  • Inline-code listing——血缘 四元组(vendor_drop_idingestion_batch_idcleaning_pipeline_versiontransform_job_id)与 OpenLineage 标准引用。
  • Inline-code table——五条仓库 SLA(vendor reconciliationPIT viewlineagemorning research pipelineincident response)与五步故障 runbook。
  • 练习——capstone 五段交付,含两条递进式 Hint。
  • FormulaExplorer——双时间 过滤 下的 as-of P/E 表达式。

五句话的纪律收尾:仓库是公司的记忆;双时间存储是回测「会被重述的数据」的唯一诚实方式;血缘 是「回测 vs 实盘」分歧 的唯一对账方式;权限治理 + 审计日志 是 守住 供应商许可证 的唯一方式;SLA + 故障 runbook 是把这个仓库当作生产服务而非研究产物来运行的唯一方式。

下一课

PIT 仓库 + 血缘 + 权限治理 + SLA 都到位之后,alpha 研究模块(4.2)与 回测模块(4.5.1)可以在它之上 正确性 前置条件 已满足 地继续 编排。后续每一个 Track-4 课程都默认这套基础设施已经存在。本模块的四节课——基本面数据产品面与 PIT 纪律(L1)、另类数据分类与评估(L2)、四种入库模式(L3)、本课的仓库 capstone(L4)——共同 定义了「量化的 数据基础设施」是什么。你下个季度计算的、读取 fundamentals_pitbars_1d 的价值策略夏普比率之所以可信,是因为本模块的四节课把它造成可信的。