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里有三个东西你必须搞明白:Cerebro、Strategy、DataFeed。说白了,它们就是整个回测系统的骨架。
核心关系一句话总结:
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对列名有要求,默认是open、high、low、close、volume。如果你的列名不一样,比如叫Open、Close,那就得手动映射:
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 核心逻辑流程图
为了让你更直观地理解整个回测流程,我画了一张图:
4.5 回测结果怎么看
跑完回测,你可能会看到一堆数字。别慌,我告诉你重点看哪几个:
| 指标 | 含义 | 我的经验 |
|---|---|---|
| 最终资金 | 回测结束时的账户余额 | 别只看这个,要看年化收益率 |
| 最大回撤 | 账户从最高点跌到最低点的幅度 | 我个人觉得,回撤超过20%的策略基本拿不住 |
| 夏普比率 | 风险调整后的收益 | 大于1算及格,大于2算优秀 |
| 交易次数 | 整个回测期间的总交易笔数 | 太少说明策略不活跃,太多说明过度交易 |
记住一句话:
回测只是起点,不是终点。一个在回测里表现完美的策略,到了实盘可能一塌糊涂。我见过太多人死在过度优化上。
好了,这一章的内容就到这儿。你先把Backtrader装上,跑通上面那个例子。等你有感觉了,咱们再聊更深入的东西。
公众号:蓝海资料掘金营,微信deep3321