Backtrader来啦:可视化篇(重构)

量化投资与机器学习公众号 独家撰写

公众号为全网读者带来Backtrader系列自推出第一期以来,受到了众多读者的喜爱与点赞,QIML也会继续把这个系列做好(www.LangLei.com.cn)。

让那些割韭菜的课程都随风而去吧!!!

公众号将为大家多维度、多策略、多场景来讲述Backtrader在量化投资领域的实践应用。同时,我们对每段代码都做了解读说明,愿你在Quant的道路上学有所获!

预定系列

  • Backtrader 来了
  • Backtrader 数据篇
  • Backtrader 指标篇
  • Backtrader 交易篇(上)
  • Backtrader 交易篇(下)
  • Backtrader 策略篇
  • Backtrader 可视化篇(重构)
  • Backtrader 常见问题汇总
  • Backtrader 常见案例汇总
  • ······

此系列将由浅入深,每期1~2周,大家敬请期待!

QIML Github已上线!

https://github.com/QIML

希望大家给我们的项目打

公众号今天正式对宣布,我们的官方Github已在今天正式上线!后面我们会把相关推文的数据、代码一并进行同步。

同时,我们会在今后的日子里,在全网发布一系列好用、实用、你绝对爱不释手的量化开源工具包!

公众号希望给国内量化投资圈贡献一份自己的力量。希望影响更多人了解量化、学习量化、找到属于一条属于自己的路!

前言

今天的《可视化篇》先会介绍与可视化相关的观测器模块 observers ,然后介绍 Backtrader 自带的绘图函数 plot ,在介绍的过程中会指出如何修改图形的样式;最后直接基于回测返回的收益序列 TimeReturn,结合pyfolio和matplotlib工具,自定义了一个可视化图形。

获取完整代码+数据,见文末链接

observers 观测器

observers 是 Backtrader 的“观测器模块”,主要用于统计回测信息,并在 plot 的帮助下实现信息的可视化展示,如下图所示:

最常用的观测器

下面是对最常用的观测器的介绍,其他观测器可以参考Backtrader 官方文档 ~ Observers - Reference:

  • backtrader.observers.Broker:记录了经纪商 broker 中各时间点的可用资金和总资产;可视化时,会同时展示 cash 和 values 曲线;如果想各自单独展示 cash 和 values,可以分别调用 backtrader.observers.Cash 和 backtrader.observers.Value;
  • backtrader.observers.BuySell:记录了回测过程中的买入和卖出信号;可视化时,会在价格曲线上标注买卖点;
  • backtrader.observers.Trades:记录了回测过程中每次交易的盈亏(从买入建仓到卖出清仓算一次交易);可视化时,会绘制盈亏点;
  • backtrader.observers.TimeReturn:记录了回测过程中的收益序列;可视化时,会绘制 TimeReturn 收益曲线;
  • backtrader.observers.DrawDown:记录了回测过程的回撤序列;可视化时,绘制回撤曲线;
  • backtrader.observers.Benchmark:记录了业绩基准的收益序列,业绩基准的数据必须事先通过 adddata、resampledata、replaydata 等数据添加函数添加进大脑中 cerebro;可视化时,会同时绘制策略本身的收益序列(即:backtrader.observers.TimeReturn 绘制的收益曲线)和业绩基准的收益曲线。

如何添加 observers

observers 观测器是通过 addobserver 添加给大脑 cerebro 的:addobserver(obscls, *args, **kwargs),其中,参数 obscls 对应 observers 类下的观测器、*args, **kwargs 对应观测器支持设置的参数,具体如下所示:

importbacktrader asbt

...

cerebro = bt.Cerebro(stdstats= False)

cerebro.addobserver(bt.observers.Broker)

cerebro.addobserver(bt.observers.Trades)

cerebro.addobserver(bt.observers.BuySell)

cerebro.addobserver(bt.observers.DrawDown)

cerebro.addobserver(bt.observers.TimeReturn)

# 添加业绩基准时,需要事先将业绩基准的数据添加给 cerebro

banchdata = bt.feeds.PandasData(dataname=data, fromdate=st_date, todate=ed_date)

cerebro.adddata(banchdata, name= 'xxxx')

cerebro.addobserver(bt.observers.Benchmark, data=banchdata)

对于 Broker、Trades、BuySell 3个观测器,默认是自动添加给 cerebro 的,可以在实例化大脑时,通过 stdstats 来控制:bt.Cerebro(stdstats=False) 表示可视化时,不展示 Broker、Trades、BuySell 观测器;反之,自动展示;默认情况下是自动展示。

