Skip to content

Latest commit

 

History

History
329 lines (253 loc) · 12.7 KB

File metadata and controls

329 lines (253 loc) · 12.7 KB

53、backtrader 的一些基本概念---如何用 backtrader 画图?

原文:https://yunjinqi.blog.csdn.net/article/details/115279045

backtrader 的画图主要是通过 matplotlib 来实现的,当 cerebro 中加载的数据比较多,指标比较多的时候,用 matplotlib 画图就会显得比较臃肿,现在也有不少人对 backtrader 的画图功能进行了扩展,比如backtrader_plotting(注:在 python3.8 ubuntu20.04 中,有 bug)

plotinfo 的使用

关于画图,其实已经讲过一部分内容了,比如在如何创建一个新的技术指标(indicator) 讲了 plotinfo 的一些参数,在这里,进行一些补充:

plotinfo = dict(
        plot = True, # 是否显示这个指标值,True 的时候显示,False 的时候不显示
        subplot = True,# 是否把指标显示到另一个窗口,True 是显示到另一个窗口,False 是显示在主图
        plotname = "",# 显示 line 的名称,默认是 class.__name__
        plotskip=False,# 旧版本的 matplotlib 上使用,已经移除
        plotabove = False,# 默认情况下,指标是在主图或者主图下面,当是 True 的时候,指标值会画在主图上面的图上
        plotlinelabels = False,# 默认情况下,如果计算的是指标 1 的指标 2,只显示指标 2,当是 True 的时候,两个都显示
        plotlinevalues=True,# 控制是否显示指标以及 observer 的最后一个数据的值
        plotvaluetags=True,# 控制是否显示最后一个值得 value tag
        plotymargin=0.15,# 画图的时候距离顶部和底部的距离是 0.15
        plotyticks=[1.0, -1.0],# 计算 y 的边界值,当是空列表的时候会自动计算
        plothlines=[1.0, -1.0],# 计算水平的边界值,默认在 1 到-1 的范围
        plotyhlines=[],# 用同一个参数,控制垂直和水平范围
        plotforce=False,# 当认为一个指标应该被画出来,但是实际上并没有,就把这个设置成 True,作为最后的手段
     	plotmaster=None,# 是否显示指标是在哪个数据上计算的
        plotylimited=True,# 计算的指标控制数据显示的范围;如果是 False,是数据控制显示范围,指标可能超出图形的边界
    ) 

在计算技术指标的时候,可以自定义显示的名称以及参数等数据,举例说明:

sma = bt.indicators.SimpleMovingAverage(self.data, period=15, plotname='mysma')
# 或者使用下面的代码
sma = bt.indicators.SimpleMovingAverage(self.data, period=15)
sma.plotinfo.plotname = 'mysma' 

plotlines 的使用

line = dict(
	_plotskip = True,# 如果设置成 True,这个 line 将会被忽略,不会画图,False 会画图
    _plotvalue = True,# 控制是否画出来这个 line 的最后一个值
    _plotvaluetag = True,# 控制是否把最后一个值显示在右边的坐标轴上
    _name = "xxx",# 把 line 的名称改变为 xxx
    _skipnan = False,# 默认不忽略缺失值,如果设置成 True,将会忽略缺失值,在两个点之间画线
    _samecolor = True,# 强制让 matplotlib 画图的颜色是一样,否则将按照 matplotlib 的机制,将循环给每个图赋予不同的颜色
    _method = "",# 给这个 line 画图选定特定的方法,如果没有指定,将会使用最基本的画图方法
    _fill_gt(line_name or value,color),# 两个参数,一个是 line 的名称或者数值,一个是颜色;用于填充颜色
) 

举例说明一些常见的用法:

