从数据到实盘:ML4T 交易代码库 Docker 环境全解(四大镜像、Compose 编排与导入自检体系)
2026/9/13 3:39:56 网站建设 项目流程

从数据到实盘:ML4T 交易代码库 Docker 环境全解(四大镜像、Compose 编排与导入自检体系)

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

本文以 envs/README.md 为骨架,结合 docker-compose.yml 与envs/目录下各镜像的 Dockerfile、依赖清单与自检脚本源码,系统拆解这套覆盖机器学习交易全流程(数据获取、特征工程、建模、回测、实盘)代码库的容器化运行环境。读完你将掌握:四类 Docker 镜像各自的服务范围与适用场景、如何用docker compose一键拉起 Jupyter Lab 或单跑某个章节脚本、GPU 透传与多平台(x86 / Apple Silicon)的取舍,以及镜像内置的"导入自检"机制如何保证环境与 27 个章节、9 个案例研究严格对齐。

一、环境设计总览:为什么需要四套镜像

该代码库覆盖从数据源到实盘执行的完整机器学习交易链路,跨 27 个章节与 9 个案例研究,涉及的第三方依赖超过 60 个。由于不同依赖对 Python 版本、CPU 架构和 GPU 的要求彼此冲突(例如gensim/signatory没有 Python 3.14 的 wheel,RAPIDS 没有 ARM64 支持),仓库把运行环境拆成四个职责清晰的 Docker 镜像,并通过 Docker Compose 统一编排:

镜像Docker HubPython平台体积
ml4t(主镜像)ml4t/ml4t:latest3.14amd64 + arm64~12 GB / ~3 GB
py312ml4t/ml4t-py312:latest3.12仅 amd64~9.6 GB
benchmarkml4t/ml4t-benchmark:latest3.14amd64 + arm64~1.7 GB
rapids本地构建3.12amd64 + NVIDIA GPU~15 GB

绝大多数读者只需要拉取主镜像ml4t,其余三套仅在特定章节需要。镜像全部发布在 Docker Hub 的docker.io/ml4t/命名空间下(docker compose pull时按image:字段直接拉取)。

二、主镜像 ml4t:一套环境覆盖全书

2.1 能力范围与快速上手

主镜像覆盖全部 27 个章节与 9 个案例研究,预装 PyTorch(含 CUDA 12.8 支持)、LightGBM、scikit-learn、Polars、Plotly 以及所有ml4t-*系列库(data、engineer、models、diagnostic、backtest、live 六个子包)。从 docker-compose.yml 可以看到,镜像内容目录被挂载到容器内的/app,数据目录挂载到/data,因此可以直接在容器里执行仓库内任意脚本:

# 拉取预构建镜像 docker compose pull ml4t # 启动 Jupyter Lab,浏览器访问 http://localhost:8888 docker compose up ml4t # 不启动 Jupyter,直接跑某一个章节的 Python 脚本 docker compose run --rm ml4t python 11_ml_pipeline/01_ols_inference.py

其中run --rm会在执行完毕后自动清理容器,适合 CI 或一次性验证;up则常驻运行 Jupyter Lab。需要指出的是,Compose 服务把 8888 端口绑定在127.0.0.1上且关闭了 Jupyter token,这是刻意为之的安全设计(详见下文 2.3 节)。

2.2 GPU 透传:同一镜像、两种运行方式

主镜像在 x86 平台上内置了 CUDA 12.8 的 PyTorch wheel,CPU 机器同样可以运行(CUDA runtime 打包在 wheel 内);在 Apple Silicon 上则自动换成 CPU-only 的 PyTorch。需要 GPU 加速时,通过gpuprofile 启用透传:

docker compose --profile gpu run --rm ml4t-gpu \ python 13_dl_time_series/01_core_architectures.py

对应地,docker-compose.yml 中定义了ml4t-gpu服务:与ml4t共用同一镜像,但通过deploy.resources.reservations.devices声明 NVIDIA driver 并占用全部 GPU,端口为 127.0.0.1:8889。GPU 透传依赖宿主机安装 nvidia-container-toolkit,容器本身不再额外打包 CUDA 驱动库(PyTorch wheel 已自带)。

2.3 镜像内部构造(源码级)