如何读取 observers 中的数据

observers 中记录了各种回测数据,可以将其看作是一个支持可视化展示的数据存储器,所以 observers 属于 lines 对象。如果想在 Strategy 中读取 observers 中的数据,就会用到 line 的相关操作,具体可以参考《Backtrader 数据篇》的内容,observers 的数据通过 self.stats 对象 来连接:

classMyStrategy(bt.Strategy):

defnext(self):

# 当前时点的前一天的可用现金

self.stats.broker.cash[ 0]

# 当前时点的前一天的总资产

self.stats.broker.value[ 0]

# 获取当前时刻前一天的收益

self.stats.timereturn.line[ 0]

# observers 取得[0]值,对应的 next 中 self.data.datetime[-1] 这一天的值

如果想要将 observers 中的数据保存到本地,可以通过 writer 写入本地文件,如下面的读写到本地 CSV 文件:

importcsv

classTestStrategy(bt.Strategy):

...

defstart(self):

self.mystats = csv.writer(open( "mystats.csv", "w"))

self.mystats.writerow([ 'datetime',

'drawdown', 'maxdrawdown',

'timereturn',

'value', 'cash'])

defnext(self):

self.mystats.writerow([self.data.datetime.date( -1).strftime( '%Y-%m-%d'),

'%.4f'% self.stats.drawdown.drawdown[ 0],

'%.4f'% self.stats.drawdown.maxdrawdown[ 0],

'%.4f'% self.stats.timereturn.line[ 0],

'%.4f'% self.stats.broker.value[ 0],

'%.4f'% self.stats.broker.cash[ 0]])

defstop(self):

self.mystats.writerow([self.data.datetime.date( 0).strftime( '%Y-%m-%d'),

'%.4f'% self.stats.drawdown.drawdown[ 0],

'%.4f'% self.stats.drawdown.maxdrawdown[ 0],

'%.4f'% self.stats.broker.value[ 0],

'%.4f'% self.stats.broker.cash[ 0]])

# 当运行到最后一根 bar 后, next 中记录的是上一根 bar 的收益

# stop 是在 next 运行完后才运行的,此时 observers 已经计算完 最后一根 bar 的收益了

# 所以可以在 stop 中获取最后一根 bar 的收益

自定义 observers

和之前各种自定义一致,自定义 observers 同样是在继承父类 bt.observer.Observer 的基础上,自定义新的的observers。下面是 Backtrader 官网提供的例子,用于统计已成功创建的订单的价格和到期订单的价格:

classOrderObserver(bt.observer.Observer):

lines = ( 'created', 'expired',)

plotinfo = dict(plot= True, subplot= True, plotlinelabels= True)

plotlines = dict(

created=dict(marker= '*', markersize= 8.0, color= 'lime', fillstyle= 'full'),

expired=dict(marker= 's', markersize= 8.0, color= 'red', fillstyle= 'full')

)

defnext(self):

fororder inself._owner._orderspending:

iforder.data isnotself.data:

continue

ifnotorder.isbuy:

continue

# Only interested in "buy" orders, because the sell orders

# in the strategy are Market orders and will be immediately

# executed

iforder.status in[bt.Order.Accepted, bt.Order.Submitted]:

self.lines.created[ 0] = order.created.price

eliforder.status in[bt.Order.Expired]:

self.lines.expired[ 0] = order.created.price

  • observers 本身是 Lines 对象,所以构建逻辑与自定义 Indicator 类似,将要统计的数据指定为相应的 line,然后随着回测的进行依次存入数据;
  • 作为 Lines 对象的 Observers 和 Indicator ,类内部都有 plotinfo = dict(...)、plotlines = dict(...) 属性,用于回测结束后通过 cerebro.plot 方法进行可视化展示;
  • 有时候如果想修改 Backtrader 已有观测器的相关属性,可以直接继承该观测器,然后设置属性取值进行修改。如下面在原始 bt.observers.BuySell 的基础上,修改买卖点的样式。

classmy_BuySell(bt.observers.BuySell):

params = (( 'barplot', True), ( 'bardist', 0.02))

plotlines = dict(

buy=dict(marker= r'$\Uparrow$', markersize= 10.0, color= '#d62728'),

sell=dict(marker= r'$\Downarrow$', markersize= 10.0, color= '#2ca02c'))

# 将 三角形改为箭头

# 突然感受到了继承的强大!

plot 图形绘制

