回测框架对比 — vectorbt vs backtrader vs Lean
回测框架的核心抽象(向量化 vs 事件驱动)、三大主流框架(vectorbt / backtrader / Lean)的设计哲学与适用边界
日期: 2026-05-14 方向: 个人量化交易 / 回测工具链 阶段: Phase 1: 基础与工具链 标签: #Backtest #vectorbt #backtrader #Lean #QuantConnect #Vectorized #EventDriven
今日目标
| 类型 | 内容 |
|---|---|
| 学习 | 回测框架的核心抽象(向量化 vs 事件驱动)、三大主流框架(vectorbt / backtrader / Lean)的设计哲学与适用边界 |
| 实操 | 同一个 SMA(20,50) on SPY 策略,用三个框架各写一份「hello world」对比代码风格 |
| 产出 | TR-DAY5 笔记 + 三段最小可跑代码 + Phase 1/2/3 三阶段的框架选型决策 |
一、为什么 Day 5 必须先做框架对比
Day 1-4 已经把 数据来源 和 执行通道 搭好了:IBKR Paper 通了、ib_insync 能下单、yfinance/Polygon 能拉历史 bar。下一步自然是「把策略跑起来」。
但「跑起来」这件事有个隐藏分叉:
路径 A:直接用 pandas 写信号 + 自己写 PnL 累加
→ 短期最快,3 天后会发现:滑点、佣金、re-balance、生存偏差
每加一条都要改一次循环结构 → 代码烂掉
路径 B:选一个回测框架,按它的抽象写策略
→ 短期慢 2-3 天(学 API),但后续每加一个策略都是「填模板」
→ 而且这个选择会影响 Phase 2(期权)和 Phase 3(实盘)
90 天是一段不长不短的时间——用什么框架,几乎决定了 30 天后的代码能不能复用、60 天后能不能加期权、90 天后能不能直接对接 IBKR。所以 Day 5 不是「先学一个框架的语法」,而是 「先做架构决策」。
PM 视角:这和企业系统选 message queue(Kafka / RabbitMQ / SQS)、选 ORM(SQLAlchemy / Django ORM / 原生)是同一类问题。选错的代价不在「这个框架做不了什么」,而在「这个框架强迫你怎么思考」。
二、回测框架的核心抽象:向量化 vs 事件驱动
回测框架表面上千差万别,底层只分两大流派。理解这两个抽象,比记任何一个框架的 API 都重要。
2.1 向量化(Vectorized)
输入:N×T 的价格矩阵(N 个标的,T 个时间步)
信号:在矩阵上做向量运算 → N×T 的布尔/权重矩阵
仓位:信号矩阵 → 持仓矩阵
PnL:持仓 × 收益 → 累加得到曲线
心智模型:把整个回测视为「N×T 张表上的一次性矩阵运算」。所有时间步同时计算,没有 for 循环遍历每个 bar。
# 概念伪代码
prices = data.values # shape (T, N)
sma_short = rolling_mean(prices, 20)
sma_long = rolling_mean(prices, 50)
entries = sma_short > sma_long # shape (T, N) bool
exits = sma_short < sma_long
# entries / exits 一次性算出整个时间维度
优点:
- 极快。底层基本是 numpy/numba/CUDA,T=10 年 × N=500 stocks × M=1000 参数组合,秒级完成
- 参数扫描友好。要扫
(short, long)网格?把第三维加上去,prices变成 (T, N, M),运算逻辑不变 - 对因子研究天然友好。截面排序、IC 计算、分组回测,本来就是矩阵操作
缺点:
- 路径依赖难表达。「上一笔成交价是 X,所以下一笔触发 stop loss」——这种「依赖于上一笔成交后状态」的逻辑,向量化里很别扭,必须先全量算出 entries/exits,再回头模拟成交
- 持仓状态机复杂时崩溃。Wheel 策略「卖 CSP→被 assign→变 CC→被 called away→回到现金」这种状态机,硬要向量化会写得像谜语
- 撮合细节失真。partial fill、市价滑点、订单簿冲击——这些都是「事件级」概念,向量化只能近似
2.2 事件驱动(Event-Driven)
循环:for each bar in timeline:
on_bar(bar):
# 此时只看得到 bar.time 之前的数据
# 调用 self.position / self.broker / self.indicators
# 决定:buy / sell / hold
# 引擎把订单送进 simulated broker → fill 在下一个 bar
心智模型:把回测视为「时间线上一个个事件依次到达,策略对每个事件做出决策」。和你最终在实盘里做的事是同构的。
# 概念伪代码(backtrader 风格)
class MyStrategy(Strategy):
def __init__(self):
self.sma_short = SMA(self.data.close, period=20)
self.sma_long = SMA(self.data.close, period=50)
def next(self): # 每个 bar 调用一次
if not self.position and self.sma_short > self.sma_long:
self.buy()
elif self.position and self.sma_short < self.sma_long:
self.close()
优点:
- 表达自然。决策代码和你脑子里的策略思考完全对应
- 路径依赖 0 成本。
self.position.avg_price直接拿来就用 - 状态机友好。可以维护任意复杂的 self.state
- 回测 → 实盘可平移。同一个
next()方法,回测时驱动它的是历史 bar,实盘时驱动它的是 live tick——理论上策略代码不动
缺点:
- 慢。Python for 循环遍历 T 个 bar,每个 bar 调用
next(),单线程下 T=10 年 × 1 个标的可能就要 30 秒 - 参数扫描痛苦。每组参数都得跑一遍完整回测,1000 组参数 = 8 小时
- 截面策略别扭。「当天涨幅前 10% 买入」——事件驱动里要在每个 bar 自己去对所有标的排序,性能糟糕
2.3 一句话判别:什么场景用什么
| 场景 | 推荐范式 | 原因 |
|---|---|---|
| 截面因子(动量/价值/低波) | 向量化 | 横截面排序 + 大量参数扫描 |
| 多标的组合优化 | 向量化 | 矩阵代数 |
| Walk-forward 参数搜索 | 向量化 | 性能差几个数量级 |
| 单标的状态机(Wheel/Pyramid) | 事件驱动 | 路径依赖 |
| 期权多腿策略 + 滚动 | 事件驱动 | 持仓状态复杂 |
| 实盘 paper trade | 事件驱动 | 与实盘同构 |
| 高频微结构回放 | 事件驱动 | 必须按 tick 顺序 |
核心洞察:向量化是「研究工具」,事件驱动是「生产工具」。两者不是替代关系,是流水线上不同工位。
三、vectorbt:因子研究的瑞士军刀
3.1 设计哲学
vectorbt 是个极端的向量化主义者。它的核心信念:「任何回测都可以表达为 numpy/numba 上的矩阵运算」。
底层栈:
- numpy 矩阵存储
- numba JIT 编译加速(写 Python 但跑出 C 速度)
- pandas 兼容(输入 DataFrame)
- plotly 可视化
它的所有 API 围绕一个核心对象:Portfolio。从 entries/exits 信号矩阵创建 Portfolio,自动算出持仓、PnL、各种统计指标。
3.2 优点(为什么因子研究人都在用它)
(1) 性能恐怖。
笔者实测:10 年日线 × 100 个 ETF × 5000 组参数
vectorbt: ~3 秒
backtrader: 估算 8-12 小时
(2) 参数扫描是 first-class citizen。
# 一次扫 100×100 = 10000 组参数
short_windows = np.arange(5, 105)
long_windows = np.arange(50, 250, 2)
pf = vbt.Portfolio.from_signals(
close=prices,
entries=..., # shape (T, 100, 100)
exits=...,
init_cash=10000,
)
# pf.stats() 直接返回 10000 行的统计表
(3) 因子分析工具链全。
- IC / Rank IC 内置
- Sharpe / Sortino / Calmar / MaxDD 一行代码
- 分位数分组(quantile portfolios)一行代码
- Walk-forward 一行代码
(4) 与 pandas/numpy 生态无缝。signal 矩阵就是 DataFrame,可以直接做 SQL-like 操作。
3.3 缺点(为什么不是所有人都用它)
(1) API 学习曲线像悬崖。
- 文档算不上烂但很跳跃,新人很容易在
Portfolio.from_signalsvsfrom_ordersvsfrom_holding里迷失 - 命名约定有自己一套(IndexAccessor、ColumnAccessor 之类),不直觉
- 错误信息常常是 numba 编译报错,对新手很不友好
(2) 事件驱动场景表达困难。
# 例:「我想要平仓时根据当前盈亏决定下一次开仓的 size」
# vectorbt:要么先全量算出 exits,再用 callback 函数(性能下降很多)
# backtrader:on_trade_close 里直接拿到 trade.pnl,1 行代码
(3) 期权支持薄弱。它本质是 spot/futures 思维,期权的多腿组合、希腊字母调整、IV 曲面交互都不是它擅长的。
(4) 社区相对小。Stack Overflow 上 backtrader 标签问题 ~5000,vectorbt ~500(截至 2026 年)。卡住时找答案更难。
(5) Pro 版很贵。免费版功能足够研究用,但 Pro(约 $400/年)的高级功能(多账户、live 数据流、portfolio optimizer)对认真用户几乎是必需。
3.4 适合场景
| 场景 | 强烈推荐 vectorbt |
|---|---|
| 因子研究(动量/反转/质量等) | ✓✓✓ |
| 大规模参数扫描 | ✓✓✓ |
| 多标的组合回测 | ✓✓ |
| Walk-forward / Cross-validation | ✓✓ |
| 期权策略 | ✗ |
| 实盘部署 | ✗(不是它的目标) |
四、backtrader:经典事件驱动
4.1 设计哲学
backtrader 是 2015 年起的老牌项目,纯 Python OOP 事件驱动。设计思路非常「Java engineer 写 Python」:
Strategy类:用户继承,写next()方法Cerebro引擎:组装数据、策略、broker、analyzerIndicators:声明式(在__init__里定义,引擎自动算)Analyzers:插件式(Sharpe、SQN、TradeAnalyzer 等都是插件)Observers:可视化插件
代码结构高度规范化,看一份 backtrader 策略和看另一份,模板基本一样。
4.2 优点
(1) 路径依赖策略首选。
def next(self):
# 直接拿到当前持仓、平均成本、未实现盈亏
if self.position:
unreal_pnl = self.position.size * (self.data.close[0] - self.position.price)
if unreal_pnl < -1000: # 路径依赖的 stop loss
self.close()
(2) 文档/教程/书都丰富。Algorithmic Trading with Python、Quantitative Trading with R 那批书很多用 backtrader 做示例。
(3) 与实盘同构。同一个 Strategy 类,回测时挂 BacktestBroker,实盘时挂 IBStore(IBKR 桥接),策略代码几乎不改。
(4) Analyzer 生态成熟。一行 cerebro.addanalyzer(bt.analyzers.SharpeRatio) 就有 Sharpe;TradeAnalyzer 给你完整的 trade-by-trade 表。
(5) 自定义指标和数据源容易。Indicator 子类几行就能写一个,不需要懂底层。
4.3 缺点
(1) 性能差。单线程 Python for 循环,10 年日线单标的约 5-30 秒。对参数扫描场景,扫 1000 组就是几小时。
(2) 维护停滞。原作者 Daniel Rodriguez 几乎不再更新(最后一次 release 在 2019)。社区 fork 了 backtrader2,但生态分裂。
(3) 多标的截面操作笨拙。要在 next() 里手动循环所有 data feeds 然后排序,写起来很啰嗦。
(4) 期权支持基本没有。可以塞期权数据,但希腊字母、链查询、多腿策略都得自己造轮子。
(5) IBKR 桥接(IBStore)不稳定。社区维护,IBKR API 升级跟不上时经常报错。建议:实盘别用 backtrader 直接连 IBKR,用 ib_insync 单独跑实盘。
4.4 适合场景
| 场景 | 推荐 backtrader |
|---|---|
| 单标的状态机策略(Wheel / Pyramid / Martingale) | ✓✓✓ |
| 路径依赖逻辑(trailing stop / chandelier exit) | ✓✓✓ |
| 教学/学习事件驱动思维 | ✓✓ |
| 中等规模参数扫描(< 100 组) | ✓ |
| 大规模因子研究 | ✗ |
| 严肃实盘部署 | △(用其他方式更稳) |
五、Lean (QuantConnect):工业级全栈
5.1 设计哲学
Lean 是 QuantConnect 公司开源的回测/实盘统一引擎。核心特点:
- C# 写的核心引擎,Python 是 wrapper。性能比纯 Python 框架高 5-10 倍
- 云端 + 本地双模式。在 quantconnect.com 网站上写代码直接跑(用他们的数据),或者本地 docker 跑(用自己的数据)
- 回测和实盘是同一个引擎。从「在网页里点 Backtest」到「点 Live Trade」是一个开关
- 数据生态最完整:股票/期权/期货/外汇/加密货币 + tick 级别 + 期权链全希腊字母
5.2 优点
(1) 期权支持是其他框架望尘莫及的。
def OnData(self, slice):
chain = slice.OptionChains.get(self.option_symbol)
if chain:
atm = sorted(chain, key=lambda x: abs(x.Strike - self.spy.Price))[0]
# x.Greeks.Delta / Gamma / Theta / Vega / Rho 全都有
# x.ImpliedVolatility 自动算
(2) 实盘部署是产品级。
- 直接对接 IBKR / Coinbase / OANDA / Bitfinex / Tradier 等十多家券商
- 云端 7×24 不停机(QuantConnect 替你管服务器)
- 一个滑块切换回测↔Paper↔实盘
(3) 数据集稳定且历史长。tick 数据回到 1998 年(美股)/ 2014 年(期权)。
(4) 多资产同时。一个 Algorithm 类里可以同时管 SPY 股票 + SPY 期权 + ES 期货,统一的下单接口。
(5) 社区库 Alpha Streams。别人写好的 Alpha 模型可以直接加载到自己的策略里。
5.3 缺点
(1) 本地搭建复杂。需要 docker / .NET runtime / 配置数据目录 / 配置 Lean.json。文档多但杂,初次跑通常要 1-2 天。
(2) C# 内核偶尔反直觉。Python wrapper 不是 100% 覆盖,某些场景 C# 的类型系统泄漏到 Python(比如 Decimal vs float 转换)。报错信息有时是 C# stack trace。
(3) 数据订阅贵。云端跑回测免费,但 Live Trading 一档约 $20/月,加 Pro 数据可能 $100-$300/月。期权 tick 数据更贵。
(4) 锁定到 QuantConnect 生态。代码可以拷出来本地跑,但 cloud 上的 Alpha Streams、Object Store、社区分享的 dataset 出来就不能用。
(5) 调试体验一般。云端 print 出来要等好几秒;本地 docker 调试虽然能上断点但配置麻烦。
5.4 适合场景
| 场景 | 推荐 Lean |
|---|---|
| 严肃期权策略(多腿/希腊字母/IV) | ✓✓✓ |
| 多资产组合(股票+期权+期货) | ✓✓✓ |
| 想要回测↔实盘 0 切换 | ✓✓✓ |
| 不想自己管理服务器 | ✓✓ |
| 简单股票动量策略 | △(杀鸡用牛刀) |
| 大规模参数扫描 | △(云端贵) |
六、六维对比表
| 维度 | vectorbt | backtrader | Lean |
|---|---|---|---|
| 性能 | ★★★★★ 极快(numba) | ★★ 单线程慢 | ★★★★ C# 内核 |
| 易用性 | ★★ 学习曲线陡 | ★★★★ 模板清晰 | ★★★ 文档多但杂 |
| 期权支持 | ★ 几乎没有 | ★ 要自己造 | ★★★★★ 工业级 |
| 实盘部署 | ★ 不是目标 | ★★ 社区桥接弱 | ★★★★★ 一键切换 |
| 社区活跃度 | ★★★ 在涨 | ★★★ 老但停滞 | ★★★★ 商业支持 |
| 价格 | ★★★★ 免费/Pro $400/年 | ★★★★★ 全免费 | ★★ Live + 数据贵 |
怎么读这张表:没有任何一个框架在所有维度都最好。选框架就是在选「我愿意为哪些维度付出代价」。
七、其他相关工具(了解即可)
7.1 zipline
- Quantopian 公司的事件驱动框架,2020 年公司倒闭后基本停止维护
- 社区有 zipline-reloaded fork,能跑但生态边缘化
- 现在不要从 zipline 起步,知道有这个东西就行
7.2 pyfolio
- Quantopian 出的 portfolio analytics 库
- 单独用于「事后分析」:给一组每日 returns,画出 tear sheet(含 rolling Sharpe、drawdown、sector exposure 等)
- 与 backtrader / zipline 集成天然
- vectorbt 内置了类似功能,所以 vectorbt 用户用得少
7.3 quantstats
- 比 pyfolio 更轻量、更快的分析工具
- 一行
quantstats.reports.html(returns, benchmark='SPY')出一个完整 HTML 报告 - 强烈推荐:不管用哪个回测框架,最终把 returns 喂给 quantstats 出 tear sheet
7.4 nautilus_trader
- 后起之秀(Rust + Python),事件驱动
- 性能介于 backtrader 和 Lean 之间,期货/外汇/crypto 友好
- 学习成本不低,文档还不全
- 留意但 Phase 1 不上车
八、我们的选型决策
回到 90 天计划的实际路径:
Phase 1(Week 1-4,因子研究 + 基础回测)→ vectorbt
理由:
- 这阶段我要扫几百组参数(比如 20 个动量窗口 × 10 个 holding period × 5 个 universe)。事件驱动几小时,向量化几秒
- 因子研究就是横截面操作 + IC 分析,vectorbt 的工具链贴合
- 学曲线陡的代价此刻最小:30 天里反复用同一个框架,投入产出比最高
Phase 2(Week 5-8,期权策略)→ vectorbt 基础版 + 选择性引入 Lean
理由:
- 简单的 covered call / cash-secured put(单腿、月度滚动)vectorbt 能凑合表达
- 一旦上多腿(spread / iron condor / 财报跨式)或希腊字母管理 → 切 Lean
- 决策点:到 Day 49 期权基础学完后,根据策略复杂度决定是不是要花 2 天搭 Lean 本地环境
- 不用 backtrader 的原因:期权支持太弱,造轮子不值得
Phase 3(Week 9-12,实盘部署)→ ib_insync + APScheduler,不用任何回测框架
理由(这点很反直觉,需要展开):
- 「回测框架」和「实盘执行框架」最好是 解耦的两个系统
- 回测框架要解决的是「在历史数据上模拟」,实盘要解决的是「与真实 broker 交互」——表面上同构,底层错误模式完全不同(实盘里 partial fill / reject / 网络断连 / IBKR 强制重启都得处理)
- 让回测框架直接连实盘的产品(backtrader-ib / Lean Live)经常因为 broker API 变更而崩
- 更稳健的架构:
研究层(vectorbt/Lean)→ 输出策略参数 + 信号生成函数 ↓ 执行层(ib_insync 直连 + APScheduler 定时)→ 调用信号函数 + 下单 ↓ 监控层(Prometheus + Grafana 或简单 log)→ 实时观测 - 这意味着 策略逻辑要被设计成「无状态信号函数」:输入是历史数据 + 当前持仓,输出是订单意图。这样它在回测里被 vectorbt 调用,在实盘里被 ib_insync 调用,逻辑同一份
PM 视角:这是经典的「研究环境 vs 生产环境」分层。和 Web2 公司里「数据科学家用 Jupyter 训模型,工程团队把模型重写成 Go 服务」是一样的架构原则。让每层做它最擅长的,不要追求「一套代码全通用」的幻象。
九、三框架 Hello World 对比:SMA(20,50) on SPY
同一个策略:当 SMA(20) 上穿 SMA(50) 时全仓买入 SPY,下穿时全部平仓。10 年日线,初始资金 $10,000。
9.1 vectorbt 版本
# tr_day5_vbt.py
import yfinance as yf
import vectorbt as vbt
# 拿数据
prices = yf.download('SPY', start='2015-01-01', end='2025-01-01')['Close']
# 算指标
sma_short = vbt.MA.run(prices, window=20).ma
sma_long = vbt.MA.run(prices, window=50).ma
# 信号矩阵
entries = sma_short.vbt.crossed_above(sma_long)
exits = sma_short.vbt.crossed_below(sma_long)
# 一行回测
pf = vbt.Portfolio.from_signals(
close=prices,
entries=entries,
exits=exits,
init_cash=10000,
fees=0.0005, # 5 bps
freq='1D',
)
# 结果
print(pf.stats())
pf.plot().show()
风格:声明式 + 矩阵思维。看不到 for 循环,所有时间点同时算完。
9.2 backtrader 版本
# tr_day5_bt.py
import backtrader as bt
import yfinance as yf
class SmaCross(bt.Strategy):
params = (('p_short', 20), ('p_long', 50))
def __init__(self):
self.sma_short = bt.indicators.SMA(self.data.close, period=self.p.p_short)
self.sma_long = bt.indicators.SMA(self.data.close, period=self.p.p_long)
self.crossover = bt.indicators.CrossOver(self.sma_short, self.sma_long)
def next(self):
if not self.position and self.crossover > 0:
self.buy(size=int(self.broker.getcash() / self.data.close[0]))
elif self.position and self.crossover < 0:
self.close()
cerebro = bt.Cerebro()
cerebro.addstrategy(SmaCross)
data = bt.feeds.PandasData(dataname=yf.download('SPY', '2015-01-01', '2025-01-01'))
cerebro.adddata(data)
cerebro.broker.setcash(10000)
cerebro.broker.setcommission(commission=0.0005)
cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe')
results = cerebro.run()
print(f"Final value: {cerebro.broker.getvalue():.2f}")
print(f"Sharpe: {results[0].analyzers.sharpe.get_analysis()}")
cerebro.plot()
风格:OOP + 命令式。next() 里写「这个 bar 我要做什么」,思考方式贴近实盘。
9.3 Lean 版本(精简)
# main.py (在 QuantConnect 上跑)
from AlgorithmImports import *
class SmaCrossAlgo(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2015, 1, 1)
self.SetEndDate(2025, 1, 1)
self.SetCash(10000)
self.spy = self.AddEquity("SPY", Resolution.Daily).Symbol
self.sma_short = self.SMA(self.spy, 20, Resolution.Daily)
self.sma_long = self.SMA(self.spy, 50, Resolution.Daily)
self.SetWarmUp(50)
def OnData(self, data):
if self.IsWarmingUp:
return
if not self.Portfolio.Invested and self.sma_short.Current.Value > self.sma_long.Current.Value:
self.SetHoldings(self.spy, 1.0)
elif self.Portfolio.Invested and self.sma_short.Current.Value < self.sma_long.Current.Value:
self.Liquidate(self.spy)
风格:和 backtrader 神似(事件驱动 + OOP),但有几处工业级 hint:SetWarmUp(50) 显式声明指标预热期、SetHoldings(0..1) 用「目标权重」而不是「股数」、AlgorithmImports 暴露的 API 涵盖股票/期权/期货统一接口。
9.4 三段代码摆在一起的观察
| 维度 | vectorbt | backtrader | Lean |
|---|---|---|---|
| 代码行数 | 最少 (~15) | 中等 (~25) | 中等 (~20) |
| 思维范式 | 矩阵 | 事件循环 | 事件循环 |
| 加滑点/佣金 | fees=0.0005 | setcommission | SetBrokerageModel |
| 改成扫 1000 组参数 | 改 2 行 | 写 cerebro.optstrategy + 跑很久 | 云端 Optimization 任务 |
| 改成路径依赖 stop loss | 头大 | 改 3 行 | 改 3 行 |
| 改成接 IBKR 实盘 | 不支持 | 不稳定 | 一个滑块 |
这张表是今天的核心 takeaway。看着三个 hello world 一样简单,但「改成 X」的成本天差地别——而真实项目里 99% 的时间是花在「改成 X」上的。
十、Day 5 实际执行 Checklist
按这个顺序做:
- (0) 看了一眼这篇笔记
- (1) 装 vectorbt:
pip install vectorbt(免费版即可,~150MB 装一会儿) - (2) 装 backtrader:
pip install backtrader(很轻量) - (3) 跑通三段 hello world 中的至少两段:建议 vectorbt + backtrader,Lean 暂时跳过(要 docker)
- (4) 对比三段的运行时长:用
%timeit或time模块感受性能差异 - (5) 装 quantstats:
pip install quantstats,用它给上面的 returns 出一份 HTML 报告 - (6) 注册 QuantConnect 账号:免费账号能跑回测,先不付费,体验一下云端 IDE
- (7) 选型决策记录:把今天的 Phase 1 / 2 / 3 选型写到
docs/daily/TR_PROGRESS.md的「Architecture Decisions」段 - (8) 更新进度:
docs/daily/TR_PROGRESS.mdWeek 1 / Day 5 标 ✅ - (9) 记录踩坑:本笔记最后加「实际执行记录」段
十一、PM 视角:今天学到的迁移性思考
1. 「选框架 = 选设计哲学」,不是选「特性清单」。
招标时市面上的 framework comparison 表格往往把每个框架打 ★ 然后简单加总。这种比较方式在量化里和在企业系统里都误导。真实情况是 每个框架都强迫你按它的世界观写代码——选错框架不是「少了某个特性」,而是「你的思考方式被它扭曲」。这点对 Web3 / DeFi 协议选择架构(Cosmos SDK vs Substrate vs ETH L2)也完全适用。
2. 「研究环境 vs 生产环境」必须分层。
vectorbt 不该直连 IBKR。这不是「能不能」的问题,是「应不应该」的问题。研究环境追求探索速度(参数扫描快、可视化好),生产环境追求可靠性(断线重连、订单幂等、监控告警)。两个不同优化目标的系统硬塞到一起会同时拖累两边。这个原则在传统软件里叫「关注点分离」,在金融系统里叫「研究/交易隔离」,在 ML 里叫「training/serving 分离」——是一回事。
3. 「同构」是个理想,「分层 + 接口契约」是现实。
「回测代码 = 实盘代码」是无数框架卖的故事。现实里,broker 行为(partial fill、滑点、reject)在回测里只能近似,硬要让代码完全一致就要么牺牲回测真实性、要么牺牲实盘鲁棒性。正确的工程实践是定义清晰的「策略接口」(输入历史/状态,输出订单意图),让回测引擎和实盘引擎各自实现接口的不同方面,而策略逻辑保持纯函数。
4. 「免费」常常不是真免费。
backtrader 全免费但维护停滞——隐藏成本是「卡住时没人帮你」。Lean 引擎免费但数据贵——隐藏成本是「严肃用就要付钱」。vectorbt 社区版够用但 Pro 收费——隐藏成本是「关键功能要加钱」。评估开源工具时,要把「卡住时找答案的时间成本」「数据成本」「迁移成本」都计入 TCO。这条对企业选型 Kafka vs Pulsar、Postgres vs Mongo 都适用。
5. 90 天计划里,Day 5 这种「停下来做架构决策」的天数很关键。
诱惑是「先开搞,问题边走边解决」。但软件工程的经验告诉我们:在错误的抽象上跑得越快,技术债累积越严重。一个下午做框架对比 + 选型决策,省的可能是 Phase 2 的两周返工。这是 PM 的核心价值之一——为团队(哪怕只有自己一个人)做出「先慢后快」的决策。
十二、明日预告
Day 6: vectorbt 完整实战 — SMA + RSI 双信号策略 with 参数扫描
- 用 vectorbt 写第一个真实可用的策略(不是 hello world)
- 双指标合成信号(AND / OR / weighted)
- 参数网格扫描 + 热力图可视化
- 加入交易成本、滑点、survivorship bias 处理
- Walk-forward 分析框架
- 性能归因:Sharpe / Sortino / MaxDD / Calmar
- 把 returns 喂给 quantstats 出第一份正式 tear sheet
实际执行记录
启动一项填一项,时间戳 + 卡点。
- [hh:mm] vectorbt 安装 — ...
- [hh:mm] backtrader 安装 — ...
- [hh:mm] Hello world 1: vectorbt 运行成功 + 耗时 — ...
- [hh:mm] Hello world 2: backtrader 运行成功 + 耗时 — ...
- [hh:mm] quantstats tear sheet 生成 — ...
- [hh:mm] QuantConnect 账号注册 + 在线跑通 hello world — ...
- [hh:mm] Phase 1/2/3 选型决策写入 TR_PROGRESS.md — ...
- 卡点 / 学到的:
总字数:约 6,400 字 今日完成度:理论 ✓ / 三框架代码 ✓ / 选型决策 ✓