连载第 1 期:从零构建我的量化系统——为什么我先选 backtrader,又为什么在第 3 天想放弃
量化系统自建实录第一篇。选型、环境搭建、Python 3.13 兼容性问题排查,以及第一次想把编辑器关掉的那个晚上。
- 本地 Python 虚拟环境(uv + Python 3.12.7)
- backtrader 最小示例跑通,输出净值曲线
- AKShare 日线数据拉取 + CSV 落盘
- requirements 锁定文件(保证可复现)
- 实盘对接 QMT
- 滑点与手续费模型
- 多标的组合回测
- point-in-time 财务数据管道
- 把数据管道从「直接读 CSV」改成带校验的加载层
- 给回测加第一版陷阱自检:未来函数扫描 + 前视偏差检查
本系列记录一个研发经理从零构建量化系统的真实过程。不是教程,是实录——包括走弯路、返工、想放弃的时刻。只谈工程与方法,不谈标的、不做投资建议。
本期做了什么
这周的目标本来很小:把本地回测环境跑起来,用一份日线数据跑通一个最小策略。
实际发生的事情是:
- 花半天做框架选型,选了 backtrader;
- 花一天写环境脚本,自以为很稳;
- 第 3 天被 Python 3.13 的兼容性问题打崩心态;
- 又花一天排查、降级、验证;
- 周末终于跑通,但留下了 3 条决定要写进规范的教训。
选型:为什么先试 backtrader
我的需求清单其实很朴素:
| 需求 | 重要度 | 说明 |
|---|---|---|
| 纯本地运行 | 高 | 研究阶段不碰实盘接口 |
| 事件驱动或向量化都行 | 中 | 先跑通,不纠结架构 |
| 社区资料多 | 高 | 出问题要搜得到答案 |
| 许可证友好 | 高 | 未来可能商用衍生品 |
| 支持 A 股日线回测 | 高 | 当前只做日线 |
候选是三个:backtrader、vectorbt、vnpy。
- vectorbt 很快,但许可证里带 Commons Clause,禁止把它的功能打包成收费交付物。对我这种「未来可能做数字产品」的规划来说是个雷区——教学可以,产品底座不行。
- vnpy 是全栈方案,事件引擎、实盘接口都有,但对「我只想先跑个日线回测」来说太重了。
- backtrader 是 GPL-3.0,社区资料最多、概念最贴近我熟悉的事件驱动模型,先拿它入门最稳。
结论:先用 backtrader 学概念,未来产品底座自研或选 MIT/Apache 系。
第 3 天:撞墙
环境脚本我写得很自信:
# 环境搭建脚本(节选)
uv venv .venv --python 3.13
source .venv/bin/activate
uv pip install backtrader matplotlib pandas
装是装上了。然后跑最小示例:
import backtrader as bt
cerebro = bt.Cerebro()
cerebro.broker.setcash(100_000)
print('启动资金:', cerebro.broker.getvalue())
cerebro.run()
print('结束资金:', cerebro.broker.getvalue())
输出直接给我一记暴击:
ModuleNotFoundError: No module named 'collections.MutableMapping'
不是示例代码的问题,是 backtrader 在 Python 3.13 下的依赖链炸了——collections.MutableMapping 这类 ABC 别名在 Python 3.10 就被移除了,旧版依赖还在用。
排查过程
第一步:确认是依赖问题而不是我的代码问题。 用干净环境复现:
uv venv /tmp/probe --python 3.13
uv pip install backtrader
python -c "import backtrader"
3.13 稳定复现,3.12 正常。锁定解释器版本是触发条件。
第二步:找到具体炸点。 完整 traceback 指向一条间接依赖,它 import 了旧路径的 collections 抽象类:
# 出问题的用法(示意)
from collections import MutableMapping # Python 3.10+ 已移除
# 正确写法
from collections.abc import MutableMapping
第三步:决策——等上游修复,还是降级 Python?
查了一圈 issue,上游修复的节奏不可控。我的需求是「这周跑通」,不是「贡献 patch」。所以决定:
# 回退到 Python 3.12
uv venv .venv --python 3.12
uv pip install backtrader matplotlib pandas
跑通了。数字终于对了。
为什么第 3 天想放弃
说真的,第 3 天晚上我关掉了编辑器。不是因为技术多难——一个 import 问题而已——而是因为一种熟悉的挫败感:明明是「跑个示例」这种最简单的一步,却要先给整个生态做一次考古。
后来我想明白了一件事:量化系统的工程复杂度,大部分不来自策略,而来自环境、数据和复现性。策略代码可以 20 行写完,但让这 20 行在半年后还能跑出一样的数字,是一套完全不同的工程问题。
这恰恰是我想持续记录的东西——不是「我用了什么策略」,而是「我怎么把这个系统搭起来」。
留下的 3 条规范
这次踩坑直接变成了我自己的工程规范:
- Python 版本锁定到小版本。
requires-python = ">=3.12,<3.13",锁文件入库。「用最新解释器」在研究阶段不是美德,是风险。 - 所有实验必须能一键复现。 脚本、锁文件、数据快照版本号三件套,缺一个就不算完成。
- 每次跑通都要留 evidence 快照:环境、版本、数据来源、验证时间。写文章要用,做产品更要用。
下期预告
两件事:把数据管道从「直接读 CSV」升级成带校验的加载层;给回测结果加第一版陷阱自检——先查未来函数和前视偏差,再看收益率曲线。
本系列只讨论工程实现与方法论,不构成任何投资建议。