cerebro.plot 写在 cerebro.run 后面,用于回测的可视化。总的来说,cerebro.plot 支持回测如下 3 大内容:

  • Data Feeds:即在回测开始前,通过 adddata、replaydata、resampledata 等方法导入大脑的原始数据;
  • Indicators :即回测时构建的各类指标,比如在 strategy 中构建的指标、通过 addindicator 添加的;
  • Observers :即上文介绍的观测器对象;
  • 在绘制图形时,默认是将 Data Feeds 绘制在主图上;Indicators 有的与 Data Feeds 一起绘制在主图上,比如均线,有的以子图形式绘制;Observers 通常绘制在子图上。

plot 中的参数

plot 中的参数主要用于系统性的配置图形,具体参数如下所示:

plot(plotter= None, # 包含各种绘图属性的对象或类,如果为None,默认取 PlotScheme 类,如下所示

numfigs= 1, # 是否将图形拆分成多幅图展示,如果时间区间比较长,建议分多幅展示

iplot= True, # 在 Jupyter Notebook 上绘图时是否自动 plot inline

**kwargs) # 对应 PlotScheme 中的各个参数

# PlotScheme 中的参数如下所示

classPlotScheme(object):

def__init__(self):

# to have a tight packing on the chart wether only the x axis or also

# the y axis have (see matplotlib)

self.ytight = False

# y-margin (top/bottom) for the subcharts. This will not overrule the

# option plotinfo.plotymargin

self.yadjust = 0.0

# Each new line is in z-order below the previous one. change it False

# to have lines paint above the previous line

self.zdown = True

# Rotation of the date labes on the x axis

self.tickrotation = 15

# How many "subparts" takes a major chart (datas) in the overall chart

# This is proportional to the total number of subcharts

self.rowsmajor = 5

# How many "subparts" takes a minor chart (indicators/observers) in the

# overall chart. This is proportional to the total number of subcharts

# Together with rowsmajor, this defines a proportion ratio betwen data

# charts and indicators/observers charts

self.rowsminor = 1

# Distance in between subcharts

self.plotdist = 0.0

# Have a grid in the background of all charts

self.grid = True

# Default plotstyle for the OHLC bars which (line -> line on close)

# Other options: 'bar' and 'candle'

self.style = 'line'

# Default color for the 'line on close' plot

self.loc = 'black'

# Default color for a bullish bar/candle (0.75 -> intensity of gray)

self.barup = '0.75'

# Default color for a bearish bar/candle

self.bardown = 'red'

# Level of transparency to apply to bars/cancles (NOT USED)

self.bartrans = 1.0

# Wether the candlesticks have to be filled or be transparent

self.barupfill = True

self.bardownfill = True

# Wether the candlesticks have to be filled or be transparent

self.fillalpha = 0.20

# Wether to plot volume or not. Note:if the data in question has no

# volume values, volume plotting will be skipped even if this is True

self.volume = True

# Wether to overlay the volume on the data or use a separate subchart

self.voloverlay = True

# Scaling of the volume to the data when plotting as overlay

self.volscaling = 0.33

# Pushing overlay volume up for better visibiliy. Experimentation

# needed if the volume and data overlap too much

self.volpushup = 0.00

# Default colour for the volume of a bullish day

self.volup = '#aaaaaa'# 0.66 of gray

# Default colour for the volume of a bearish day

self.voldown = '#cc6073'# (204, 96, 115)

# Transparency to apply to the volume when overlaying

self.voltrans = 0.50

# Transparency for text labels (NOT USED CURRENTLY)

self.subtxttrans = 0.66

# Default font text size for labels on the chart

self.subtxtsize = 9

# Transparency for the legend (NOT USED CURRENTLY)

self.legendtrans = 0.25

# Wether indicators have a leged displaey in their charts

self.legendind = True

# Location of the legend for indicators (see matplotlib)

self.legendindloc = 'upper left'

# Plot the last value of a line after the Object name

self.linevalues = True

# Plot a tag at the end of each line with the last value

self.valuetags = True

# Default color for horizontal lines (see plotinfo.plothlines)

self.hlinescolor = '0.66'# shade of gray

# Default style for horizontal lines

self.hlinesstyle = '--'

# Default width for horizontal lines

self.hlineswidth = 1.0

# Default color scheme: Tableau 10

self.lcolors = tableau10

# strftime Format string for the display of ticks on the x axis

self.fmt_x_ticks = None

# strftime Format string for the display of data points values

self.fmt_x_data = None