# 把 histo 这条线画成柱状图(bar)
lines = ('histo',)
plotlines = dict(histo=dict(_method='bar', alpha=0.50, width=1.0))
# 把 myline 这条线超过 other_line 的部分画成红色
plotlines = dict(
    myline=dict(_fill_gt('other_line', 'red'))
)
# 把 myline 超过 50 的部分画成红色
plotlines = dict(
    myline=dict(_fill_gt(50, 'red))
)

# 把 myline 这条线超过 other_line 的部分画成红色,设置 50%的透明度
plotlines = dict(
    myline=dict(_fill_gt('other_line', ('red', 0.50)))
)
# 买卖点设置
plotlines = dict(
    buy=dict(marker='^', markersize=8.0, color='lime', fillstyle='full'),
    sell=dict(marker='v', markersize=8.0, color='red', fillstyle='full')
)
# observer 中的 trades 的 pnl 的设置
...
lines = ('pnlplus', 'pnlminus')
...

plotlines = dict(
    pnlplus=dict(_name='Positive',
                 marker='o', color='blue',
                 markersize=8.0, fillstyle='full'),
    pnlminus=dict(_name='Negative',
                  marker='o', color='red',
                  markersize=8.0, fillstyle='full')
)
# observer 中回撤设置
lines = ('drawdown', 'maxdrawdown',)

...

plotlines = dict(maxdrawdown=dict(_plotskip='True',))
# 技术指标中布林带的设置
plotlines = dict(
    mid=dict(ls='--'),
    top=dict(_samecolor=True),
    bot=dict(_samecolor=True),
)
# 技术指标中 Stochastic 的设置
lines = ('percK', 'percD',)
...
plotlines = dict(percD=dict(_name='%D', ls='--'),
                 percK=dict(_name='%K')) 

控制指标画图的方法

当设计指标和 observer 的时候,有两个函数可以用于控制画图

  • _plotlabel(self)

    控制显示的指标名称;会在指标的名称后面增加新的参数,如:

    def _plotlabel(self):
        plabels = [self.p.period]
        plabels += [self.p.movav] * self.p.notdefault('movav')
        return plabels 
  • _plotinit(self)

    将会在画图之前调用,做一些特殊的初始化操作;

    # 将会额外增加两条水平的线,upperband 和 lowerband
    def _plotinit(self):
        self.plotinfo.plotyhlines = [self.p.upperband, self.p.lowerband] 

整体上控制画图的参数

cerebro.plot()有很多参数可以使用,可以使用不同的参数控制画出来的图形

  • plotter

    控制画图的属性值,默认值是 None,将会使用默认的 plotter,即 PlotScheme

  • numfigs

    当一个图形中有太多的 bar 的时候,将会不容易观察;这个将会把图形切割成很多的片段

  • iplot

    如果在 notebook 中进行画图,将会自动使用 inline 模式

  • **kwargs

    传入的参数将会改变 plotter 或者 PlotScheme 的值

# 默认画图中的一些参数,大家可以忽略,基本用不到.最好能够结合 matplotlib 来看这一部分
# self.style 这个比较有意思,可以设置线段的类型
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 

PlotScheme 中颜色的控制机制

PlotScheme 提供了一个可以被重写的方法,用于定义下个 line 的颜色:

def color(self,idx):
	pass 
# idx 是现在的 index 在一个单独的幅图中画图。
# macd 有三个 line,将会使用 0,1,2 三个 idx
# 在下个图或者另外的指标中,idx 将会重新从 idx 开始 

backtrader 默认使用 Tableau 10 Color Palette,并且把 index 修改成如下:

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

通过重写 color 或者在 plot 中改变 lcolors 的变量值,整个画图的颜色是可以完全改变的。在源代码中,还有Tableau 10 Light 和 the Tableau 20 color palettes 的定义,感兴趣可以参考。

画出来一部分图

如果 cerebro.plot()包含的日期或者 bar 个数较多,可以只画出来一部分,cerebro.plot()有两个参数 start 和 end 支持截取一部分日期或者 bar,参数也支持两种,一种是 datetime 格式,一种是数字格式

# 使用 datetime 格式
cerebro.plot(start=datetime.date(2005, 7, 1), end=datetime.date(2006, 1, 31))
# 或者使用数字
cerebro.plot(start=75, end=185) 

如何让不同的数据共享一个坐标轴

如果要加载两个以上的数据,并且希望这两个数据共享一个坐标轴,就需要对第二个以后的数据做特殊处理

import backtrader as bt

cerebro = bt.Cerebro()

data0 = bt.feeds.MyFavouriteDataFeed(dataname='futurename')
cerebro.adddata(data0)
data1 = bt.feeds.MyFavouriteDataFeed(dataname='spotname')
# 需要对 data1 额外做下面的处理
data1.compensate(data0)  
data1.plotinfo.plotmaster = data0
data1.plotinfo.sameaxis = True
# 加载 data1
cerebro.adddata(data1)

...

cerebro.run() 

智慧、心灵、财富,总要有一个在路上,愿我们能在人生的道路上,不断成长、不断成熟~~~

感兴趣可以关注我的专栏:

my_quant_study_note:分享一些关于量化投资、量化交易相关的思考

backtrader 量化投资回测与交易:本专栏免费,分享 backtrader 相关的内容。

[量化投资神器-backtrader 源码解析-从入门到精通:本专栏目前收费 99 元,预计更新 100 篇策略+20 篇 backtrader 讲解+80 篇源代码分析。](