Introduction
When backtesting, we often want to know the operation of the strategy. Although we can get a glimpse of it through the final statistical indicators, it is most humane to visualize the backtesting process. At the same time, we can also design better by observing the backtesting process& Optimize quantitative strategies. Backtrader uses the matplotlib library to provide visualization capabilities
Instructions
Backtrader data visualization is very simple, just call the plot() method after run().
cerebro.run()
cerebro.plot()
plot(self, plotter=None, numfigs=1, iplot=True, **kwargs)
The meaning of each parameter of the method is as follows:
-
plotter
: PlotScheme and its derived class objects containing plotting properties. The default is None. If it is None, the default PlotScheme object will be instantiated. -
numfigs
: Split the graph into multiple images for display, the default is 1 -
iplot
: Whether to automatically plot inline when running in Jupyter Notebook, the default is True. If you are not running in jupyter, it is best to set this parameter to False, otherwise problems may occur. -
*kwargs
:args parameter is used to change the plotter attribute value
There are two ways to systematically control the visualization configuration:
-
Directly by setting the args parameter of the plot() method, as shown below.
cerebro.plot(iplot=False,
style='candel', # 设置主图行情数据的样式为蜡烛图
plotdist=0.1, # 设置图形之间的间距
barup = '#ff9896', bardown='#98df8a', # 设置蜡烛图上涨和下跌的颜色
volup='#ff9896', voldown='#98df8a', # 设置成交量在行情上涨和下跌情况下的颜色
)
2. Customize the PlotScheme class to modify the corresponding parameters
The PlotScheme object includes all system-level plotting options, as shown below.
class PlotScheme(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
The PlotScheme class defines a color(self, idx)
method that returns the color to be used. Subclasses can overload it, and its idx parameter is the current index of the line to be drawn. For example, MACD draws three lines, and the idx variable has three values: 0, 1, and 2. The new indicator idx will restart from 0. The default color scheme is Tableau 10 Color Palette
, and the corresponding index is tab10_index = [3, 0, 2, 1, 2, 4, 5, 6, 7, 8, 9]
. The colors to be used can be changed by overriding the color() method in a custom PlotScheme class or by passing the lcolors variable to the plot method.
def color(self, idx):
colidx = tab10_index[idx % len(tab10_index)]
return self.lcolors[colidx]
Visual components
Backtrader supports visualization of 3 major components:
-
Data feeds data source: import cerebro's original data through the adddata, replaydata and resampledata methods
-
Indicators : indicators declared in the strategy class or added through addindicator
-
Observers observer objects: observers added through addobserver, such as Cash and Value objects
When drawing graphics, the default is to draw the data feeds on the main chart. Some indicators are drawn on the main chart together with the data feeds, such as moving averages, and some are drawn in the form of subgraphs; observers are usually drawn on on sub-picture
Visualization options
In addition to the above-mentioned system control of visualization options through plot() parameters and custom PlotScheme, Indicators and Observers have some options to control their drawing forms. There are 3 types in total :
-
Object object-level visualization options—can affect the drawing behavior of the entire object, controlled by plotinfo
plotinfo = dict(plot=True, # 是否绘制
subplot=True, # 是否绘制成子图
plotname='', # 图形名称
plotabove=False, # 子图是否绘制在主图的上方
plotlinelabels=False, # 主图上曲线的名称
plotlinevalues=True,
plotvaluetags=True,
plotymargin=0.0,
plotyhlines=[],
plotyticks=[],
plothlines=[],
plotforce=False,
plotmaster=None,
plotylimited=True,
)
There are 2 ways to access plotinfo's properties as follows:
# 通过参数来设置
sma = bt.indicators.SimpleMovingAverage(self.data, period=15, plotname='mysma')
# 通过属性来设置
sma = bt.indicators.SimpleMovingAverage(self.data, period=15)
sma.plotinfo.plotname = 'mysma'
-
Line related visualization options - You can use the plotlines object to control the drawing behavior of the lines object. The options in plotlines will be directly passed to matplotlib when drawing, as shown below.
lines = ('histo',)
plotlines = dict(histo=dict(_method='bar', alpha=0.50, width=1.0))
-
Method-controlled visualization — When dealing with indicator indicators and observers, the _plotlabel(self), _plotinit(self) methods allow further control of the visualization
Conclusion & Communication
Follow the WeChat public account: Zhuge Shuo Talk for more content. At the same time, you can also get invitations to join the quantitative investment group, communicate and discuss with many investment enthusiasts, quantitative practitioners, and technology experts, and quickly improve your investment level in actual combat.
Writing articles is not easy. If you think this article is helpful to you, please click and read it.