如果想要系统性修改图形样式,可以重新定义 PlotScheme 类,然后修改里面用到的参数;也可以直接在plot 中修改:

# 通过参数形式来设置

cerebro.plot(iplot= False,

style= 'candel', # 设置主图行情数据的样式为蜡烛图

lcolors=colors , # 重新设置主题颜色

plotdist= 0.1, # 设置图形之间的间距

barup = '#ff9896', bardown= '#98df8a', # 设置蜡烛图上涨和下跌的颜色

volup= '#ff9896', voldown= '#98df8a', # 设置成交量在行情上涨和下跌情况下的颜色

....)

关于主题颜色,Backtrader 提供了Tableau 10 、Tableau 10 Light、Tableau 20 3种主题色,默认是以 Tableau 10 为主题色。但是看源代码,不知道如何修改 lcolors,源码 scheme.py 文件中的 tableau10 只一个变量,直接赋值给 self.lcolors = tableau10,如果在我们在自己的的 notebook上运行 lcolors=tableau10 会报错,提示 tableau10 变量不存在。所以,如果想修改主题色,需要重新定义 tableau10 变量:

# 定义主题色变量:直接从源码 scheme.py 中复制的

tableau20 = [

'steelblue', # 0

'lightsteelblue', # 1

'darkorange', # 2

'peachpuff', # 3

'green', # 4

'lightgreen', # 5

'crimson', # 6

'lightcoral', # 7

'mediumpurple', # 8

'thistle', # 9

'saddlebrown', # 10

'rosybrown', # 11

'orchid', # 12

'lightpink', # 13

'gray', # 14

'lightgray', # 15

'olive', # 16

'palegoldenrod', # 17

'mediumturquoise', # 18

'paleturquoise', # 19

]

tableau10 = [

'blue', # 'steelblue', # 0

'darkorange', # 1

'green', # 2

'crimson', # 3

'mediumpurple', # 4

'saddlebrown', # 5

'orchid', # 6

'gray', # 7

'olive', # 8

'mediumturquoise', # 9

]

tableau10_light = [

'lightsteelblue', # 0

'peachpuff', # 1

'lightgreen', # 2

'lightcoral', # 3

'thistle', # 4

'rosybrown', # 5

'lightpink', # 6

'lightgray', # 7

'palegoldenrod', # 8

'paleturquoise', # 9

]

# 选一个主题色做修改

cerebro.plot(lcolors=tableau10)

# 当然也可以选自己喜欢的主题色

mycolors = [ '#729ece', '#ff9e4a', '#67bf5c',

'#ed665d', '#ad8bc9', '#a8786e',

'#ed97ca', '#a2a2a2', '#cdcc5d', '#6dccda']

cerebro.plot(lcolors=mycolors)

大家可以发现,从源码中复制的主题色,后面都注释了索引号,而 Backtrader 在绘制图形时,选择颜色的顺序依次是这样的:

  • tab10_index = [3, 0, 2, 1, 2, 4, 5, 6, 7, 8, 9];
  • tab10_index 中的序号对应的是 主题色 的索引号;
  • 每一幅图,依次取 tab10_index 中的序号对应的颜色来绘制,比如 MACD 有 3 条 line,line0 的颜色为 tab10_index[0] = 3,也就是 lcolors=tableau10 中的索引号为 3 对应的颜色 'crimson';line1 的颜色为 tab10_index[1] = 0,也就是 lcolors=tableau10 中的索引号为 0 对应的颜色 'blue';
  • 所以在设置颜色时,需要与 tab10_index 中的序号结合起来看。

局部绘图参数设置

对于 Indicators 和 Observers 的可视化设置,通过类内部的 plotinfo = dict(...)、plotlines = dict(...) 属性来控制,其中 plotinfo 主要对图形整体布局进行设置,plotlines 主要对具体 line 的样式进行设置:

plotinfo = dict(plot= True, # 是否绘制

subplot= True, # 是否绘制成子图

plotname= '', # 图形名称

plotabove= False, # 子图是否绘制在主图的上方

plotlinelabels= False, # 主图上曲线的名称

plotlinevalues= True, # 是否展示曲线最后一个时间点上的取值

plotvaluetags= True, # 是否以卡片的形式在曲线末尾展示最后一个时间点上的取值

plotymargin= 0.0, # 用于设置子图 y 轴的边界

plothlines=[a,b,...], # 用于绘制取值为 a,b,... 的水平线

plotyticks=[], # 用于绘制取值为 a,b,... y轴刻度

plotyhlines=[a,b,...], # 优先级高于plothlines、plotyticks,是这两者的结合

plotforce= False, # 是否强制绘图

plotmaster= None, # 用于指定主图绘制的主数据

plotylimited= True,

# 用于设置主图的 y 轴边界,

# 如果True,边界只由主数据 data feeds决定,无法完整显示超出界限的辅助指标;

# 如果False, 边界由主数据 data feeds和指标共同决定,能确保所有数据都能完整展示

)