阅读 envs/ml4t/Dockerfile 可以还原主镜像的完整构建链路,其中有几个关键设计值得展开:

  • Python 3.14 来自 uv 而非系统:基础镜像只是ubuntu:24.04,Python 由uv python install 3.14安装(python-build-standalone),并创建 venv 到/opt/ml4t,随后ENV PATH="/opt/ml4t/bin:$PATH"使/opt/ml4t/bin/python成为默认解释器。这样绕开了 deadsnakes PPA 在 CI 上的网络抖动。
  • TA-Lib 从源码编译:技术指标库 TA-Lib 没有官方 wheel,Dockerfile 从 GitHub 下载 v0.6.4 源码并configure && make && make install
  • PyTorch 最先安装以最大化层缓存:amd64 用--index-url https://download.pytorch.org/whl/cu128安装 CUDA 12.8 wheel(约 5.4 GB),arm64 装 CPU 版(约 200 MB);安装后把torch/torchaudio/torchvision的精确版本 freeze 到/tmp/ml4t-constraints.txt,保证后续依赖解析不会覆盖。
  • 以 uv.lock 为唯一事实源:构建时用uv export --frozen从仓库根目录的 uv.lock 导出一份完全钉死版本的 constraint,再uv pip install解析依赖。Dockerfile 注释记录了不这样做的后果:浮动解析会漂移出锁定环境(如 litellm 拉到带 Rust 扩展的版本在 Python 3.14 上编译失败),导致容器内环境与uv sync读者不一致。
  • LightGBM 双路径:amd64 强制从源码以USE_CUDA=ON编译(需要 nvcc 12.6 + libnccl),构建时验证库能导入并报告 CUDA 支持;arm64 直接装 pip wheel。LightGBM 的精确版本同样从 uv.lock 读取(写入/tmp/lightgbm-pin.txt),防止浮动版本漂移。
  • kaleido + Chrome for Testing(amd64):为了让fig.show()在读者自己的运行中产出 PNG 静态图(GitHub notebook 查看器需要image/png),镜像安装了 Chrome for Testing 并配置+png渲染器;arm64 回退到交互式plotly_mimetype。同时把/home/ml4t设为 1777 权限并ENV HOME=/home/ml4t,避免宿主 UID 无 passwd 条目时 Chrome 因 HOME 不可写而崩溃。
  • 安全基线:Jupyter 以空 token、空密码启动,但端口只绑定 127.0.0.1;Origin/XSRF 检查保持开启,防止浏览器的恶意页面通过回环地址 POST 到 8888 执行代码。此外还禁用了与 JupyterLab 4.x 不兼容的catboost-widget扩展。
  • 内置运维脚本:镜像固化两个命令——ml4t-status打印 Python/PyTorch/CUDA/GPU 状态(python -c内联实现),ml4t-test-imports包装 envs/test_all_imports.py 用于导入自检(见第六节)。

三、py312 镜像:补齐 Python 3.14 生态缺口

3.1 哪些笔记本需要它

有四个核心依赖目前没有 Python 3.14 的 wheel,被移入 Python 3.12 的 py312 镜像;另外 Ch05/Ch10/Ch12/Ch14 的若干笔记本还会命中 Python 3.14 上 torch CUDA 导入的已知 bug,同样需要 3.12 环境:

笔记本依赖
Ch0503_sigcwgan_signaturessignatory
Ch0906_path_signaturessignatory、esig
Ch1001_word2vec02_asset_embeddings03_sentiment_evolutiongensim
Ch1506_fed_announcement_bststfcausalimpact(TFP BSTS)

按 envs/py312/Dockerfile 的注释,完整覆盖清单还包括 Ch0501_timegan/07_dp_gan、Ch0912_wasserstein_regimes、Ch1210_shap_nlp_sentiment、Ch1406_conditional_autoencoder(torch CUDA bug 或 shap 兼容性问题)。注意 Ch21 深度对冲不在其中——pfhedge0.22.0 在 Python 3.14 + numpy 2.3.5 下可以正常导入和定价,所以它仍是主镜像依赖。

3.2 使用方式

py312 服务挂在py312profile 下,需要显式启用:

docker compose --profile py312 pull py312 docker compose --profile py312 run --rm py312 python 05_synthetic_data/03_sigcwgan_signatures.py

3.3 隔离解释器 /opt/bsts:两个互相冲突的依赖集共存

py312 镜像里有一个容易忽略但很精妙的工程决策。tfcausalimpact要求pandas<=2.2与 NumPy 1.x,而 signature 栈(signatory/esig)要求 NumPy 2.x,二者在同一个 Python 3.12 环境内无法共存。解决方案是在同一个镜像内创建第二个独立 venv/opt/bsts/opt/ml4t解释器及其 numpy 2、gensim、pfhedge 依赖保持不变,BSTS 相关笔记本则显式调用/opt/bsts/bin/python

docker compose --profile py312 run --rm py312 \ /opt/bsts/bin/python 15_causal_estimation/06_fed_announcement_bsts.py

