4. Backtrader入门:安装与核心概念

说实话,我刚开始接触量化回测那会儿,也踩过不少坑。市面上框架不少,但Backtrader是我用得最顺手的。它轻量、灵活,而且社区活跃。今天咱们就把它装起来,再把那几个核心概念捋清楚。

4.1 安装Backtrader

安装其实很简单。我个人习惯用pip,一行命令搞定:

pip install backtrader

如果你需要画图功能,建议再加个matplotlib:

pip install backtrader[plotting]

嗯,这里要注意一点。有些Windows用户会遇到安装失败的情况。我遇到过一回,是因为缺少VC++运行库。解决办法也很简单,去微软官网下载个Visual C++ Redistributable装上就行。

验证安装是否成功,你可以在Python里试试:

import backtrader as bt
print(bt.__version__)

如果能正常输出版本号,那就说明装好了。

4.2 三大核心概念

Backtrader里有三个东西你必须搞明白:CerebroStrategyDataFeed。说白了,它们就是整个回测系统的骨架。

核心关系一句话总结:

Cerebro是导演,Strategy是剧本,DataFeed是演员。导演拿着剧本,指挥演员把戏演完。

4.2.1 Cerebro —— 回测引擎

Cerebro是Backtrader的大脑。它负责加载数据、运行策略、执行交易、输出结果。你可以把它理解成一个调度中心。

我刚开始用的时候,总觉得Cerebro像个黑盒子。后来看源码才发现,它其实就是一个事件循环。每次来一根新的K线,它就触发策略里的逻辑,然后决定要不要买卖。

创建Cerebro实例很简单:

cerebro = bt.Cerebro()

然后你可以往里面加数据、加策略、设置初始资金:

cerebro.adddata(data)          # 添加数据
cerebro.addstrategy(MyStrategy) # 添加策略
cerebro.broker.setcash(100000)  # 设置初始资金10万

最后调用run方法,回测就开始了:

results = cerebro.run()

4.2.2 Strategy —— 策略逻辑

Strategy是你写策略的地方。你需要继承bt.Strategy,然后重写几个关键方法。

我个人习惯把策略拆成三块:

  • __init__:初始化指标和变量
  • next:每根K线都会调用一次,核心交易逻辑写在这里
  • notify_order:订单状态变化时触发,用来处理成交结果

举个最简单的例子:

class SimpleMovingAverageStrategy(bt.Strategy):
    params = (('period', 20),)

    def __init__(self):
        self.sma = bt.indicators.SimpleMovingAverage(
            self.data.close, period=self.params.period
        )

    def next(self):
        if not self.position:
            if self.data.close[0] > self.sma[0]:
                self.buy()
        elif self.data.close[0] < self.sma[0]:
            self.sell()

你看,逻辑其实很简单。价格上穿均线就买,下穿就卖。但实际项目中,你还要考虑滑点、手续费、仓位管理。我曾经就因为没考虑滑点,回测跑出来年化30%,实盘直接亏成狗。

避坑指南:

我曾经在策略里直接用了self.data.close[0]来判断当前价格。但回测时,这个值其实是当根K线的收盘价。如果你在盘中用这个逻辑,可能会出问题。建议用self.data.close[-1]取上一根K线的收盘价来做判断。

4.2.3 DataFeed —— 数据源

DataFeed就是喂给策略的数据。Backtrader支持多种数据格式:CSV、Pandas DataFrame、甚至直接从Yahoo Finance拉数据。

我最常用的是Pandas DataFrame,因为方便做数据预处理:

import pandas as pd
import backtrader as bt

# 假设你有一个DataFrame,包含'open','high','low','close','volume'列
df = pd.read_csv('EURUSD_1h.csv', index_col=0, parse_dates=True)

# 转换成Backtrader的数据格式
data = bt.feeds.PandasData(dataname=df)

# 添加到Cerebro
cerebro.adddata(data)

这里有个坑。Backtrader对列名有要求,默认是openhighlowclosevolume。如果你的列名不一样,比如叫OpenClose,那就得手动映射:

data = bt.feeds.PandasData(
    dataname=df,
    open='Open',
    high='High',
    low='Low',
    close='Close',
    volume='Volume'
)

4.3 第一个简单回测

好了,理论说完了,咱们动手跑一个完整的回测。就用上面那个均线策略,回测EURUSD的1小时数据。

import backtrader as bt
import pandas as pd

# 1. 定义策略
class SmaCross(bt.Strategy):
    params = (('period', 20),)

    def __init__(self):
        self.sma = bt.indicators.SMA(self.data.close, period=self.params.period)

    def next(self):
        if not self.position:
            if self.data.close[0] > self.sma[0]:
                self.buy()
        else:
            if self.data.close[0] < self.sma[0]:
                self.sell()

# 2. 加载数据
df = pd.read_csv('EURUSD_1h.csv', index_col=0, parse_dates=True)
data = bt.feeds.PandasData(dataname=df)

# 3. 初始化Cerebro
cerebro = bt.Cerebro()
cerebro.adddata(data)
cerebro.addstrategy(SmaCross)
cerebro.broker.setcash(10000.0)
cerebro.broker.setcommission(commission=0.001)  # 千分之一手续费

# 4. 运行回测
print(f'初始资金: {cerebro.broker.getvalue():.2f}')
results = cerebro.run()
print(f'最终资金: {cerebro.broker.getvalue():.2f}')

# 5. 画图
cerebro.plot()

跑完之后,你会看到一张图,上面有价格曲线、均线、还有买卖点标记。嗯,第一次看到自己的策略跑出结果,还是挺有成就感的。

小技巧:

如果你不想每次都从CSV读数据,可以把数据缓存到内存里。我一般用pickle把处理好的DataFrame存起来,下次直接加载,能省不少时间。

4.4 核心逻辑流程图

为了让你更直观地理解整个回测流程,我画了一张图:

Backtrader回测核心流程 DataFeed CSV / DataFrame / API Cerebro 回测引擎 Strategy 策略逻辑 每根K线循环 回测结果 收益率 / 夏普比率 / 回撤 流程说明: 1. DataFeed提供历史K线数据 2. Cerebro逐根K线驱动Strategy执行 3. Strategy根据指标信号决定买卖 4. 回测结束后输出绩效报告

4.5 回测结果怎么看

跑完回测,你可能会看到一堆数字。别慌,我告诉你重点看哪几个:

指标 含义 我的经验
最终资金 回测结束时的账户余额 别只看这个,要看年化收益率
最大回撤 账户从最高点跌到最低点的幅度 我个人觉得,回撤超过20%的策略基本拿不住
夏普比率 风险调整后的收益 大于1算及格,大于2算优秀
交易次数 整个回测期间的总交易笔数 太少说明策略不活跃,太多说明过度交易

记住一句话:

回测只是起点,不是终点。一个在回测里表现完美的策略,到了实盘可能一塌糊涂。我见过太多人死在过度优化上。

好了,这一章的内容就到这儿。你先把Backtrader装上,跑通上面那个例子。等你有感觉了,咱们再聊更深入的东西。


公众号:蓝海资料掘金营,微信deep3321