# 修改交易观测器的样式

classmy_Trades(bt.observers.Trades):

plotlines = dict(

pnlplus=dict(_name= 'Positive',

marker= '^', color= '#ed665d',

markersize= 8.0, fillstyle= 'full'),

pnlminus=dict(_name= 'Negative',

marker= 'v', color= '#729ece',

markersize= 8.0, fillstyle= 'full'))

# 修改买卖点样式

classmy_BuySell(bt.observers.BuySell):

params = (( 'barplot', True), ( 'bardist', 0.02)) # bardist 控制买卖点与行情线之间的距离

plotlines = dict(

buy=dict(marker= r'$\Uparrow$', markersize= 10.0, color= '#d62728'),

sell=dict(marker= r'$\Downarrow$', markersize= 10.0, color= '#2ca02c'))

部分修改效果

一般主图的样式通过 plot 中的参数来设置;Indicators 和 Observers 的样式通过继承原始类,然后通过修改plotinfo 和 plotlines 属性来设置;部分修改效果如下所示:

蜡烛图样式:

plt.style.use( 'seaborn') # 使用 seaborn 主题

plt.rcParams[ 'figure.figsize'] = 20, 10# 全局修改图大小

# 修改 Trades 观测器的样式

classmy_Trades(bt.observers.Trades):

plotlines = dict(

pnlplus=dict(_name= 'Positive',

marker= '^', color= '#ed665d',

markersize= 8.0, fillstyle= 'full'),

pnlminus=dict(_name= 'Negative',

marker= 'v', color= '#729ece',

markersize= 8.0, fillstyle= 'full'))

# 修改 BuySell 的样式

classmy_BuySell(bt.observers.BuySell):

params = (( 'barplot', True), ( 'bardist', 0.02))

plotlines = dict(

buy=dict(marker= r'$\Uparrow$', markersize= 10.0, color= '#d62728'),

sell=dict(marker= r'$\Downarrow$', markersize= 10.0, color= '#2ca02c'))

# 简单均线策略

classTestStrategy(bt.Strategy):

......

# 绘制图形

cerebro1 = bt.Cerebro(stdstats= False)

......

# 添加观测器

cerebro1.addobserver(bt.observers.DrawDown)

cerebro1.addobserver(bt.observers.Benchmark, data=datafeed1)

cerebro1.addobserver(bt.observers.Broker)

cerebro1.addobserver(my_Trades)

cerebro1.addobserver(my_BuySell)

#先运行策略

rasult = cerebro1.run

#策略运行完后,绘制图形

colors = [ '#729ece', '#ff9e4a', '#67bf5c', '#ed665d', '#ad8bc9', '#a8786e', '#ed97ca', '#a2a2a2', '#cdcc5d', '#6dccda']

tab10_index = [ 3, 0, 2, 1, 2, 4, 5, 6, 7, 8, 9]

cerebro1.plot(iplot= False,

style= 'line', # 绘制线型价格走势,可改为 'candel' 样式

lcolors=colors,

plotdist= 0.1,

bartrans= 0.2,

volup= '#ff9896',

voldown= '#98df8a',

loc= '#5f5a41',

grid= False) # 删除水平网格

蜡烛图样式:

绘制蜡烛图时,蜡烛之间会比较拥挤,可以通过设置 numfigs=2,分 2 部分绘制。下图只展示了后半部分的内容。

基于收益序列进行可视化

Backtrader 自带的绘图工具方便好用,不过平时在汇报策略回测结果时,可能更关注的是策略的累计收益曲线和业绩评价指标等结果,而这些回测统计信息只需基于回测返回的 TimeReturn 收益序列做简单计算即可得到。下面是基于 Backtrader 回测返回的分析器 TimeReturn、pyfolio、matplotlib 得到的可视化图形:

.....

# 回测时需要添加 TimeReturn 分析器

cerebro1.addanalyzer(bt.analyzers.TimeReturn, _name= '_TimeReturn')

result = cerebro1.run

