backtrader整体框架
backtrader 是一个量化回测的库,支持多品种、多策略、多周期的回测和交易。更重要的是可以集成 torch 等神经网络分析模块。
Cerebro
类是 backtrader 的核心。Strategy
类、Broker
和Sizer
类都是由Cerebro
类实例化而来。
整体流程
- backtrade 自带的数据源是
yahoofinance()
,也可使用自己本地的 csv 文件。 DataFeed
模块会将原始数据导入到Cerebro
,之后就可以进行矢量化操作。Strategy
模块会根据策略将订单提交到Broker
。Broker
是一个抽象的交易所,里面定义了订单执行、仓位管理和交易费率等。Strategy
模块中包括了三个模块Observer
、Analyzer
和Indicator
。Observer
负责观测市场数据。Analyzer
负责分析算法产生的数据,可以看做是一个评估模块。Indicator
是指标和信号模块,策略主要通过指标和信号来判断是否触发交易。Sizer
主要负责仓位的管理。因为Strategy
只负责触发交易,但不知道怎么分配仓位。Sizer
就可以独立控制仓位管理。
数据流程

实操流程
安装环境
python
pip install backtrader matplotlib
回测示例
注意,需要准备CSV格式的个股数据。
python
import backtrader as bt
import pandas as pd
import matplotlib.pyplot as plt
import datetime as dt
import numpy as np
class SMAStrategy(bt.Strategy):
'''
自定义的策略, 需继承 bt.Strategy
'''
def __init__(self):
self.dataclose = self.data0.close
self.order = None
self.buyprice = None
self.buycomm = None
self.sma = bt.indicators.SimpleMovingAverage(self.data0, period=15)
def next(self):
'''
一般在这里写实际的策略。
这里就是收盘价上穿sma买入,反之则卖出。
'''
if not self.position: # 判断是否有持仓
if self.dataclose[0] > self.sma[0]: # 判断收盘价是否上穿sma
self.buy()
else:
if self.dataclose[0] < self.sma[0]:
self.close() # 平仓
def notify_order(self, order):
'''
获取订单状态,这个函数一般可以通用。
'''
if order.status in [order.Submitted, order.Accepted]:
return
if order.status in [order.Completed]:
if order.isbuy():
self.log(
'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm)
)
self.buyprice = order.executed.price
self.buycomm = order.executed.comm
else:
self.log(
'SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm)
)
self.bar_executed = len(self)
elif order.status in [order.Canceled, order.Margin, order.Rejected]:
self.log('Drder Canceled / Margin / Rejected')
self.order = None
def notify_trade(self, trade):
'''
追踪每笔交易的状态,这个函数一般可以通用。
'''
if not trade.isclosed:
return
self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
(trade.pnl, trade.pnlcomm))
def log(self, txt, dt=None, doprint=False):
'''
保存日志
'''
if doprint:
dt = dt or self.datas[0].datetiem.date(0)
print('%s, %s' % (dt.isoformat(), txt))
if __name__ == "__main__":
# 实例化cerebro
cerebro = bt.Cerebro()
# 处理数据
dataframe = pd.read_csv('TSLA.csv')
dataframe['Datetime'] = pd.to_datetime(dataframe['Date'])
dataframe.set_index('Datetime', inplace=True)
# 加载数据源
data_TSLA = bt.feeds.PandasData(dataname = dataframe,
fromdate = dt.datetime(2025,1,2),
todate = dt.datetime(2025,1,31))
cerebro.adddata(data_TSLA)
# 加载策略
cerebro.addstrategy(SMAStrategy)
# 加载Analyzer
cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name="SharpeRatio")
cerebro.addanalyzer(bt.analyzers.DrawDown, _name = "DrawDown")
# 在Broker中设置初始资金和手续费
cerebro.broker.setcash(10000.0)
cerebro.broker.setcommission(commission = 0.0006)
# 设置Sizer
cerebro.addsizer(bt.sizers.PercentSizer, percents = 90)
result = cerebro.run()
print("夏普比率", result[0].analyzers.SharpeRatio.get_analysis()['sharperatio'])
print("最大回撤", result[0].analyzers.DrawDown.get_analysis["max"]['drawdown'])
cerebro.plot()
参考:【【Backtrader教程01】Python Backtrader量化回测框架 | 代码实战教学 | 单均线回测收益率570%?】 https://www.bilibili.com/video/BV1QR4y147rS/?share_source=copy_web\&vd_source=9eb6d7fad45f9fa869cd9abb34fa68ca