从数据到实盘: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 Hub | Python | 平台 | 体积 |
|---|---|---|---|---|
| ml4t(主镜像) | ml4t/ml4t:latest | 3.14 | amd64 + arm64 | ~12 GB / ~3 GB |
| py312 | ml4t/ml4t-py312:latest | 3.12 | 仅 amd64 | ~9.6 GB |
| benchmark | ml4t/ml4t-benchmark:latest | 3.14 | amd64 + arm64 | ~1.7 GB |
| rapids | 本地构建 | 3.12 | amd64 + 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_signatures | signatory |
Ch0906_path_signatures | signatory、esig |
Ch1001_word2vec、02_asset_embeddings、03_sentiment_evolution | gensim |
Ch1506_fed_announcement_bsts | tfcausalimpact(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.py3.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:pyarrow、duckdb、tables、clickhouse-connect、psycopg、influxdb-client、questdb、pykx),体积仅约 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_HOST、TIMESCALE_PORT、INFLUXDB_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/.kx(q从 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.4、pyarrow<20,CuPy 要求numpy<2.3,cudf-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-gpu(gpu)、benchmark(benchmark)、benchmark-full(benchmark-full)、rapids(rapids)、py312(py312)、py312-gpu(py312-gpu)、neo4j(kg,知识图谱章节的图数据库)、timescaledb/postgres/clickhouse/questdb/influxdb(benchmark/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=/data、ML4T_PATH=/app、TEST(CI 用)、NEO4J_URI/USER/PASSWORD、NUMBA_CACHE_DIR=/tmp/numba_cache、MPLCONFIGDIR=/tmp/matplotlib、POLARS_FMT_MAX_ROWS=20、POLARS_FMT_STR_LEN=50、VIRTUAL_ENV=/opt/ml4t、UV_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 --verbose8.1 各镜像的测试面
| 镜像 | 第三方包 | ML4T 库 | Utils 模块 | 覆盖章节 |
|---|---|---|---|---|
| ml4t | 50 个 | 6 个(data、engineer、models、diagnostic、backtest、live) | 22 个(4 个仓库级 + 18 个案例研究级) | Ch01–Ch26 |
| py312 | 4 个(signatory、esig、gensim、tfcausalimpact) | 1 个(diagnostic) | — | Ch05、Ch09、Ch10、Ch12、Ch14、Ch15 |
| benchmark | 5 个(duckdb、tables、数据库客户端) | 0 | — | Ch02 |
包按章节分组测试,失败能直接映射到受影响的笔记本;退出码 0 表示全部通过,1 表示存在失败。在主镜像上跑测试时,py312 专属包只做提示性展示(informational),不算失败。
8.2 底层实现:从手工清单到 AST 自动发现
envs/test_all_imports.py 的核心是CHAPTER_PACKAGES/PY312_PACKAGES/BENCHMARK_PACKAGES三张按章节组织的包清单,并维护了一张IMPORT_MAP处理"包名 ≠ import 名"的情况(如scikit-learn → sklearn、beautifulsoup4 → bs4、ml4t-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 原生支持
ml4t与benchmark,py312需 Rosetta 或直接读提交的 notebook 输出,benchmark-full与rapids不可用。 - GPU 前置条件:
ml4t-gpu、py312-gpu、rapids均要求 NVIDIA GPU 且宿主安装 nvidia-container-toolkit;rapids还必须本地构建。 - kdb+:可选,个人许可挂载后才会参与基准;无许可时对应笔记本自动跳过。
- 目录挂载:首次运行前确保数据目录与
~/.cache/huggingface存在,避免 Docker 以 root 创建导致权限问题。
结语
这套环境体系把"多架构、多 Python 版本、多 GPU 栈"的冲突收敛成四个边界清晰的镜像与一份 Compose 编排:主镜像ml4t覆盖 99% 场景,py312兜底没有 3.14 wheel 的依赖并以内嵌/opt/bsts隔离解释器解决依赖冲突,benchmark与rapids服务特定章节的存储/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),仅供参考