跳到正文

Notebook 的局限性:为什么 Jupyter 无法支撑量化工作流

Jupyter notebooks 适合探索但不适合生产量化系统。理解其局限性防止你构建脆弱的工作流。

第 5 篇 · 共 8 篇 约 2 分钟

Jupyter notebooks 是量化研究的默认环境。它们非常适合探索:你可以逐个单元格运行代码、内联可视化数据、快速迭代。但作为量化系统的生产平台,notebooks 有根本性局限,造成脆弱性、bug 和维护噩梦。

核心问题:Notebooks 是伪装的脚本

Notebook 是一个包含代码单元格及其输出的 JSON 文件。它是一个 交互式脚本,不是一个结构化程序。随着你的量化系统增长,这会产生问题。

问题 1:执行顺序依赖

Notebooks 按用户定义的顺序执行单元格,而不是按依赖顺序。这意味着:

  • 单元格 5 可能使用单元格 3 中定义的变量,但你本次会话还没运行单元格 3
  • 单元格 7 的输出可能来自之前运行的单元格 4,已经过时
  • 乱序运行单元格会产生错误结果但没有报错

解决方案: 使用有清晰导入层次结构的 .py 文件。Notebooks 只用于探索。

问题 2:无测试基础设施

Notebooks 没有内置方式来编写和运行测试。你可以在单元格中调用 assert,但:

  • 测试不会跨会话持久化
  • 没有测试运行器(pytest, unittest)
  • 「运行时工作了」的代码在生产中可能出问题

解决方案: 在 .py 文件中编写生产代码。在 notebooks 中导入它们进行探索。

问题 3:Notebooks 版本控制困难

Notebook JSON 以 diff 和合并而闻名。notebook 的小更改会产生大量难以阅读的 JSON diff。这使得协作开发变得痛苦。

解决方案: 使用 nbdime 或 nbconvert 在 git 操作前去除输出。或对所有重要内容使用 .py 文件。

问题 4:状态泄漏

关闭并重新打开 notebook 不会清除状态。变量跨会话持久化。这意味着:

  • 「昨天它工作了」毫无意义
  • 你无法通过从头重新运行 notebook 来复现结果

正确的架构

project/
├── requirements.txt
├── src/
│   ├── factors/
│   │   ├── momentum.py      # 经过测试,可用于生产
│   │   └── tests/
│   │       └── test_momentum.py
│   ├── data/
│   │   └── fetch.py
│   └── backtest/
│       └── engine.py
├── notebooks/
│   ├── exploration/
│   │   └── momentum_discovery.ipynb   # 仅用于探索
│   └── validation/
│       └── backtest_validation.ipynb
└── scripts/
    └── run_backtest.py

Notebooks 只放在 notebooks/exploration/ 和 notebooks/validation/。所有生产代码放在 src/。

何时使用 Notebooks

适合:

  • 初始数据探索和可视化
  • 一次性分析
  • 与非工程师分享结果
  • 信号想法的原型设计

不适合:

  • 生产系统
  • 需要测试的任何东西
  • 协作开发
  • 需要每天可靠运行的代码

参考文献

  • McKinney, Python for Data Analysis, 附录. O’Reilly, 2023. ISBN: 978-1-492-07231-9.
  • Ramalho, Fluent Python, 第 9 章. O’Reilly, 2022. ISBN: 978-1-492-05635-8.
  • López de Prado, Advances in Financial Machine Learning, 第 1 章. Wiley, 2018. ISBN: 978-1-119-48208-6.