Banner

Backtrader

10小时前

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 = None

next() 每个 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. 新手推荐练习路线

  1. 用 CSV 跑通 GenericCSVData 和空策略
  2. 换成 akshare 拉数据,跑 PandasData
  3. 写双均线策略,输出期末资金
  4. 加佣金和滑点,对比结果差距
  5. 加 SharpeRatio、DrawDown、Returns 分析器
  6. 用 optstrategy 做一轮网格搜索
  7. 留出样本外数据验证参数
  8. 再考虑接模拟盘,不要直接实盘

10. 常见报错速查

现象原因处理
绘图报错Matplotlib 版本过高降级 Matplotlib 或自己画资金曲线
没有交易指标未成型或信号没触发检查数据长度和 enter 条件
一直不下单self.order 没被清空在 notify_order 里重置或撤单
收益异常高用了未来数据或开了 coc改成下一根 K 线成交
A 股回测失真没复权、没处理停牌退市用复权数据并补停牌逻辑
TA-Lib 装不上缺底层 C 库下载对应版本 whl 安装

如果主要目标是 A 股实盘,Backtrader 更适合做研究验证,实盘链路通常还要额外搭 Broker 和风控。如果只是想快速跑通跨市场回测和复杂策略逻辑,它的灵活性仍然很实用。


4