如何用保形预测给交易信号加预测区间
2026/9/14 6:44:26 网站建设 项目流程

如何用保形预测给交易信号加预测区间

【免费下载链接】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

给交易信号加一个"这次预测可能错多少"的量度,是本仓库第 11 章 notebook 06_conformal_prediction.ipynb 解决的任务。它以 100 只 ETF 的面板数据为基础,对 21 日前向收益(标签fwd_ret_21d)做 Ridge 回归,然后用三种保形预测方法——Split-Conformal(SC)、Conformalized Quantile Regression(CQR)、Adaptive Conformal Inference(ACI)——生成带有限样本覆盖率保证的预测区间。与假设残差服从正态分布的经典置信区间不同,保形预测只需要校准集与测试集满足可交换性这一更弱的条件;金融数据在 walk-forward 评估下会破坏可交换性,所以 notebook 的后半部分重点在于监测覆盖率在哪里失效,而不是盲信名义保证。

本文的操作路径:准备特征与标签两个前置文件 → 运行 notebook 得到三种方法的区间 → 用校准指标表和分层覆盖率表判断区间是否可信 → 把区间宽度接到仓位权重上。

先备好两个前置文件:ETF 特征与 21 日收益标签

notebook 开头会断言两个文件必须存在,否则直接停止并提示先跑对应的上游 notebook:

  • case_studies/etfs/labels/fwd_ret_21d.parquet—— 由 ETF 案例研究第 2 阶段02_labels.py生成
  • case_studies/etfs/features/financial.parquet—— 由第 3 阶段03_financial_features.py生成

在仓库根目录按顺序执行(Docker 路径下在 Jupyter Lab 终端里去掉uv run前缀,直接写python):

# ETF 市场数据(Yahoo Finance,无需 API key) uv run python data/etfs/market/download.py # 生成标签与特征 uv run python case_studies/etfs/02_labels.py uv run python case_studies/etfs/03_financial_features.py

这两个阶段属于 ETF 案例研究 的管线:100 只 ETF、日频数据、月度决策、21 日前向收益标签、8 折 walk-forward 切分(10 年训练、1 年验证)。缺少数据时 notebook 会抛出DataNotFoundError并给出对应数据集的下载命令。

运行 notebook:Docker 与本地两种入口

Docker 路径(推荐)

Docker 提供跨平台一致的环境,本章所有 notebook 都在ml4t镜像中运行(docs/running-notebooks.md):

# 首次拉取镜像(x86 约 12 GB,ARM64 约 3 GB) docker compose pull ml4t # 直接运行本 notebook,不经过 Jupyter docker compose run --rm ml4t python 11_ml_pipeline/06_conformal_prediction.py

本地 uv 路径

uv sync # 安装依赖,需要 C/C++ 编译器和 Python 头文件,见 docs/installation.md uv run python 11_ml_pipeline/06_conformal_prediction.py

必须从仓库根目录运行。数据加载器按工作目录解析data/,在11_ml_pipeline/子目录里运行会报No module named 'utils'或数据缺失。

在桌面环境直接运行.py会弹出 matplotlib 图形窗口并阻塞到窗口关闭,看起来像卡住;无显示环境(服务器、CI)用无头方式运行:

MPLBACKEND=Agg PLOTLY_RENDERER=json uv run python 11_ml_pipeline/06_conformal_prediction.py

快速试跑(可选)

