pmorissette/bt · MIT · v1.2.3
bt 回测库:用算法树搭多资产组合回测
bt(pmorissette/bt)是一个 2014 年起持续维护的 Python 回测库。它把一次回测拆成四类可复用算法——什么时候调仓、选哪些券、怎么分权重、怎么成交——按顺序串成一棵策略树,再喂进「日期 × 资产」的价格矩阵,输出组合收益、权重、交易与回撤统计;绩效统计与图表由 ffn 提供。它更像「组合研究框架」而不是单标的快速试算工具。
项目来源
项目页面显示约 3.0k Star / 501 fork;该数字会随社区活动变化,采集日期为 2026-09-20。
查看源码与 release
bt 能解决什么问题?
官方 README 把它的价值写成四条:组合策略逻辑、把策略建成组合树、给交易成本建模、对比结果。翻译成研究场景就是下面四件事。
把策略拆成可复用算法
调度、选券、权重、再平衡各自是独立对象,同一套选券算法可以配上不同的权重与再平衡算法,改一个环节就能做对照实验,不必重写整个策略代码。
把多个策略装进一棵树
策略与证券可以嵌在同一棵树里,因此「先分子策略、再合并成组合」可以写成一个整体回测,而不是自己写循环拼接结果。
给交易成本建模
库内提供成本模型抽象(CostModel、SqrtCostModel、AlmgrenChrissCostModel)与佣金配置,用来观察换手与成本对绩效的影响,而不是默认「无摩擦成交」。
一次拿到多组结果
回测结果对象里同时有收益、权重、交易记录与回撤等统计(统计与图表由 ffn 提供),便于横向对比不同参数与不同组合结构。
一次回测怎么跑通?五步流程
前两步用官方 README 的合成价格示例,不需要下载任何行情数据就能验证环境是否装好;后三步才是真实研究要做的替换工作。命令与类名以官方 README 与 PyPI 包(1.2.3)为准。
什么时候动手
动哪些标的
各分多少
怎么成交
- 装环境并确认版本
命令:
pip install bt,随后python -c "import bt; print(bt.__version__)"。预期输出:1.2.3。若报缺少 pandas,见安装页的依赖边界说明。 - 用合成价格跑通最小回测
代码:README 示例——
bt.Strategy("equal_weight", [RunMonthly(), SelectAll(), WeighEqually(), Rebalance()])配bt.run(bt.Backtest(strategy, prices))。预期输出:result.display()打印统计表与净值曲线。合成价格用np.linspace生成,无需联网取数。 - 换成自己的价格矩阵
把
prices换成pd.DataFrame,行索引是DatetimeIndex,每列一个标的的收盘价。预期:列名即标的代码,缺失日期会按索引对齐,空值会参与计算,先查数据再跑。 - 按研究问题组合算法
把选券换成
SelectMomentum、权重换成WeighInvVol或WeighERC、再平衡换成RebalanceOverTime,即可得到不同的组合行为。预期:result.stats指标随算法组合改变。 - 读结果并做对照
看
result.stats、result.prices、result.weights、result.transactions,或用benchmark_random做随机基准对照。预期:能回答「超额来自选券还是来自权重」这类问题。
bt 的四个核心概念是什么?
下面四个名字在官方 README 与包结构里都能核到(bt/__init__.py 公开导出),理解它们就理解了 bt 的写法。
| 概念 | 它负责什么 | 适用场景 | 注意点 |
|---|---|---|---|
Algo | 最小动作单元,被调用时返回 True/False,用返回值决定后续算法是否继续执行 | 想复用某段判断逻辑(如「只在月末动手」) | 单个算法不产生交易,只改状态或目标权重 |
AlgoStack | 把多个算法按顺序串成一个整体,前一个返回 False 就短路 | 需要「条件不满足就跳过本次调仓」 | 顺序写反会得到完全不同的行为,先调度后选券 |
Strategy | 一棵策略树:持有算法栈与证券/子策略,运行时按数据时间轴推进 | 定义单个策略或嵌套子策略 | 只写选券不写 Rebalance 不会产生交易 |
Backtest | 把策略与价格数据绑定,作为一次回测任务 | 一个策略 × 一段数据 × 一组成本假设 | 数据是「日期 × 标的」的收盘价矩阵 |
bt.run | 执行一个或多个 Backtest 并汇总成结果对象 | 多策略并行对比 | 传多个 Backtest 得到组合结果,统计口径会合并 |
Result | 结果对象:stats / prices / weights / transactions 等 | 读指标、查交易明细、画图 | 统计与图表由 ffn 提供,字段口径以 ffn 文档为准 |
内置算法库有哪些类?
bt 1.2.3 的 bt.algos 里共 59 个算法类,按用途可以分成八组。下表每组给出代表类名与搭配方式,逐类清单见「算法库」页。
| 分组 | 代表类名 | 典型搭配 | 注意点 |
|---|---|---|---|
| 调度(什么时候动手) | RunOnce / RunDaily / RunWeekly / RunMonthly / RunQuarterly / RunYearly / RunPeriod | 放在算法链最前 | 没有调度算法时回测不会按预期频率调仓 |
| 日历与条件触发 | RunOnDate / RunAfterDate / RunAfterDays / RunEveryNPeriods / RunIfOutOfBounds | 配合调度类使用 | 边界条件写错会整段不调仓,建议用小样本先验证 |
| 选券(动哪些标的) | SelectAll / SelectN / SelectMomentum / SelectWhere / SelectRegex / SelectHasData | 接在调度之后 | 选完标的集合变了,仍需权重算法分配资金 |
| 权重(各分多少) | WeighEqually / WeighSpecified / WeighTarget / WeighInvVol / WeighERC / WeighMeanVar | 接在选券之后 | 权重之和与杠杆上限以库的实现为准,先看是否需要用 ScaleWeights |
| 限额与风控 | LimitWeights / LimitDeltas / TargetVol | 放在权重之后、再平衡之前 | 限额会改变目标权重,别和回测假设混着讲 |
| 再平衡与成交 | Rebalance / RebalanceOverTime / PTE_Rebalance / CapitalFlow / SetNotional | 算法链收尾 | 不写再平衡算法就不会成交 |
| 逻辑与统计 | Require / Not / Or / SetStat / StatTotalReturn / StatMultiPeriodReturn | 做条件分支或记录自定义统计量 | 统计量只在结果对象里可读,不是绩效指标本身 |
| 交易与公司行为 | CorporateActions / CloseDead / ClosePositionsAfterDates / RollPositionsAfterDates / ReplayTransactions | 需要模拟现金流与到期处理时 | 这类算法偏进阶,先确认数据里是否有对应字段 |
| 风险与保证金 | UpdateRisk / PrintRisk / HedgeRisks / Margin / SimulateRFQTransactions | 做对冲或保证金场景 | v1.2.3 修复了保证金维持追缴与证券乘数相关问题,注意版本 |
bt 1.2.3 的 bt/algos.py(2026-09-20 核验,共 59 个类);每个类的参数与默认值以官方文档 algos 章节为准。自建 bt 回测,还是先用本机技能路线?
同一个研究问题,两条路线的准备成本差别很大:一条是把环境、数据与代码都握在自己手里,另一条是先拿到结论再决定是否值得自建。
自建 bt 回测管道
- Python 3.9+ 环境与
pip install bt(含编译核心,轮子与 Python 版本绑定) - 自己准备「日期 × 标的」价格矩阵,自己处理缺失与复权
- 自己把研究问题翻译成算法链,并解释统计口径
- 好处:可复现、可回归测试、可写进版本管理
本机技能路线(免部署)
- 用自然语言描述研究问题,直接拿结构化结论
- 数据获取与出图可由本机技能完成,不必先装 Python 环境
- 适合先判断「这个问题值不值得做成回测」
- 边界:本机 29 个技能里没有等价于 bt 算法树 + 组合回测引擎的能力
| 你的当前状态 | 建议先做 | 理由 |
|---|---|---|
| 只有「某只标的最近怎么样」这类问题 | 技能路线 | 取数与指标摘要即可回答,不值得搭环境 |
| 要比较多套权重/再平衡方案 | 自建 bt | 算法链正好是为「换一个环节做对照」设计的 |
| 要做多资产组合而不是单标的 | 自建 bt | 价格矩阵天然是多列结构 |
| 只想验证一个想法是否值得深挖 | 先技能路线,再自建 | 先用一句话确认现象,再决定要不要写代码 |
| 结论要进报告或对外发布 | 自建 bt | 需要可复现的代码与数据版本 |
| 没有 Python 环境也不想装 | 技能路线 | 本机技能免部署;但组合回测仍需自建环境 |
本机技能路线用起来怎么样?
下面两张截图来自本机对话的真实使用(左右翻页查看),用于对照自建路线「装环境 + 备数据 + 写算法链」的准备成本;它们演示的是技能路线,不是 bt 的运行结果。
| bt 工作流里的环节 | 本机技能路线能否覆盖 | 前置条件 |
|---|---|---|
| 取历史行情(价格矩阵的原料) | 可以:财经数据类技能可取行情 | 安装客户端;部分数据源需 Token 或账号 |
| 看单标的指标状态 | 可以:技术分析类技能给指标状态 | 覆盖范围以技能说明为准,部分仅覆盖 A 股 |
| 组合统计与图表 | 部分:可出收益、回撤等摘要与图 | 口径与你自建回测未必一致,比较前先对齐 |
| 算法链与再平衡执行 | 不能替代:本机无等价引擎 | 需要 Rebalance/WeighX 这类逐日推进的引擎 |
| 可复现与回归测试 | 不能替代:结论需固化成代码 | 版本管理、数据版本、成本假设都要自建 |
| 交易成本建模 | 不能替代:成本模型属于回测引擎能力 | 自建时用 CostModel 系列配置 |
什么时候适合用 bt、什么时候不适合?
bt 的定位是「组合与算法复用」,不是「任何回测需求都套」。下面六条对应最常见的匹配与错配。
| 场景 | 适不适合 | 原因 |
|---|---|---|
| 多资产组合、按权重定期再平衡 | 适合 | 价格矩阵与权重/再平衡算法正是为这类问题准备的 |
| 想比较多套权重或再平衡规则 | 适合 | 换一个算法对象即可做对照实验 |
| 要模拟交易成本与换手影响 | 适合 | 库内提供成本模型抽象与佣金配置 |
| 单标的日内高频、逐笔撮合 | 不适合 | bt 按数据行推进,不是逐笔撮合引擎 |
| 要接实盘下单 | 不适合 | bt 是回测库,不提供实盘通道 |
| 只想快速看一只股票的技术指标 | 不必用 | 指标计算与看图有更轻的做法,自建成本更高 |
跑不通时先查什么?
下面六种现象覆盖了初次使用 bt 最容易卡住的地方,按「处理方式」逐条试;报错原文、依赖约束与版本差异以官方 README、文档与本地终端提示为准。
| 现象 | 常见原因 | 处理方式 |
|---|---|---|
No matching distribution found for bt | Python 版本或平台没有对应轮子 | 确认 Python ≥3.9(官方 classifier 覆盖 3.9–3.13),或改用源码安装并准备编译工具链 |
ModuleNotFoundError: No module named 'pandas' | bt 的运行时依赖里没有直接写 pandas | 显式安装 pandas / numpy(它们经 ffn 进入依赖链,环境不完整时会缺) |
| 回测跑完没有任何交易 | 算法链里没写再平衡算法 | 在链尾补 Rebalance()(或用 RebalanceOverTime 分步成交) |
| 结果与预期差很远 | 算法顺序写反,或权重算法没接在选券之后 | 按「调度 → 选券 → 权重 → 再平衡」顺序检查,必要时先插 Debug / PrintInfo 看中间状态 |
| 净值曲线有异常跳变 | 价格矩阵有空值、重复索引或货币不一致 | 先检查 DataFrame 索引是否 DatetimeIndex、是否有 NaN 与重复日期 |
| 统计口径与自己的算法对不上 | 绩效统计由 ffn 计算,口径与自算不同 | 以 ffn 文档为准,或自行用 prices 序列复算并注明口径 |
bt 常见问题
bt 是免费的吗?可以商用吗?
bt 采用 MIT 许可(PyPI 包元数据与仓库 LICENSE 均标注 MIT),可自由使用与修改;具体使用仍以仓库 LICENSE 原文为准。使用时请自行确认第三方数据源的授权范围。
bt 支持哪些 Python 版本?
包元数据 Requires-Python >=3.9,分类器覆盖 3.9 / 3.10 / 3.11 / 3.12 / 3.13。实测下载到的是与解释器和平台绑定的编译轮子(如 cp311-win_amd64),装到没有轮子的环境会走源码构建分支,需自备编译工具链。
能回测 A 股 / 港股 / 美股吗?
bt 本身不提供行情,只要你能把数据整理成「日期 × 标的」的收盘价矩阵,市场不受限制。数据来源与复权口径需自己解决;本机技能路线里的财经数据类技能可以取到部分市场行情,但覆盖面以各技能说明为准。
bt 能实盘交易吗?
不能。bt 是回测库,不包含实盘通道与风控执行;它输出的是回测结果统计。若目标是实盘,需要另外接入交易接口,并自行承担全部风险。
bt 和 backtesting.py 有什么区别?
两者的抽象方向不同:backtesting.py 面向单标的策略,用 Strategy.init/next 两个方法描述逐根 K 线的行为;bt 面向多资产组合,把「调度 / 选券 / 权重 / 再平衡」拆成可复用算法串成策略树。选哪个取决于你要做单标的研究还是组合研究,具体能力以各自官方文档为准。
回测结果能当作收益预期吗?
不能。官方 README 明确写了「回测结果依赖数据质量与建模假设,不预测未来表现」。本站所有示例都只用于说明用法,不构成投资建议。