/opt/bsts同时注册了 Jupyter 内核:镜像里既安装了名为 "Python 3.12 (BSTS)" 的 ipykernel,又通过 envs/py312/kernels/bsts-quiet/kernel.json 提供静默版本,保证笔记本在 Jupyter 内也能选对解释器。py312 的专用依赖在 envs/py312/pyproject.toml 中声明(requires-python = ">=3.12,<3.13"),同样以 uv.lock 派生 constraint 钉版本。

3.4 Apple Silicon 用户怎么办

py312 没有原生 arm64 镜像(signatory/esig/gensim 均无 ARM wheel)。Apple Silicon 上有两条出路:直接阅读仓库里已提交的.ipynb运行输出,或在 Rosetta 下运行 amd64 镜像:

DOCKER_DEFAULT_PLATFORM=linux/amd64 docker compose --profile py312 run --rm py312 python ...

后者速度慢且无 GPU。需要 GPU 时,Compose 还提供了py312-gpu服务(同样仅 amd64),供六个 GPU 标记的 py312 笔记本使用。

四、benchmark 镜像:存储层基准测试专用

4.1 服务范围

Chapter 2 的存储基准测试需要在文件格式(Parquet、DuckDB、HDF5/PyTables)与多种时序数据库(TimescaleDB、ClickHouse、QuestDB、InfluxDB)之间横向对比读写性能。benchmark 镜像只包含这些客户端依赖(见 envs/benchmark/pyproject.toml:pyarrowduckdbtablesclickhouse-connectpsycopginfluxdb-clientquestdbpykx),体积仅约 1.7 GB。

4.2 标准流程

docker compose pull benchmark # 启动数据库服务(timescaledb、clickhouse、questdb、influxdb) 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 # 测试完成后停止数据库 docker compose --profile benchmark down

数据库连接信息全部通过环境变量注入(CLICKHOUSE_HOSTTIMESCALE_PORTINFLUXDB_ORG/TOKEN/BUCKET等,见 docker-compose.yml 中benchmark服务段),容器内直接连服务名(如ml4t-clickhouse)即可。

4.3 源码级细节:ARM64 与 kdb+

  • questdb 客户端在 ARM64 上从 sdist 编译:envs/benchmark/Dockerfile 为此用 rustup 安装了最新稳定版 Rust 工具链(Debian 自带 cargo 过旧),保证 amd64 和 arm64 都能成功构建。
  • kdb+/PyKX 许可不烧入镜像:kdb+ 许可属于个人资产,绝不进入发布的镜像。运行期把宿主机~/.kx~/.pykx以只读方式挂载进容器,并设置QLIC=/home/ml4t/.kxq从 QLIC 环境变量解析许可,仅文件存在不够)。没有许可时,21_storage_benchmark_database会跳过 kdb+ 并明确提示。
  • benchmark-full:x86 专属全集:ArcticDB 没有 Linux ARM64 wheel,因此完整版通过 envs/benchmark/Dockerfile.full 构建并强制platforms: [linux/amd64],挂在benchmark-fullprofile 下,Apple Silicon 上不可用。
  • 可复现性护栏:基准镜像同样从 uv.lock 派生态钉死 constraint。Dockerfile 注释记录了一个真实案例——若自由解析,会装到 pandas 3.0.2(lock 钉的是 2.3.3),而 pandas 3 让 HDF5 的symbol列每行宽约 8 字节,导致同样的面板数据从 71 MB 变成 79 MB,Chapter 2 的数字在镜像里无法复现。此外kaleido在此镜像中被限制<1.0(1.x 需要 Chrome,而基准镜像不携带),只影响静态图片导出、不影响基准数值。

五、rapids 镜像:Chapter 12 的 GPU GBM 基准

Chapter 12 的02_gbm_comparison需要在 GPU 上横向评测梯度提升库(RAPIDS cuML 的 XGBoost GPU、LightGBM CUDA、CatBoost GPU,外加 CPU 基线)。这是一套单一用途镜像,不是通用 ml4t 镜像:

docker compose --profile rapids build rapids docker compose --profile rapids run --rm rapids \ python 12_gradient_boosting/02_gbm_comparison.py