notebook 顶部有参数单元格(# %% tags=["parameters"]),生产默认值为:

SEED = 42 MAX_SYMBOLS = 0 # 0 = 全部标的 TRAIN_SUBSAMPLE = 0.25 # 每折训练日期按该比例抽样 RETRAIN = False RIDGE_ALPHA = 1.0 TARGET_COVERAGE = 0.90 MAX_CV_FOLDS = 0 # 0 = 全部折 MAX_QR_SAMPLES = 20_000 # QuantileRegressor 的 LP 求解器是 O(n^3),超出则抽样

用 Papermill 注入缩减值可以几分钟内跑完,适合先验证流程再跑全量:

uv run papermill 11_ml_pipeline/06_conformal_prediction.ipynb /dev/null \ --cwd . -k python3 \ -p MAX_SYMBOLS 15 \ -p MAX_CV_FOLDS 2

--cwd .保持工作目录为仓库根目录,原因同上。注意:只要MAX_SYMBOLS > 0MAX_CV_FOLDS > 0,notebook 会自动把结果文件名加上_fast后缀(conformal_results_fast.joblib),避免缩减运行的结果覆盖完整运行的缓存。测试套件也提供整章验证入口:

uv run pytest tests/test_chapter_notebooks.py -v -k "06_conformal_prediction"

三种保形方法分别怎么构造区间

三个方法共用同一套数据流程:从setup.yaml加载规范的 walk-forward 切分(generate_cv_splits,带 21 天标签缓冲),每折的训练集再按 80/20 切成模型训练集与校准集;每个 fold 训练样本少于 100 行或测试少于 20 行时跳过该折。运行中会逐折打印进度,例如Fold 1: SC=..%, CQR=..%, ACI=..%,这里的百分比是该折的实际覆盖率。

Split-Conformal:最简实现

数据分成训练集、校准集、测试集三部分。回归的非一致性得分是绝对残差 $s_i = |y_i - \hat{y}_i|$,区间半宽取校准得分排序后第 $\lceil (n+1)(1-\alpha) \rceil$ 小的那个。这个"取整到真实得分"的步数正是有限样本保证的来源:插值式分位数函数会返回略窄的值,恰好丢掉保证需要的那点余量。notebook 用 utils/modeling.py 中的conformal_quantile直接按秩取值;当秩超过校准集大小时(校准集太小,无法认证所请求的覆盖率),它返回inf,产生无界区间——这是诚实的失败,比引用手里最大的得分更可靠。

CQR:自适应宽度的区间

训练两个分位数回归模型(QuantileRegressorsolver="highs")分别给出下界 $q_{\alpha/2}$ 和上界 $q_{1-\alpha/2}$,非一致性得分为 $s_i = \max(\hat{q}{\alpha/2}(x_i) - y_i,; y_i - \hat{q}{1-\alpha/2}(x_i))$,再用保形校准修正量cal_adj平移两个分位点。区间宽度随观察点变化,在波动大的时期变宽。代价是 LP 求解器随训练集规模呈 $O(n^3)$,所以有MAX_QR_SAMPLES抽样上限;TRAIN_SUBSAMPLE则按日期层面缩减每折训练历史,三种方法共用同一缩减比例以保证可比。

ACI:在线更新失覆盖率

标准保形假设可交换性,而市场分布会随时间漂移。ACI 的更新规则:

$$\hat{\alpha}_{t+1} = \hat{\alpha}t + \gamma \cdot (\alpha{\text{target}} - \mathbf{1}{y_t \notin C_t})$$

$\gamma$ 是适应速度(notebook 默认 0.01),$\hat{\alpha}_t$ 被裁剪在 [0.001, 0.999] 保持区间有限。漏覆盖(indicator 为 1)使 $\hat{\alpha}_t$ 下降、区间放宽;持续过覆盖则收紧区间。在截面面板上有两条硬约束:同一决策日的所有 ETF 共用一个 $\hat{\alpha}_t$(不能用一只 ETF 的已实现收益设定同日另一只的区间);反馈只能来自 21 个会话前已 resolve 的标签,任何更早的回灌都是前视偏差。因此每个 fold 的前 21 个交易日运行在目标 $\alpha$ 上,这是方法本身的属性。

验证结果:看覆盖率、区间宽度和分层表

结果缓存在11_ml_pipeline/models/06_conformal_prediction/conformal_results.joblib,缓存签名绑定 notebook 源码、输入文件摘要和关键设置;代码或输入变了会自动重拟合并提示Refitting: cached results ... are stale。想强制重跑把RETRAIN置为True

需要依次核对的输出:

  1. 校准指标表calibration_metrics):对 SC、CQR、ACI 分别给出actual_coverage(池化实际覆盖率)、coverage_gap(相对TARGET_COVERAGE的差距,不是相对固定的 0.90)、mean_width/std_width(区间宽度的均值与离散度)、fold_std(折间覆盖率的稳定性)、n_foldsn_predictions。四个维度回答不同问题,方法的排序在各维度上并不一致:宽度最稳的方法没有余量吸收 regime 变化,覆盖率反而会移动。
  2. 多水平校准曲线:对 0.1 到 0.9 九个目标水平,把请求覆盖率与经验覆盖率画在一张图上,对角线为完美校准。点在对角线上方是保守(区间偏宽),下方是欠覆盖。notebook 记录的结果是曲线落在对角线下方——这正是期望方向,因为有限样本保证依赖可交换性,而非平稳收益上的 walk-forward 评估恰好破坏它。曲线同时落盘为calibration.parquettarget_coverage/empirical_coverage两列)。
  3. ACI 自适应轨迹:打印最后一个 fold 的 alpha 范围与均值(对照目标值 0.10),并画出整条轨迹。轨迹偏离目标线并保持偏离,说明池化校准得分需要那么多调整才能覆盖到请求比率,不代表区间仍在漏。
  4. 区间宽度分布:三个直方图面板对比宽度形态。SC 每折只固定一个宽度,面板是少量尖峰,峰间差异全部来自折到折的变化;CQR 和 ACI 逐观察点定宽,呈连续分布。宽度能否随波动率联动,直接决定区间能不能用于仓位——notebook 用 VIX(FRED 系列vixcls,不可用时回退到 |return| 代理)叠加图来检查这一点。
  5. 分波动率三分位覆盖率表:把 |return| 分为低/中/高三档,检查每档内部的实际覆盖率(列Marginal/Low/Mid/High)。这是 notebook 自述"最重要的表":边际列贴近视目标值,但按三分位拆开,三种方法都在高波动档显著欠覆盖、在两个平静档几乎全覆盖。边际数字是"在无关紧要处过覆盖"与"在关键处欠覆盖"的平均。notebook 指出三个方法的修正量都来自跨 regime 池化的校准集,波动尖峰时刻的区间主要由占校准样本大多数的平静日子决定;文档给出的应对方向是regime 条件化校准——按事前已知的市场状态划分校准得分,分别计算修正量。

