金融数据宇宙:machine-learning-for-trading 第 2 章数据源分类、质量审计与存储选型实战指南
【免费下载链接】machine-learning-for-tradingCode for Machine Learning for Trading, 3rd edition — from data sourcing to live execution.项目地址: https://gitcode.com/GitHub_Trending/ma/machine-learning-for-trading
金融研究的结论严格受制于数据的定义与生成方式。本指南基于 machine-learning-for-trading 开源仓库第 2 章"金融数据宇宙"(02_financial_data_universe),系统讲解市场数据 / 基本面数据 / 另类数据的分类框架、各资产类别(美股、ETF、期货、期权、加密永续、外汇)的市场结构差异、数据质量审计四支柱(结构校验、异常检测、分布漂移、摄取卫生),以及存储与查询架构的基准选型。读完你将掌握:如何用 22 个配套 notebook 落地一套从数据源尽职调查到增量更新、再到存储基准验证的完整金融数据工程工作流。
章节定位:在触碰任何数据集之前先建立概念地图
第 2 章的核心贡献并非只是"市场 / 基本面 / 另类数据"三分法,而是一个更深刻的论断:每一个数据集都内嵌了关于时间戳(timestamps)、调整(adjustments)、标识符(identifiers)和修订(revisions)的定义,而这些选择决定了数据在研究中的真实含义。同样的"收盘价",在不同资产、不同供应商、不同处理管线里可能指完全不同的东西。
据此,章节设定了五条学习目标:
- 区分市场、基本面与另类数据,并解释数据集定义如何塑造各数据源在研究与交易应用中的含义;
- 比较主要资产类别的可观测性、惯例与工程约束,识别市场结构如何改变"可测量、可建模"的对象;
- 应用金融数据质量框架诊断常见失效模式,尤其是时间点违规、生存偏差、公司行为错误与标识符不匹配;
- 在数据质量、法律合规、技术与商业维度上对数据供应商进行尽职调查;
- 选择适配研究与生产需求的存储与查询架构,包括何时使用分区文件、嵌入式分析数据库或服务端数据库。
全章的配套实践位于02_financial_data_universe/目录,共 22 个 notebook(每个均配套同名的.py脚本,由 jupytext 以 percent 格式同步维护),全部运行于ml4tDocker 镜像环境。
2.1 金融数据现代分类法:市场、基本面与另类数据
分类法的意义在于回答"这个数据源在回答什么问题"。章节将数据划分为三大类,而每一类的"定义内嵌"问题都不同:
- 市场数据(Market Data):价格、成交量、订单簿等交易产物,以高可观测性为特征,但易受市场微观结构(如撮合规则、涨跌停、交易时段)影响;
- 基本面数据(Fundamental Data):财务报表、宏观经济指标、持仓披露等,修订频繁且滞后发布,是最典型的"位时间数据"(bitemporal data)来源;
- 另类数据(Alternative Data):新闻文本、卫星影像、链上数据、预测市场等,覆盖度与信噪比差异极大,往往需要额外的实体解析与清洗。
章节反复强调:任何数据集都必须在四个维度上给出明确答案——时间戳(事件发生在何时,行情时间 vs 知识时间)、调整(是否复权、如何复权)、标识符(ticker 会变,需要稳定的 instrument ID)、修订(供应商是否回改历史值)。这四个维度是后续所有质量检查的靶心。
2.2 资产类别市场数据格局:价格、流动性与"数据集"的跨市场含义
本节的价值在于比较:同样的"价格""流动性"乃至"数据集"概念,在股票、ETP、期货、期权、数字资产、外汇、固收、互换与商品中含义迥异,工程选择与市场结构不可分割。配套的 12 个 EDA notebook 逐一落地了这一论点。
美股:生存偏差与复权约定
01_us_equities_eda引入 Wiki Prices 数据集——一套无生存偏差(survivorship-bias-free)的美股价格集合,源自已停更的社区维护版 Quandl WIKI 日线文件(2018 年 3 月停更)。该来源决定了解析管线的能力边界,notebook 的任务正是查明"这套面板能告诉我们什么、不能告诉我们什么"。核心代码通过data.load_us_equities加载面板,并区分两类价格列(见 01_us_equities_eda.py):
| 列类型 | 列名 | 用途 |
|---|---|---|
| 原始价 | open、high、low、close、volume | 分析实际成交价格水平 |
| 复权价 | adj_open、adj_high、adj_low、adj_close、adj_volume | 收益计算与回测 |
复权列吸收拆分与股息,使跨越公司行为的收益等于投资者真实可获得的收益。计算收益用adj_*,需要成交打印价时用原始列。面板还自带ex_dividend与split_ratio两个公司行为输入,这正是02_corporate_actions能在 AAPL 上"用算例验证"而非"信任供应商"的前提——该验证在 AAPL 上通过,但并非处处通过(详见15_survivorship_bias_detection)。
公司行为:拆分与股息如何打破价格连续性
02_corporate_actions演示了股票拆分与股息如何打破历史价格序列,并推导行业标准的后向复权(backward adjustment)方法。核心论点(见 02_corporate_actions.py):不做复权时,2:1 拆分表现为 −50% 的假暴跌,除息日价格跳空扭曲收益计算,基于未复权价格的 ML 特征因此系统性错误。各类公司行为的影响总结如下:
| 类型 | 描述 | 对价格的影响 | 对股份的影响 |
|---|---|---|---|
| 股票拆分 | 如 2:1 拆分 | 减半 | 翻倍 |
| 反向拆分 | 如 1:4 | 变为 4 倍 | 变为 1/4 |
| 现金股息 | 向股东派现 | 下跌股息的金额 | 不变 |
| 股票股息 | 增发股份 | 按比例下跌 | 增加 |
该 notebook 调用ml4t.data.adjustments.apply_corporate_actions生成复权 OHLCV 面板,并与 Quandl WIKI 自带的预复权序列对照验证;AAPL 因历史长、两类行为齐全、每次拆分幅度大到在原始价格中无可辨认,成为教学算例。
ETF:全书记案例的 50 只 ETF 宇宙
03_etfs_eda引入作为全书 ETF 轮动动量案例研究基石的 50 只 ETF 宇宙,探索其 schema、覆盖度、类别与数据质量特征。该宇宙在后续章节(案例研究见case_studies/etfs/)反复复用。
期货:连续合约构造与会话边界
期货板块由三个 notebook 组成,层层递进:
04_cme_futures_eda:介绍随书发布的 CME 期货数据集,演示数据结构、覆盖度与期货数据关键概念;05_futures_session_aggregation:把以 UTC 存储的小时级连续期货数据转换为会话感知的日线。CME 交易时段于美中时间 16:00 结束,因此日线必须尊重这一边界而非 UTC 午夜——周日晚上 18:00 开始的时段计入周一(见 05_futures_session_aggregation.py)。数据经 ratio(乘法)后向复权以消除展期价差,聚合覆盖全部 30 个产品 × 三个期限(前月、次月、第三月);06_futures_continuous:处理期货分析中最关键的挑战——由单个到期合约构造连续价格序列。实现基于成交量的前月识别展期检测(含 no-rollback 约束避免虚假切换),并比较 Panama(加法)与 ratio(乘法)两种后向复权方法:前者保持跨展期的美元 P&L,后者保持跨展期的百分比收益。两个声明参数(见 06_futures_continuous.py)值得注意:MIN_OUTRIGHT_PRICE = 500.0用价格下限把直盘合约与日历价差分开(CME 同时挂牌两者);CALENDAR_ROLL_SESSIONS_BEFORE = 5以交易会话而非日历日计——ES 每个到期日都是周五,日历日 5 天会落到周日,把切换推到周一。最后与 Databento 预构建的连续序列交叉核对并量化差异。
期权:前视信息与 Black-Scholes 从零推导
07_sp500_options_eda:全面探索 AlgoSeek S&P 500 期权分析数据集。期权数据与现货本质不同——它包含关于预期波动率、方向情绪与尾部风险的前视信息,这些无法直接从标的价格中观测;08_options_greeks_computation:从第一性原理推导并实现 Black-Scholes 定价框架,用 Brent 法数值求解隐含波动率,编码全部五个 Greeks(Delta、Gamma、Vega、Theta、Rho),并与 AlgoSeek 数据的预计算值验证残差来源。值得注意的实现细节(见 08_options_greeks_computation.py):无固定无风险利率——一年期美债收益率在 2020 年内下跌逾 1 个百分点,任何单一常数对全年大多数日子都是错的,因此验证部分按日期读取利率并打印其范围;09_options_continuous:期权是时间衰减工具,其价格同时反映标的敞口价值与剩余到期时间,需要专门的连续化处理。
加密永续合约:24/7 市场与资金费率套利
10_crypto_perps_eda:引入 Binance Futures 加密货币数据集:19 个永续合约的小时级 OHLCV 与捕捉永续-现货基差的 8 小时级 Premium Index。加密市场 24/7 交易(每年 8,760 小时 vs 股票 252 个交易日),且 premium 指数单位为小数、乘以 100 才是百分比(见 10_crypto_perps_eda.py);11_crypto_premium_analysis:在主要加密货币上加载、探索并分析 premium 动态,识别潜在套利机会,构成资金费率套利策略的基础。
外汇:OTC 聚合报价
12_fx_pairs_eda引入 OANDA 外汇数据集。外汇是 OTC 市场、无中央交易所,价格由多个流动性提供方聚合而成,报价惯例(pip、时区、周末缺口)与交易所市场显著不同。
2.3 数据采购:尽职调查框架
本节是全章的风险控制核心:许多表面上的研究成功其实是数据缺陷制造的。尽职调查被组织为四个维度——通用质量维度、金融特有失效模式、供应商评估、内部治理——把抽象警告转成可操作规则:时间点正确性、生存处理、公司行为方法论、标识符完整性、法律权利、可复现版本化。
数据质量框架的四支柱
13_data_quality_framework演示完整的质量工作流,全部检查来自ml4t.data.validation与ml4t.data.anomaly模块,作用于美股日线 OHLCV(见 13_data_quality_framework.py):
- 结构校验(
OHLCVValidator):OHLC 不变量(high ≥ open/close ≥ low)、空值、重复; - 异常检测(
AnomalyManager+ReturnOutlierDetector、VolumeSpikeDetector、PriceStalenessDetector):收益离群、成交量尖峰、价格停滞; - 分布漂移(PSI,Population Stability Index):分箱处理会丢弃哪些信息;
- 摄取卫生:缺口、重复、公司行为检测(公司行为检测器对照同文件的 split 与 dividend 列打分)。
参数声明展示了"同一阈值、三种尺度"的微妙性:OUTLIER_THRESHOLD = 3.0原样传给三个检测器,作为三种不同尺度估计的乘数,于是同一数值在收益空间产生三条不同 cutoff——MAD、Z-score、IQR 在同一阈值下会标记不同数量的事件,notebook 专门测量这些 cutoff 而非含糊带过。SYMBOLS使用旧版 Wiki/Quandl 的写法(FB 而非 META);CORPORATE_ACTION_THRESHOLD作为隔夜收益阈值标记候选公司行为,再用面板自带的真实 split 比率与除息金额打分,而非肉眼检查标记日期。
时间点验证:剔除未来函数
14_point_in_time_validation强调时间点正确性对有效回测的生死攸关:使用决策时刻不可得的信息会造成未来函数(lookahead bias),使回测优于实盘表现。notebook 沿三条线展开(见 14_point_in_time_validation.py):
- 区分事件时间(何时发生)与知识时间(何时得知),以及宏观发布的位时间轴;
- 用可视化证明中心化移动平均为何泄漏未来信息,并构建修正后的尺度不变启发式(特征收益 vs 未来收益相关性,
LEAK_THRESHOLD = 0.30以上判为泄漏)——该启发式能命中close.pct_change(-1)这类特征,而"水平 vs 收益"相关性则漏检; - 通过
vintage_date查询 FRED,展示 GDP 初估值与修订值的差异。EXECUTION_LAG_ROWS = 1模拟收盘信号次日成交的执行滞后。
生存偏差:最危险的污染形式
15_survivorship_bias_detection用真实历史数据演示、检测并量化生存偏差。起点是01_us_equities_eda留下的异常:面板记录了 777 个符号退出,且全部发生在 2014 年及以后——只有 2014 年至面板末日这段窗口表现得像活跃宇宙,因此ANALYSIS_START = "2014-01-01"(见 15_survivorship_bias_detection.py)。回答"静默丢弃退出者的组合高估了多少收益"分三步:
- 读取退出记录,确立面板对离场符号"知道什么、不知道什么";
- 修复收益序列:复权价中含有未复权的公司行为,不修正不仅加噪、还会反转答案的符号;
- 量化偏差:用
N_SIMS = 1000次蒙特卡洛模拟建模面板无法观测的量——持有者在最后报价之后实际收到什么,构建 CRSP 校准的退市场景并输出MC_BAND = (10, 90)百分位带。
参数MAX_TRUSTED_RETURN = 1.0的单边性编码了一个事实:多头持仓不可能亏损超过全部,因此不可信的日收益只可能是上涨。最终结论区分了生存完整性(survivorship completeness)与宇宙完整性(universe completeness)两个概念。
供应商比较
16_provider_comparison将尽职调查框架落到多供应商对比,对应章节"一般质量维度、金融特有失效模式、供应商评估、内部治理"中的评估环节。
2.4 数据存储:从文件格式到数据库引擎的基准选型
本节把数据纪律翻译为基础设施决策:不推销单一技术栈,而是解释存储选择如何取决于访问模式、规模、并发与运维成熟度,并用基准量化文件格式、嵌入式引擎与服务端数据库之间的权衡,为现代研究工作流给出实用默认架构,同时说明何时需要更复杂的系统。
端到端管线与管理
17_complete_pipeline:端到端数据管线,综合本章概念(使用 crypto_perps、wiki_provider 数据);18_data_management:用 ml4t-data 的生产级特性大规模管理数据——DataManager(拉取/存储/更新的统一入口)、Universe(S&P 500、NASDAQ 100 等预定义符号列表)、HiveStorage(分区 Parquet,支持快速查询与增量写入)、增量更新与 CLI 脚本化工作流(见 18_data_management.py);19_incremental_updates:增量更新是 ml4t-data 存在的核心理由。全量刷新重取每个符号的全部历史行,增量运行只取上次以来的会话——在数百符号、十年历史的宇宙上,前者是数百万行、后者每天数百行。核心洞察(见 19_incremental_updates.py):- 终点比起点更重要:Yahoo 会把当前交易所日期返回为一行"只有累积成交量、没有 OHLC"的占位 bar,
DataManager.update()取到datetime.now()会每天抛DataValidationError: yahoo: Column 'open' contains 1 null values;update_through_last_complete_bar则以交易所时间(而非 UTC)向前回退,直到供应商接受该窗口为止; fill_gaps=True默认值对 OHLCV 不安全:日历不知情的缺口检测会把每个周末和美国假日当成缺失交易日做前向填充,每个符号凭空多出数百根幻影 bar。正确做法是让非交易日缺席,交由日历感知的完整性检查兜底——即第三节的GapDetector;- 四种更新策略:
INCREMENTAL(默认,拉取最后存储时间戳之后的数据,最快)、APPEND_ONLY(只增不改,审计安全归档)、FULL_REFRESH(重新下载替换全部,损坏后恢复)、BACKFILL(补齐区间内缺失时段,修补历史空洞);IncrementalUpdater提供底层控制,多数场景用DataManager.update()即可。
- 终点比起点更重要:Yahoo 会把当前交易所日期返回为一行"只有累积成交量、没有 OHLC"的占位 bar,
文件格式基准
20_storage_benchmark_file在相同的 100 万行 OHLCV 面板(L 规模:100 符号 × 10,000 根一分钟 bar)上比较 CSV、Parquet、Feather(Arrow IPC)与 HDF5 三个维度:写入时间、读取时间(强制物化)与磁盘占用(见 20_storage_benchmark_file.py)。关键方法学:
- 时序策略统一:写入单次计时无预热(数据集只写一次);读取取
TIMING_RUNS次均值且前置一次不计时预热——这些是热缓存数字,如实描述研究循环的重复访问模式,但会美化内存映射格式(Feather 映射已驻留页),冷盘首读会缩小与 Parquet 的差距,网络/对象存储上压缩格式因搬运字节更少通常完胜; - 强制物化:Feather/HDF5 读取必须强制物化,防止内存映射或惰性读伪装成瞬时读;
- 列式投影收益:读 2 列 vs 9 列的量化对比;
- 环境敏感性:同一面板在锁定环境(
uv run,即uv.lock)下 HDF5 约 71 MB,在benchmarkDocker 镜像(更新版 pandas、新字符串 dtype)下约 79 MB——CSV/Parquet/Feather 不受影响,复现 §2.4 数字必须用uv run。
数据库引擎基准
21_storage_benchmark_database在 7 个存储引擎上执行 5 类操作(见 21_storage_benchmark_database.py):
| 类别 | 引擎 | 特征 |
|---|---|---|
| 嵌入式 | SQLite、DuckDB、ArcticDB | 进程内,无需服务端 |
| 时序服务端 | ClickHouse、QuestDB、TimescaleDB | 生产规模,需 Docker |
| 通用 | PostgreSQL、InfluxDB | 基线对比 |
| HFT 专用 | kdb+/PyKX | 交易行业标准 |
基准操作:Write(批量插入)、Read(全表扫描)、Range Query(7 天时间窗,回测工作流)、OHLCV Aggregation(分钟 bar 重采样为日 bar)、ASOF Join(成交-报价对齐,微观结构关键)。方法学同样严苛:写入单发无预热且持久性计入计时区(PostgreSQL/TimescaleDB 同步提交,QuestDB/InfluxDB 在计时区内轮询至wait_until_rows_visible,因此每个写入时间都终止于同一事件——数据已持久且可查询);读取为预热后的均值(客户端无法清除服务端缓存,"冷读"对嵌入式是冷的、对服务端是热的,既不冷也不可比,故统一取"温且一致");每个读取都按预期行数精确校验,近似命中即错误答案,防止静默截断的查询刷出最快时间。磁盘占用一列则按各引擎自报口径解读(文件大小 vssystem.parts.bytes_on_disk压缩数据部分),不作等口径压缩率对比。
DataFrame 引擎对比
22_pandas_polars_benchmark在 S/M/L 三档规模的合成金融数据上对比 pandas 与 Polars 的 read、filter、groupby、join、lazy 操作,支撑 §2.4 的内存引擎选择建议。
运行方式与前置条件
从仓库根目录运行任意 notebook 的脚本版:
# 从仓库根目录运行 uv run python 02_financial_data_universe/<notebook>.py # 测试模式(Papermill 缩减数据) uv run pytest tests/test_chapter_notebooks.py -v -k "02_financial_data_universe"测试模式通过 Papermill 注入参数覆盖(每个 notebook 的tags=["parameters"]单元格即为此设计,如MAX_SYMBOLS、BENCHMARK_SCALE等),CI 可据此缩小数据规模快速执行。
NB21 数据库基准前置条件
21_storage_benchmark_database依赖benchmark环境与数据库服务。其中DuckDB 与 SQLite 本地即跑、无需任何额外配置;其余五个引擎需先启动基准服务栈:
docker compose --profile benchmark up -d不启动这些服务时,NB21 会静默回退到 2 引擎子集(仅 DuckDB + SQLite),§2.4 的服务端数据库对比结果将无法复现。结束后用docker compose --profile benchmark down关闭栈。该 notebook 的完整运行方式为:
docker compose --profile benchmark up -d timescaledb clickhouse questdb influxdb docker compose --profile benchmark run --rm benchmark python 02_financial_data_universe/21_storage_benchmark_database.py从本章到全书:数据宇宙的工程闭环
第 2 章并非孤立的理论章节——它交付的是后续全部工作的数据地基:ETF 宇宙支撑 ETF 轮动动量案例,Binance 永续 premium 数据进入加密资金费率套利案例(case_studies/crypto_perps_funding/),数据质量框架被下游的14_point_in_time_validation(位时间卫生)、15_survivorship_bias_detection、17_complete_pipeline直接消费,19_incremental_updates的增量更新流程与data/download_all.py --update生产流程同构。仓库中的data/包提供了load_us_equities、load_etfs、load_cme_futures、load_crypto_perps、load_macro等规范加载器,数据按资产类别落盘于ML4T_DATA_PATH下的分区 Parquet;tests/test_chapter_notebooks.py与tests/test_chapter_imports.py等测试则保证每个章节脚本可复现、可验证。理解"数据集定义决定数据含义"这一章核心理念,是之后所有特征工程、模型训练与回测结论可信的前提。
延伸阅读
本章参考文献覆盖了文中每个论断的学术出处,包括:Beaver 等的退市收益与会计异象(Journal of Accounting and Economics, 2007);Berg 等的 ESG 评级分歧(Review of Finance, 2022);Carhart 等的共同基金生存偏差(The Review of Financial Studies, 2002);Cong 等的加密洗盘交易(Management Science, 2023);Fong 等的全球流动性代理指标(Review of Finance, 2017);He 等的永续合约原理(arXiv, 2024);Karnaukh 等的外汇流动性(SSRN, 2015);Shumway 的 CRSP 退市偏差(The Journal of Finance, 1997);Vidal-Tomás 的加密货币数据源选择(International Review of Financial Analysis, 2022);以及 López de Prado 的《Advances in Financial Machine Learning》(Wiley, 2018)与 Yin Luo 等的《Seven Sins of Quantitative Investing》。这些文献共同支撑了本章关于生存偏差、退市处理、数据源选择与量化研究七宗罪的方法论论断。
【免费下载链接】machine-learning-for-tradingCode for Machine Learning for Trading, 3rd edition — from data sourcing to live execution.项目地址: https://gitcode.com/GitHub_Trending/ma/machine-learning-for-trading
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考