关键约束(来自 envs/rapids/Dockerfile 与 docker-compose.yml):

  • 基础镜像为nvcr.io/nvidia/rapidsai/base:25.04-cuda12.8-py3.12必须本地构建,无预构建版本,且仅支持 amd64(RAPIDS 无 ARM64),需要 NVIDIA GPU + nvidia-container-toolkit。
  • RAPIDS 是编译型环境,cuDF 25.4 要求pandas<2.2.4pyarrow<20,CuPy 要求numpy<2.3cudf-polars要求polars<1.26——所以除 scipy(跟随根 lock)外,基础镜像的科学计算包全部保持基线版本,只有 lock 之外的包才钉到 uv.lock。
  • LightGBM 从源码以USE_CUDA=ON编译,版本严格取自 uv.lock。Dockerfile 记录了 2026-08-10 的一次真实构建失败:浮动lightgbm>=4.6拉到 4.7.0,其 device-link 的libnccl_static.a是 CUDA-13 产物,nvcc 12.6 的 nvlink 无法读取(ABI version 不兼容),这正是版本必须钉死的原因。
  • GPU 验证无法在构建期完成(无 GPU 访问),构建期只验证库导入与 CUDA 支持报告,运行期由detect_gpu_capabilities()校验。
  • 镜像还内置benchmark-status脚本,打印平台架构并列出全部可用基准(Parquet/DuckDB/HDF5/ClickHouse/TimescaleDB/QuestDB/InfluxDB)。

六、Compose 编排:profile、挂载与环境变量

envs/README.md 里的所有命令都依赖仓库根目录的 docker-compose.yml,理解这份编排是灵活使用环境的前提:

  • 服务与 profile 一览ml4t(默认拉起)、ml4t-gpugpu)、benchmarkbenchmark)、benchmark-fullbenchmark-full)、rapidsrapids)、py312py312)、py312-gpupy312-gpu)、neo4jkg,知识图谱章节的图数据库)、timescaledb/postgres/clickhouse/questdb/influxdbbenchmark/benchmark-full/databases)。只有显式声明 profile 的服务才需要--profile参数启动,避免普通读者被无关容器拖累。
  • x-common 锚点(所有服务共享):
    • user: "${UID:-1000}:${GID:-1000}"——以宿主 UID/GID 运行,容器内生成的文件属主正确,且 Dockerfile 中"去掉--allow-root"的安全设计得以成立。
    • 三个挂载:仓库根目录.:/app:rw;数据目录${ML4T_DATA_PATH:-./data}:/data:rw(可写,因为 data/download_all.py 需要向 /data 写入);HuggingFace 缓存${HF_HOME:-${HOME}/.cache/huggingface}:/home/ml4t/.cache/huggingface:rw(可写,因为笔记本以local_files_only=True加载钉死的 checkpoint,必须能看到宿主缓存;首次运行还需先mkdir -p ~/.cache/huggingface,否则 Docker 以 root 创建绑定目录会导致权限失败)。
    • 环境变量:ML4T_DATA_PATH=/dataML4T_PATH=/appTEST(CI 用)、NEO4J_URI/USER/PASSWORDNUMBA_CACHE_DIR=/tmp/numba_cacheMPLCONFIGDIR=/tmp/matplotlibPOLARS_FMT_MAX_ROWS=20POLARS_FMT_STR_LEN=50VIRTUAL_ENV=/opt/ml4tUV_PROJECT_ENVIRONMENT=/opt/ml4t与显式 PATH。
    • 可选.env文件(required: false),stdin_open: true+tty: true支持交互式调试。
  • 端口约定ml4t8888、ml4t-gpu8889、benchmark/benchmark-full8887,全部只绑定 127.0.0.1;数据库端口(5437/5436/8123/9000/8086)也映射到本机,便于宿主侧排查。

七、目录结构:envs/ 内部布局

envs/ ├── README.md # 本文档所依据的环境说明 ├── ml4t/Dockerfile # 主镜像(Python 3.14,多架构) ├── py312/ │ ├── Dockerfile # Python 3.12,用于 signatory/esig/gensim/pfhedge/tfcausalimpact │ ├── pyproject.toml # py312 专用依赖 │ ├── bsts-pyproject.toml # /opt/bsts 隔离解释器的依赖 │ ├── bsts_kernel.py # BSTS 内核辅助 │ └── kernels/bsts-quiet/kernel.json ├── benchmark/ │ ├── Dockerfile # 基准镜像(含数据库客户端) │ ├── Dockerfile.full # x86 专属全集(含 ArcticDB) │ ├── pyproject.toml # 基准专用依赖 │ └── pyproject.full.toml # 全集依赖 ├── rapids/ │ ├── Dockerfile # RAPIDS cuML + LightGBM CUDA │ └── base_constraints.py # 冻结 RAPIDS 基线版本 ├── __init__.py ├── scan_imports.py # AST 扫描器(自动发现依赖) └── test_all_imports.py # 导入验证脚本(共 63 个包)

八、导入自检:每个镜像的健康检查

环境是否完好,不靠猜,靠"能不能 import"。每个镜像都内置了自检脚本 envs/test_all_imports.py,在 pull/build 之后运行一遍即可确认全部章节依赖可用:

