添加分析指标
# 添加分析指标
# 返回年初至年末的年度收益率
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.0
def 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.price
priceout = trade.history[len(trade.history)-1].event.price
datein = 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 - 100
pnl = trade.history[len(trade.history)-1].status.pnlcomm
pnlpcnt = 100 * pnl / brokervalue
barlen = trade.history[len(trade.history)-1].status.barlen
pbar = pnl / barlen
self.cumprofit += pnl
size = value = 0.0
for record in trade.history:
if abs(size) < abs(record.status.size):
size = record.status.size
value = record.status.value
highest_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) / pricein
lp = 100 * (lowest_in_trade - pricein) / pricein
if dir == 'long':
mfe = hp
mae = lp
if dir == 'short':
mfe = -lp
mae = -hp
self.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.period1
analyzer['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 analyzer
ret = []
for i in result:
ret.append(get_my_analyzer(i[0]))
pd.DataFrame(ret)