Backtrader
Backtrader 上手建议按 “装环境 → 准备数据 → 写策略 → 配置资金佣金滑点 → 跑回测 → 看分析器 → 参数优化 → 模拟盘” 推进,重点是把坑提前避开。
1. 安装环境
python -m venv bt_env
# Windows
bt_env\Scripts\activate
# macOS/Linux
source bt_env/bin/activate
pip install backtrader pandas numpy -i https://pypi.tuna.tsinghua.edu.cn/simple需要绘图再装:
pip install backtrader[plotting]绘图依赖会自动带 matplotlib、pyqtgraph 等。Python 版本建议 3.8 到 3.11,3.12 以上容易出现 Matplotlib 绘图异常或 dateutil 解析失败。
2. 准备数据
最省事的是用 akshare 拉 A 股日线再转成 PandasData:
import akshare as ak
import pandas as pd
import backtrader as bt
df = ak.stock_zh_a_hist(symbol="000001", period="daily",
start_date="20200101", end_date="20241231",
adjust="qfq")
df["date"] = pd.to_datetime(df["日期"])
df = df.rename(columns={"开盘":"open","最高":"high","最低":"low",
"收盘":"close","成交量":"volume"})
df = df[["date","open","high","low","close","volume"]].set_index("date")
data = bt.feeds.PandasData(dataname=df)关键点是必须有 datetime 索引和小写 open/high/low/close/volume 字段,再通过 bt.feeds.PandasData 加载。如果不想改列名,也可以自定义 DataFeed 做中文列映射。
A 股强烈建议用前复权或后复权数据,否则除权除息会让回测严重失真。
3. 写第一个策略
class SmaCross(bt.Strategy):
params = dict(fast=10, slow=30)
def __init__(self):
fast = bt.ind.SMA(period=self.p.fast)
slow = bt.ind.SMA(period=self.p.slow)
self.crossover = bt.ind.CrossOver(fast, slow)
self.order = None
def next(self):
if self.order:
return
if not self.position and self.crossover > 0:
self.order = self.buy()
elif self.position and self.crossover < 0:
self.order = self.close()
def notify_order(self, order):
if order.status in [order.Completed, order.Canceled, order.Margin, order.Rejected]:
self.order = Nonenext() 每个 K 线会被调用一次,交易逻辑写在这里。用 self.order 挡重复下单很常见,但如果限价单或止损单一直没成交,self.order 会一直有值,导致后续逻辑全被挡住,最好主动撤单。
4. 配置资金、佣金、滑点和分析器
cerebro = bt.Cerebro()
cerebro.adddata(data)
cerebro.addstrategy(SmaCross)
cerebro.broker.setcash(100000)
cerebro.broker.setcommission(commission=0.001)
cerebro.broker.set_slippage_perc(0.001)
cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name="sharpe")
cerebro.addanalyzer(bt.analyzers.DrawDown, _name="drawdown")
cerebro.addanalyzer(bt.analyzers.Returns, _name="returns")
results = cerebro.run()
strat = results[0]
print("期末资金:", cerebro.broker.getvalue())
print("夏普:", strat.analyzers.sharpe.get_analysis().get("sharperatio"))
print("最大回撤:", strat.analyzers.drawdown.get_analysis()["max"]["drawdown"])设置初始资金用 setcash,佣金用 setcommission,滑点用 set_slippage_perc。DrawDown 能给出最大回撤、回撤时长和恢复时间,Returns 能给出总收益和年化收益。
5. 绘图
cerebro.plot(style="candlestick")如果报错,大概率是 Matplotlib 版本太新。Backtrader 早期基于 Matplotlib 1.x 开发,Matplotlib 3.x 引入不兼容改动,常见解法是降级到 2.2.5 左右。也有说法是 Matplotlib 3.4+ 不兼容,可降到 3.3.4。还有人遇到新版 matplotlib.dates 不再包含 warnings 导致导入失败,只能改 backtrader 源码解决。
更稳的做法是别依赖 cerebro.plot(),直接把资金曲线导出用 matplotlib 或 plotly 自己画。
6. 参数优化
cerebro = bt.Cerebro()
cerebro.adddata(data)
param_grid = {
"fast": range(5, 21, 5),
"slow": range(20, 61, 10),
}
cerebro.optstrategy(SmaCross, **param_grid)
results = cerebro.run(maxcpus=4, optreturn=False)用 optstrategy 替代 addstrategy,传入参数范围即可自动遍历组合,maxcpus 可以开多核并行。开启多进程时要确保数据源和策略逻辑可序列化,数据库连接最好放在 start 或 init 里,不要用全局变量。
优化最大的坑是过拟合。历史最优参数未来不一定有效,专业做法是样本内样本外检验,或者看最优参数是否集中在稳定区域,而不是孤立奇点。只盯着收益率最高的参数,很容易忽略巨大回撤和极低胜率。
7. 理解成交机制,避免回测虚高
Backtrader 默认在下一个交易日开盘成交,今天收盘发现信号、明天开盘买入,这更符合 A 股 T+1 的实盘逻辑。虽然可以用 set_coc(True) 强制当日收盘成交,但通常会极大虚增收益,导致实盘无法复现。
想模拟当日成交,更合理的是换用分钟级数据,而不是直接开 cheat-on-close。
8. 接 A 股模拟盘或实盘
Backtrader 没有官方对接同花顺、东方财富的公开稳定 API,实时模式需要自己实现 Broker 和 DataFeed 作为桥梁,常见方案是用 easytrader 自动操作 PC 客户端,流程是 Backtrader 到自定义 Broker,再到 easytrader,再到客户端。
接 A 股必须适配这些规则:T+1 不能当日买当日卖、下单数量必须是 100 股整数倍、下单前检查涨跌停、只在 9:30-11:30 和 13:00-15:00 执行下单。风控上建议单次下单不超过账户资金一定比例,加订单失败重试、持仓实时校验和强制止损。
另外版本兼容也要留意,有反馈 Backtrader 1.9.76 与 easytrader 0.8.3 存在线程调度兼容问题。
9. 新手推荐练习路线
- 用 CSV 跑通 GenericCSVData 和空策略
- 换成 akshare 拉数据,跑 PandasData
- 写双均线策略,输出期末资金
- 加佣金和滑点,对比结果差距
- 加 SharpeRatio、DrawDown、Returns 分析器
- 用 optstrategy 做一轮网格搜索
- 留出样本外数据验证参数
- 再考虑接模拟盘,不要直接实盘
10. 常见报错速查
| 现象 | 原因 | 处理 |
|---|---|---|
| 绘图报错 | Matplotlib 版本过高 | 降级 Matplotlib 或自己画资金曲线 |
| 没有交易 | 指标未成型或信号没触发 | 检查数据长度和 enter 条件 |
| 一直不下单 | self.order 没被清空 | 在 notify_order 里重置或撤单 |
| 收益异常高 | 用了未来数据或开了 coc | 改成下一根 K 线成交 |
| A 股回测失真 | 没复权、没处理停牌退市 | 用复权数据并补停牌逻辑 |
| TA-Lib 装不上 | 缺底层 C 库 | 下载对应版本 whl 安装 |
如果主要目标是 A 股实盘,Backtrader 更适合做研究验证,实盘链路通常还要额外搭 Broker 和风控。如果只是想快速跑通跨市场回测和复杂策略逻辑,它的灵活性仍然很实用。