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
就可以獨立控制倉位管理。
數據流程
實操流程
安裝環境
pip install backtrader matplotlib
回測示例
注意,需要準備CSV格式的個股數據。
import backtrader as bt
import pandas as pd
import matplotlib.pyplot as plt
import datetime as dt
import numpy as npclass SMAStrategy(bt.Strategy):'''自定義的策略, 需繼承 bt.Strategy'''def __init__(self):self.dataclose = self.data0.closeself.order = Noneself.buyprice = Noneself.buycomm = Noneself.sma = bt.indicators.SimpleMovingAverage(self.data0, period=15)def next(self):'''一般在這里寫實際的策略。這里就是收盤價上穿sma買入,反之則賣出。'''if not self.position: # 判斷是否有持倉if self.dataclose[0] > self.sma[0]: # 判斷收盤價是否上穿smaself.buy()else:if self.dataclose[0] < self.sma[0]:self.close() # 平倉def notify_order(self, order):'''獲取訂單狀態,這個函數一般可以通用。'''if order.status in [order.Submitted, order.Accepted]:returnif 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.priceself.buycomm = order.executed.commelse: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 = Nonedef notify_trade(self, trade):'''追蹤每筆交易的狀態,這個函數一般可以通用。'''if not trade.isclosed:returnself.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__":# 實例化cerebrocerebro = 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)# 加載Analyzercerebro.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)# 設置Sizercerebro.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