# ml4t 镜像(镜像内固化的命令) docker compose run --rm ml4t ml4t-test-imports # 等价显式调用 docker compose run --rm ml4t python envs/test_all_imports.py # py312 镜像 docker compose --profile py312 run --rm py312 python envs/test_all_imports.py --image py312 # benchmark 镜像 docker compose --profile benchmark run --rm benchmark python envs/test_all_imports.py --image benchmark # 只测某个章节(并打印明细) docker compose run --rm ml4t python envs/test_all_imports.py --chapter 15 --verbose

8.1 各镜像的测试面

镜像第三方包ML4T 库Utils 模块覆盖章节
ml4t50 个6 个(data、engineer、models、diagnostic、backtest、live)22 个(4 个仓库级 + 18 个案例研究级)Ch01–Ch26
py3124 个(signatory、esig、gensim、tfcausalimpact)1 个(diagnostic)Ch05、Ch09、Ch10、Ch12、Ch14、Ch15
benchmark5 个(duckdb、tables、数据库客户端)0Ch02

包按章节分组测试,失败能直接映射到受影响的笔记本;退出码 0 表示全部通过,1 表示存在失败。在主镜像上跑测试时,py312 专属包只做提示性展示(informational),不算失败。

8.2 底层实现:从手工清单到 AST 自动发现

envs/test_all_imports.py 的核心是CHAPTER_PACKAGES/PY312_PACKAGES/BENCHMARK_PACKAGES三张按章节组织的包清单,并维护了一张IMPORT_MAP处理"包名 ≠ import 名"的情况(如scikit-learn → sklearnbeautifulsoup4 → bs4ml4t-data → ml4t)。它还会重点校验 14 个历史安装高危包(pymc、arviz、riskfolio、chronos、stable_baselines3、feast 等),并单独测试ml4t.*六个库与 22 个 utils 模块。

更有意思的是--scan模式:它调用 envs/scan_imports.py,用 AST 遍历仓库全部.py文件,自动提取所有顶层第三方 import(包括函数内、try块内、TYPE_CHECKING守卫内的依赖),剔除标准库和仓库自身模块(自动识别{name}.py{name}/__init__.py),再按IMAGE_OVERRIDES分类到对应镜像:

# 推荐在容器内用 --scan 做读者自检:新依赖会被自动发现 docker compose run --rm ml4t python envs/test_all_imports.py --scan # 只列出某镜像应导入的包,不实际 import python envs/scan_imports.py --image py312 --list

手工清单保证输出稳定,AST 扫描保证不遗漏新依赖,二者配合形成了"环境与仓库永不脱节"的护栏——这也与仓库测试体系中的导入覆盖测试相呼应。

九、本地构建与适用前提

如果不想从 Docker Hub 拉取,也可以从源码构建(构建耗时因平台差异较大):

docker compose build ml4t # x86 约 45 分钟,ARM64 约 15 分钟 docker compose --profile py312 build py312 # 约 30 分钟 docker compose --profile benchmark build benchmark # 约 10 分钟

几点前提与限制总结:

  • 平台支持矩阵:Linux/Windows x86_64 全功能(GPU 可选);macOS Intel 除 GPU 外全功能;Apple Silicon 原生支持ml4tbenchmarkpy312需 Rosetta 或直接读提交的 notebook 输出,benchmark-fullrapids不可用。
  • GPU 前置条件ml4t-gpupy312-gpurapids均要求 NVIDIA GPU 且宿主安装 nvidia-container-toolkit;rapids还必须本地构建。
  • kdb+:可选,个人许可挂载后才会参与基准;无许可时对应笔记本自动跳过。
  • 目录挂载:首次运行前确保数据目录与~/.cache/huggingface存在,避免 Docker 以 root 创建导致权限问题。

结语

这套环境体系把"多架构、多 Python 版本、多 GPU 栈"的冲突收敛成四个边界清晰的镜像与一份 Compose 编排:主镜像ml4t覆盖 99% 场景,py312兜底没有 3.14 wheel 的依赖并以内嵌/opt/bsts隔离解释器解决依赖冲突,benchmarkrapids服务特定章节的存储/GPU 基准;而uv.lock派生的全量版本钉死、AST 驱动的导入自检与按章节分组的失败映射,则保证了容器内环境与读者本地uv sync环境的可复现性和一致性。无论你是想快速跑通一个笔记本、复现 Chapter 2 的存储基准,还是做 GPU 梯度提升对比,都可以据此选择正确的镜像与 profile,一步到位。

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

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

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

立即咨询