一个使用限制需要明确:这里的 |return| 是用被覆盖的已实现结果构造的,本身有污染(高档部分靠构造选择了大残差),只因为不需要额外数据才被采用。生产环境的诊断应分层在决策时刻可知的事前状态(滚动已实现波动率、VIX 水平)上。发现的方向对该污染稳健,具体数值不稳健。

把区间宽度接进仓位

notebook 最后给出一个最小可用的逆宽度仓位规则:用 CQR 区间宽度构造position_weight = median_width / width(除数下限1e-10),再裁剪到 [0, 3] 封顶。窄区间放大相对仓位,宽区间降低敞口——模型不确定时自动减仓。这是第 19 章 19_risk_management 完整仓位框架的预览。注意它继承了上面的分层覆盖缺口:按宽度缩仓的策略会在高波动 regime 相对真实不确定性持有最大仓位,而这正是区间最不可信的时候。

已知限制

  • 金融数据不满足可交换性,名义覆盖率保证只在近似意义上成立。notebook 的结论是:边际覆盖率是这里最不值得关注的数字,方法可以在边际上达标、同时在其区间宽度决定仓位的 regime 里失败。
  • ACI 的反馈天然滞后 21 个会话(标签 resolve 的时点),只能跟踪比标签更慢的漂移,步长大小改变不了这个滞后——它是交易问题本身的属性。
  • 本文只覆盖 ETF 案例研究的fwd_ret_21d场景。换标签或换案例研究时,LABEL_HORIZON_SESSIONS(ACI 的delay_sessions)、标签缓冲和case_study_id都要与新的标签视野一致。

跑通后,下一步入口是 07_case_study_insights.ipynb,它在九个案例研究之间比较线性模型表现,判断线性基线在哪里留出了值得交给更复杂模型的空间。

【免费下载链接】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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询