# 提取收益序列

pnl = pd.Series(result[ 0].analyzers._TimeReturn.get_analysis)

# 计算累计收益

cumulative = (pnl + 1).cumprod

# 计算回撤序列

max_return = cumulative.cummax

drawdown = (cumulative - max_return) / max_return

# 计算收益评价指标

importpyfolio aspf

# 按年统计收益指标

perf_stats_year = (pnl).groupby(pnl.index.to_period( 'y')).apply( lambdadata: pf.timeseries.perf_stats(data)).unstack

# 统计所有时间段的收益指标

perf_stats_all = pf.timeseries.perf_stats((pnl)).to_frame(name= 'all')

perf_stats = pd.concat([perf_stats_year, perf_stats_all.T], axis= 0)

perf_stats_ = round(perf_stats, 4).reset_index

# 绘制图形

importmatplotlib.pyplot asplt

plt.rcParams[ 'axes.unicode_minus'] = False# 用来正常显示负号

importmatplotlib.ticker asticker # 导入设置坐标轴的模块

plt.style.use( 'seaborn') # plt.style.use('dark_background')

fig, (ax0, ax1) = plt.subplots( 2, 1, gridspec_kw = { 'height_ratios':[ 1.5, 4]}, figsize=( 20, 8))

cols_names = [ 'date', 'Annual\nreturn', 'Cumulative\nreturns', 'Annual\nvolatility',

'Sharpe\nratio', 'Calmar\nratio', 'Stability', 'Max\ndrawdown',

'Omega\nratio', 'Sortino\nratio', 'Skew', 'Kurtosis', 'Tail\nratio',

'Daily value\nat risk']

# 绘制表格

ax0.set_axis_off # 除去坐标轴

table = ax0.table(cellText = perf_stats_.values,

bbox=( 0, 0, 1, 1), # 设置表格位置, (x0, y0, width, height)

rowLoc = 'right', # 行标题居中

cellLoc= 'right',

colLabels = cols_names, # 设置列标题

colLoc = 'right', # 列标题居中

edges = 'open'# 不显示表格边框

)

table.set_fontsize( 13)

# 绘制累计收益曲线

ax2 = ax1.twinx

ax1.yaxis.set_ticks_position( 'right') # 将回撤曲线的 y 轴移至右侧

ax2.yaxis.set_ticks_position( 'left') # 将累计收益曲线的 y 轴移至左侧

# 绘制回撤曲线

drawdown.plot.area(ax=ax1, label= 'drawdown (right)', rot= 0, alpha= 0.3, fontsize= 13, grid= False)

# 绘制累计收益曲线

(cumulative).plot(ax=ax2, color= '#F1C40F', lw= 3.0, label= 'cumret (left)', rot= 0, fontsize= 13, grid= False)

# 不然 x 轴留有空白

ax2.set_xbound(lower=cumulative.index.min, upper=cumulative.index.max)

# 主轴定位器:每 5 个月显示一个日期:根据具体天数来做排版

ax2.xaxis.set_major_locator(ticker.MultipleLocator( 100))

# 同时绘制双轴的图例

h4,l1 = ax1.get_legend_handles_labels

h4,l2 = ax2.get_legend_handles_labels

plt.legend(h4+h4,l1+l2, fontsize= 12, loc= 'upper left', ncol= 1)

fig.tight_layout # 规整排版

plt.show

'seaborn' 主题下的绘制效果:

'dark_background' 主题下的绘制效果:

总结

关于回测结果的可视化,不同的需求对应不同的可视化内容。Backtrader 回测框架本身就对原始数据集 Data Feeds、回测指标 Indicators 、回测结果观测器 Observers 提供了对用户非常友好的绘图接口。对于一些额外的数据,也可以结合 Backtrader 分析器 Analyzers 返回的指标,选用自己熟悉的 Python 绘图工具 Matplotlib、Seaborn、Plotly 等来进行可视化展示。

代码+数据获取

https://github.com/QIML/learn_backtrader

希望大家给我们的项目打

量化投资与机器学习微信公众号,是业内垂直于量化投资、对冲基金、Fintech、人工智能、大数据领域的主流自媒体公众号拥有来自公募、私募、券商、期货、银行、保险、高校等行业20W+关注者,连续2年被腾讯云+社区评选为“年度最佳作者”。

主营产品:中空玻璃设备,玻璃陶瓷加工设备,燃煤锅炉,燃气锅炉,电热锅炉,锅炉熔炉及配件,干燥设备,设备及组件