bt / first backtest

bt 首次回测:零市场数据跑通一次组合回测

bt 的首次次运行不需要下载任何行情:官方 README 用 np.linspace 合成两条价格序列,就能把「调度 → 选券 → 权重 → 再平衡」整条算法链跑通。先确认环境与本页流程,再把数据换成你自己的价格矩阵,才能判断结果是否可信。

数据:合成价格即可跑通输出:result.display() 统计表基于官方 README 示例原文

首跑四步

合成价格
DataFrame
组算法链
Strategy
run
Backtest
看结果
display
四步顺序固定:数据 → 算法链 → 执行 → 读结果;任何一步出错都会在结果里体现为「无交易」或曲线异常。
零数据可跑README 示例用合成价格
四类算法调度 / 选券 / 权重 / 再平衡
结果对象继承 ffn 的组合统计
证据README + 包源码(2026-09-20 核验)
Minimal example

最小可跑的首次回测怎么写?

下面这段来自官方 README(原文照录),用两条合成的价格序列做等权月度再平衡,不需要任何行情源。

import numpy as np
import pandas as pd
import bt

prices = pd.DataFrame(
    {
        "asset_a": np.linspace(100, 120, 252),
        "asset_b": np.linspace(100, 110, 252),
    },
    index=pd.bdate_range("2020-01-01", periods=252),
)

strategy = bt.Strategy(
    "equal_weight",
    [
        bt.algos.RunMonthly(),
        bt.algos.SelectAll(),
        bt.algos.WeighEqually(),
        bt.algos.Rebalance(),
    ],
)
result = bt.run(bt.Backtest(strategy, prices))
result.display()
Step by step

首次回测怎么分五步跑通?

每步都给代码、一句话说明与可核对的预期输出;报错原文以本地终端提示为准。

  1. 准备价格矩阵

    prices = pd.DataFrame({...}, index=pd.bdate_range("2020-01-01", periods=252)):行是日期索引(DatetimeIndex),每列一个标的的收盘价。预期prices.shape 返回 (252, 2)

  2. 写算法链

    bt.Strategy("equal_weight", [RunMonthly(), SelectAll(), WeighEqually(), Rebalance()]):一个列表就是一条算法链,顺序即执行顺序。预期strategy 对象创建成功,无异常。

  3. 绑定数据并执行

    result = bt.run(bt.Backtest(strategy, prices))Backtest 把策略与价格绑定,bt.run 执行并返回结果对象。预期:返回 bt.backtest.Result(继承 ffn 的组合统计类)。

  4. 打印统计

    result.display():输出组合统计表与净值曲线。预期:看到总收益、年化、回撤等统计行。

  5. 取权重与交易明细

    result.get_weights()result.get_transactions();单个回测的换手与集中度用 Backtest.turnover()Backtest.herfindahl_index()预期:拿到权重矩阵与交易记录,用来核对「调仓是否按月发生」。

源码依据:上面第 3–5 步的类与方法名取自 PyPI 包 bt 1.2.3bt/backtest.py(2026-09-20 核验):Result 继承 ffn.GroupStats,公开 get_weights()get_transactions()get_security_weights()plot_weights() 等方法;Backtest 提供 run()weights()positions()turnover()herfindahl_index()。字段口径以官方文档与 ffn 文档为准。
Four algos

示例里的四个算法各自负责什么?

理解这四个类,就能把示例改造成自己的策略:换掉其中一个,策略行为就随之改变。

算法管什么换掉它会变成什么注意点
RunMonthly()决定什么时候动手(每月执行一次)RunDaily 变每日调仓、换 RunQuarterly 变季度放在算法链最前;没有调度类算法时不会按预期频率触发
SelectAll()决定动哪些标的(选中全部可用证券)SelectN 取前 N 名、换 SelectMomentum 按动量选它会写入 temp['selected'],默认排除当日无数据、价格 ≤0 的证券
WeighEqually()决定各分多少(等权)WeighInvVol 逆波动、WeighERC 风险平价依赖上一步的 selected:没有选券结果时权重无从分配
Rebalance()把目标权重变成交易(差额调仓)RebalanceOverTime 分步成交、LimitDeltas 限制换手通常放在算法链最后;不写它就不会产生任何交易
四者的顺序调度 → 选券 → 权重 → 再平衡顺序颠倒会得到完全不同的调仓行为调试时插入 Debug / PrintInfo 观察中间状态
结果去哪了算法链只改「目标权重」,成交由再平衡算法负责统计与图表由 ffn 提供,口径以 ffn 文档为准
Read results

