添加分析指标
# 添加分析指标
# 返回年初至年末的年度收益率
cerebro.addanalyzer(bt.analyzers.AnnualReturn, _name='_AnnualReturn')
# 计算最大回撤相关指标
cerebro.addanalyzer(bt.analyzers.DrawDown, _name='_DrawDown')
# 计算年化收益:日度收益
cerebro.addanalyzer(bt.analyzers.Returns, _name='_Returns', tann=252)
# 计算年化夏普比率:日度收益
cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='_SharpeRatio', timeframe=bt.TimeFrame.Days, annualize=True, riskfreerate=0) # 计算夏普比率
cerebro.addanalyzer(bt.analyzers.SharpeRatio_A, _name='_SharpeRatio_A')
# 返回收益率时序
cerebro.addanalyzer(bt.analyzers.TimeReturn, _name='_TimeReturn')
# 启动回测
result = cerebro.run()# 提取结果
print("--------------- AnnualReturn -----------------")
print(result[0].analyzers._AnnualReturn.get_analysis())
print("--------------- DrawDown -----------------")
print(result[0].analyzers._DrawDown.get_analysis())
print("--------------- Returns -----------------")
print(result[0].analyzers._Returns.get_analysis())
print("--------------- SharpeRatio -----------------")
print(result[0].analyzers._SharpeRatio.get_analysis())
print("--------------- SharpeRatio_A -----------------")
print(result[0].analyzers._SharpeRatio_A.get_analysis())# 常用指标提取
analyzer = {}
# 提取年化收益
analyzer['年化收益率'] = result[0].analyzers._Returns.get_analysis()['rnorm']
analyzer['年化收益率(%)'] = result[0].analyzers._Returns.get_analysis()['rnorm100']
# 提取最大回撤
analyzer['最大回撤(%)'] = result[0].analyzers._DrawDown.get_analysis()['max']['drawdown'] * (-1)
# 提取夏普比率
analyzer['年化夏普比率'] = result[0].analyzers._SharpeRatio_A.get_analysis()['sharperatio']# 日度收益率序列
ret = pd.Series(result[0].analyzers._TimeReturn.get_analysis())
下面是在 Backtrader 社区中找到的自定义分析器,用于查看每笔交易盈亏情况:
地址:
https://community.backtrader.com/topic/1274/closed-trade-list-including-mfe-mae-analyzer;
该案例涉及到 trade 对象的相关属性,具体可以参考官方文档:https://www.backtrader.com/docu/trade/ 。
class trade_list(bt.Analyzer):def __init__(self):self.trades = []self.cumprofit = 0.0def notify_trade(self, trade):if trade.isclosed:brokervalue = self.strategy.broker.getvalue()dir = 'short'if trade.history[0].event.size > 0: dir = 'long'pricein = trade.history[len(trade.history)-1].status.pricepriceout = trade.history[len(trade.history)-1].event.pricedatein = bt.num2date(trade.history[0].status.dt)dateout = bt.num2date(trade.history[len(trade.history)-1].status.dt)if trade.data._timeframe >= bt.TimeFrame.Days:datein = datein.date()dateout = dateout.date()pcntchange = 100 * priceout / pricein - 100pnl = trade.history[len(trade.history)-1].status.pnlcommpnlpcnt = 100 * pnl / brokervaluebarlen = trade.history[len(trade.history)-1].status.barlenpbar = pnl / barlenself.cumprofit += pnlsize = value = 0.0for record in trade.history:if abs(size) < abs(record.status.size):size = record.status.sizevalue = record.status.valuehighest_in_trade = max(trade.data.high.get(ago=0, size=barlen+1))lowest_in_trade = min(trade.data.low.get(ago=0, size=barlen+1))hp = 100 * (highest_in_trade - pricein) / priceinlp = 100 * (lowest_in_trade - pricein) / priceinif dir == 'long':mfe = hpmae = lpif dir == 'short':mfe = -lpmae = -hpself.trades.append({'ref': trade.ref,'ticker': trade.data._name,'dir': dir,'datein': datein,'pricein': pricein,'dateout': dateout,'priceout': priceout,'chng%': round(pcntchange, 2),'pnl': pnl, 'pnl%': round(pnlpcnt, 2),'size': size,'value': value,'cumpnl': self.cumprofit,'nbars': barlen, 'pnl/bar': round(pbar, 2),'mfe%': round(mfe, 2), 'mae%': round(mae, 2)})def get_analysis(self):return self.trades# 添加自定义的分析指标
cerebro.addanalyzer(trade_list, _name='tradelist')# 启动回测
result = cerebro.run(tradehistory=True)# 返回结果
ret = pd.DataFrame(result[0].analyzers.tradelist.get_analysis())
参数优化:
该功能只需通过 cerebro.optstrategy() 方法往大脑添加策略。
class TestStrategy(bt.Strategy):params=(('period1',5),('period2',10),) #全局设定均线周期......# 实例化大脑
cerebro1= bt.Cerebro(optdatas=True, optreturn=True)
# 设置初始资金
cerebro1.broker.set_cash(10000000)
# 加载数据
datafeed1 = bt.feeds.PandasData(dataname=data1, fromdate=datetime.datetime(2019,1,2), todate=datetime.datetime(2021,1,28))
cerebro1.adddata(datafeed1, name='600466.SH')# 添加优化器
cerebro1.optstrategy(TestStrategy, period1=range(5, 25, 5), period2=range(10, 41, 10))# 添加分析指标
# 返回年初至年末的年度收益率
cerebro1.addanalyzer(bt.analyzers.AnnualReturn, _name='_AnnualReturn')
# 计算最大回撤相关指标
cerebro1.addanalyzer(bt.analyzers.DrawDown, _name='_DrawDown')
# 计算年化收益
cerebro1.addanalyzer(bt.analyzers.Returns, _name='_Returns', tann=252)
# 计算年化夏普比率
cerebro1.addanalyzer(bt.analyzers.SharpeRatio_A, _name='_SharpeRatio_A')
# 返回收益率时序
cerebro1.addanalyzer(bt.analyzers.TimeReturn, _name='_TimeReturn')# 启动回测
result = cerebro1.run()# 打印结果
def get_my_analyzer(result):analyzer = {}# 返回参数analyzer['period1'] = result.params.period1analyzer['period2'] = result.params.period2# 提取年化收益analyzer['年化收益率'] = result.analyzers._Returns.get_analysis()['rnorm']analyzer['年化收益率(%)'] = result.analyzers._Returns.get_analysis()['rnorm100']# 提取最大回撤(习惯用负的做大回撤,所以加了负号)analyzer['最大回撤(%)'] = result.analyzers._DrawDown.get_analysis()['max']['drawdown'] * (-1)# 提取夏普比率analyzer['年化夏普比率'] = result.analyzers._SharpeRatio_A.get_analysis()['sharperatio']return analyzerret = []
for i in result:ret.append(get_my_analyzer(i[0]))pd.DataFrame(ret)