跑完的结果怎么读?

bt 的结果对象把「组合层统计」与「单次回测明细」分成两层,下表说明各自用什么入口读。

想看什么用什么读适用场景注意点
整体统计(收益、年化、回撤)result.display();统计来自 ffn.GroupStats快速判断一次回测是否合理统计口径由 ffn 决定,与自己手算不一致时先对齐口径
组合权重矩阵result.get_weights()核对权重是否按预期分配权重是目标值还是成交后值,以文档与实现为准
交易记录result.get_transactions()核对调仓频率与成交量无交易时先查算法链是否缺 Rebalance
单个回测的换手Backtest.turnover()评估成本敏感度高换手必须叠加成本模型再判断
持仓集中度Backtest.herfindahl_index()判断是否退化成少数标的等权与集中化策略的读数含义不同
净值与回撤曲线plot_weights() / plot_histogram() 等绘图方法出图写报告出图依赖 ffn / matplotlib 环境
Real data

换成自己的数据要做什么?

README 明确写了「回测结果依赖数据质量与建模假设」。换成真实数据前,先把下面四项准备好。

要素要求常见错法
索引必须是日期索引(DatetimeIndex),按时间升序用字符串或整数当索引导致排序错乱
每列一个标的的收盘价,列名即标的标识列里混入成交量或成交额
缺失值显式处理(对齐、前向填充或剔除),不要留下 NaNNaN 参与计算导致净值跳变或统计失真
复权口径自己决定并记录(前复权 / 后复权 / 不复权)不同标的口径不一致,收益不可比
数据来源bt 不提供行情;自备数据或用本机财经数据类技能取数把来源不明的数据当权威数据使用
区间与频率先固定一个区间与频率做基线,再改变量同时改区间、标的与算法,结论无法归因
Troubleshooting

首跑最容易卡在哪六处?

下面六种现象覆盖首次运行最常见的失败方式,处理方式以官方文档与本地提示为准。

现象常见原因处理方式
跑完没有任何交易算法链没有再平衡算法在链尾补 Rebalance()
报索引类型相关错误价格表的索引不是日期序列pd.to_datetimepd.bdate_range 重建索引并排序
结果数字明显失真价格表里有 NaN 或重复日期prices.isna().sum()prices.index.duplicated().sum() 自检
权重与预期不符算法顺序写反(权重算法在选券之前)按调度 → 选券 → 权重 → 再平衡顺序检查
想把合成价格的收益当结论合成价格是人为直线,不具市场特征只用于验证流程;结论必须基于真实数据并注明区间与口径
报缺少模块环境缺 pandas / numpy(bt 未直接声明这两个依赖)显式安装并记录版本,见安装页依赖边界
FAQ

bt 首次回测常见问题

首次回测一定要有行情数据吗?

不需要。官方 README 的入门示例用 np.linspace 合成价格,目的就是让你在没有数据源的情况下先跑通流程;但合成价格只能验证代码与流程,不能用于任何结论。

为什么我的回测一笔交易都没有?

最常见的原因是算法链里缺再平衡算法(如 Rebalance()):算法链只负责算目标权重,把权重变成交易是再平衡算法的职责。其次检查调度算法是否真的触发了调仓。

能回测 A 股 / 港股 / 美股吗?

bt 不提供行情,只要求你把数据整理成「日期 × 标的」的收盘价矩阵,因此市场不受库的限制;标的选择、复权口径与交易日差异都要你自己处理。

怎么把交易成本算进去?

通过 Backtest 的成本模型参数配置(CostModel / SqrtCostModel / AlmgrenChrissCostModel),详见「成本与固收」页;具体参数名与默认值以官方文档为准。

结果里的统计是谁算的?

绩效统计与图表由 ffn(Financial Functions for Python)提供,bt 的结果对象继承 ffn 的组合统计类。因此统计字段名与口径应以 ffn 文档为准,不要假设 bt 自己实现了一套。

回测结果能当收益预期吗?

不能。官方 README 写明回测结果依赖数据质量与建模假设、不预测未来表现;本站示例仅用于说明用法,不构成投资建议。

跑通之后怎么把策略与数据换成自己的?

bt 的示例跑通说明环境与链路都没问题;接下来理解策略类的生命周期与参数优化,再把行情数据换成本地可用来源,才能得到针对自己标的的结论。