Skip to content

策划

原文: https://www.backtrader.com/docu/plotting/plotting/

尽管回溯测试是一个基于数学计算的自动化过程,但通常情况下,人们希望实际可视化正在发生的事情。无论是使用经过回溯测试运行的现有算法,还是查看指标(内置或自定义)随数据交付的内容。

因为每件事背后都有一个人,绘制数据源、指标、操作、现金和投资组合价值的演变图可以帮助人们更好地了解正在发生的事情,抛弃/修改/创造想法,以及看图表的人对视觉信息可能做的任何事情。

这就是为什么backtrader使用matplotlib提供的工具,提供内置的制图工具。

如何策划

任何回溯测试运行都可以通过调用单个方法来绘制:

cerebro.plot() 

当然,这通常是最后发出的命令,就像在这个简单的代码中一样,它使用来自backtrader源的一个样本数据。

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import backtrader as bt

class St(bt.Strategy):
    def __init__(self):
        self.sma = bt.indicators.SimpleMovingAverage(self.data)

data = bt.feeds.BacktraderCSVData(dataname='../../datas/2005-2006-day-001.txt')

cerebro = bt.Cerebro()
cerebro.adddata(data)
cerebro.addstrategy(St)
cerebro.run()
cerebro.plot() 

这就得到了下面的图表。

!image

该图表包括 3 名观察者,在这种情况下,考虑到缺乏任何交易,这些观察者大多毫无意义

  • 顾名思义,一名CashValue观察员在回测运行期间跟踪CashValue总波尔图(包括现金)

  • Trade观察者,在交易结束时显示实际损益

    交易定义为打开一个头寸并将该头寸带回0(直接或从多头到空头或从空头到多头的交叉)

  • 一个BuySell观察者,在买入卖出操作发生的位置(在价格之上)进行绘图

这些3 个观察者cerebro自动添加,并由stdstats参数控制(默认值:True。如果需要,请执行以下操作以禁用它们:

cerebro = bt.Cerebro(stdstats=False) 

或以后当运行时,如:

cerebro = bt.Cerebro()
...
cerebro.run(stdstats=False) 

标绘元素

尽管Observers在导言中已经提到,但它们并不是绘制的唯一元素。这三件事是有计划的:

  • adddatareplaydataresampledata向大脑添加数据源

  • 指标在策略层面上声明(或添加到大脑中的addindicator纯粹用于实验目的,并将指标添加到虚拟策略中)

  • 观察者添加到大脑中addobserver

    观察者是与策略同步运行的线路对象,可以访问整个生态系统,能够跟踪CashValue等事物

打印选项

指示器观察者有几个选项,可以控制它们在图表上的绘制方式。有三大集团:

  • 影响整个对象打印行为的选项

  • 影响各条线打印行为的选项

  • 影响系统范围打印选项的选项

对象范围打印选项

这些由指示器观察者中的该数据集控制:

plotinfo = dict(plot=True,
                subplot=True,
                plotname='',
                plotskip=False,
                plotabove=False,
                plotlinelabels=False,
                plotlinevalues=True,
                plotvaluetags=True,
                plotymargin=0.0,
                plotyhlines=[],
                plotyticks=[],
                plothlines=[],
                plotforce=False,
                plotmaster=None,
                plotylimited=True,
           ) 

虽然plotinfo在类定义时显示为dict,但backtrader的元类机制将其转化为一个被继承的对象,甚至可以经历多重继承。这意味着:

  • 如果子类将subplot=True之类的值更改为subplot=False,则层次结构较低的子类将后者作为subplot的默认值

有两种方法可以为这些参数赋值。让我们看看 1st方法的SimpleMovingAverage实例化:

sma = bt.indicators.SimpleMovingAverage(self.data, period=15, plotname='mysma') 

从示例中可以推断,SimpleMovingAverage构造函数未使用的任何**kwargs都将被解析为plotinfo值(如果可能)。SimpleMovingAverage定义了一个参数period。这意味着plotname将与plotinfo中同名的参数匹配。

2nd方法:

sma = bt.indicators.SimpleMovingAverage(self.data, period=15)
sma.plotinfo.plotname = 'mysma' 

可以访问沿着SimpleMovingAverage实例化的plotinfo对象,也可以使用标准的Python点符号访问其中的参数。比语法 abve 更简单、更清晰。

期权的含义

  • plot:是否需要打印对象

  • subplot:是沿着数据还是在独立的子图中绘图。移动平均线是在数据上绘制的示例。随机RSI是以不同比例绘制在子图表中的事物的示例。

  • plotname:在图表上使用的名称,而不是名称。如上例所示,用mysma代替SimpleMovingAverage

  • plotskip弃用):旧别名plot

  • plotabove:是否在数据上方绘制。否则,请在下面绘制。只有在subplot=True的情况下才有效

  • plotlinelabels:当subplot=False时,是否沿图表上图例中的数据绘制各条线的名称

    示例:波林格带有 3 条线,但指示器绘制在数据顶部。让图例只显示一个名称,如BollingerBands,而不是显示 3 个单独行的名称(midtopbot)似乎是明智的

    这方面的一个用例是BuySell观察者,对于该观察者,显示两条线的名称及其标记是有意义的:BuySell,以便最终用户清楚地知道这是什么。

  • plotlinevalues:控制指示器和观察者中线条的图例是否具有最后绘制的值。每行可通过_plotvalue控制

  • plotvaluetags:控制是否在行的右侧绘制带有最后一个值的值标记。每行可通过_plotvaluetag控制

  • plotymargin:添加到图表上各个子图表顶部和底部的边距

    这是一个百分比,但以 1 为基础。例如:0.05->5%

  • plothlines:一个可编辑的,包含水平线必须绘制的值(在刻度内)。

    例如,这有助于具有超买超卖区域的经典指标,如RSI,通常在7030处绘制线条

  • plotyticks:一个可编辑的,包含数值(在刻度内),在该数值处,刻度上必须特别放置数值记号

    例如,强制电子秤有一个50来标识电子秤的中点。虽然这看起来很明显,但指示器使用自动缩放机制,如果带有0-100刻度的指示器定期在 30-95 之间移动,则50可能不会明显位于中心。

  • plotyhlines:一个可编辑的,包含水平线必须绘制的值(在刻度内)。

    这可以同时接管plothlinesplotyticks

    如果以上都没有定义,那么放置水平线和刻度的位置将完全由该值控制

    如果定义了上述任何一项,则其优先于此选项中的值

  • plotforce:有时,因此将数据源与指标和 bla、bla、bla 匹配的复杂过程……自定义指标可能无法绘制。这是尝试强制打印的最后手段。

    如果其他一切都失败了,就使用它

  • plotmaster:一个指示器/观察者有一个主设备,该主设备是数据正在工作。在某些情况下,可能需要使用不同的母版绘制。

    一个用例是PivotPoint指标,它根据数据计算,但用于数据。只有将其绘制在每日数据上才有意义,而该数据正是该指示器有意义的地方。

  • plotylimited:目前仅适用于数据源。如果True(默认),数据图上的其他行不会改变比例。示例:布林带(顶部和底部)可能远离数据馈送的实际绝对最小值/最大值。使用\plotlimited=True, those bands remain out of the chart, because the data controls the scaling. If set toFalse`,条带会影响 y 刻度,并在图表上可见

    一个用例是PivotPoint指标,它根据数据计算,但用于数据。只有将其绘制在每日数据上才有意义,而该数据正是该指示器有意义的地方。

特定于线的打印选项

指标/观察者线且该线的绘制方式会受到plotlines对象的影响。plotlines中指定的大多数选项在绘图时直接传递给matplotlib。因此,文档依赖于已经完成的事情的示例。

重要:选项是按行指定的。

部分期权由反向交易者直接控制。这些都以下划线(_开头):

  • _plotskip布尔值),表示如果设置为True,则必须跳过特定直线的绘制

  • _plotvalue布尔值)控制此行图例是否包含最后打印的值(默认为True

  • _plotvaluetag布尔值)用于控制是否绘制带有最后一个值的右手侧标签(默认为True

  • _name字符串)用于更改特定行的绘图名称

  • _skipnanbool,默认值:False):打印时跳过NaN值,例如允许在指示器生成的两个距离点之间绘制一条线,其所有中间值为NaN(新创建数据点的默认值)

  • _samecolor布尔值)这将强制下一行具有与上一行相同的颜色,从而避免matplotlib默认机制,即为每个新打印的元素循环使用颜色贴图

  • 选择绘图方法matplotlib_method字符串将用于元素。如果未指定,则将选择最基本的plot方法。

    来自MACDHisto的示例。此处histo线绘制为bar,这是行业事实上的标准。在MACDHisto的定义中可以找到以下定义:

    py lines = ('histo',) plotlines = dict(histo=dict(_method='bar', alpha=0.50, width=1.0))

    alphawidthmatplotlib的选项

  • _fill_gt/_fill_lt

    允许在给定线和以下线之间填充:

    • 另一行

    • 数值

    参数是由 2 个元素组成的 iterable,其中:

    • 1st参数是字符串(参考线名称)或数值

      填充将在自身值与行值或数值之间进行

    • 2nd参数为:

      • 具有颜色名称(matplotlib兼容)或十六进制规范的字符串(参见matloplit示例)

      • 一个 iterable,其中 1st元素是颜色的字符串/十六进制值,第二个元素是指定 alpha 透明度的数值(默认值:0.20在打印方案中由fillalpha控制)

    示例:

    ```py

    Fill for myline when above other_line with colour red

    plotlines = dict( myline=dict(_fill_gt('other_line', 'red')) )

    Fill for myline when above 50 with colour red

    plotlines = dict( myline=dict(_fill_gt(50, 'red)) )

    Fill for myline when above other_line with colour red and 50%

    transparency (1.0 means "no transparency")

    plotlines = dict( myline=dict(_fill_gt('other_line', ('red', 0.50))) ) ```

将选项传递到未知行

  • Ue 名称_X,其中X表示零基索引中的数字。这意味着选项用于第X

来自OscillatorMixIn的用例:

plotlines = dict(_0=dict(_name='osc')) 

顾名思义,这是一个mixin类,用于多重继承方案(特别是在右侧)。mixin不知道 1st行的实际名称(索引以零为基础),而另一个指标将是多重继承混合的一部分。

这就是为什么将选项指定为:_0。子类化完成后,结果类的 1st行将在绘图中显示名称osc

一些绘图线示例

BuySell观察者具有以下特征:

plotlines = dict(
    buy=dict(marker='^', markersize=8.0, color='lime', fillstyle='full'),
    sell=dict(marker='v', markersize=8.0, color='red', fillstyle='full')
) 

buysell行具有直接传递给matplotlib的选项,用于定义标记标记化颜色填充样式。所有这些选项都在matplotlib中定义

Trades观察者具有以下特征:

...
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')
) 

这里,通过使用_name将行的名称从例如pnlplus重新定义为Positive。其余选项用于matplotlib

DrawDown观察员:

lines = ('drawdown', 'maxdrawdown',)

...

plotlines = dict(maxdrawdown=dict(_plotskip='True',)) 

这个定义了两行,让最终用户不仅可以访问当前drawdown的值,还可以访问其最大值(maxdrawdown。但由于_plotskip=True的原因,后者未绘制

BollingerBands指示器:

plotlines = dict(
    mid=dict(ls='--'),
    top=dict(_samecolor=True),
    bot=dict(_samecolor=True),
) 

此处mid线将具有虚线样式,topbot线将具有与mid线相同的颜色。

Stochastic(在_StochasticBase中定义并继承):

lines = ('percK', 'percD',)
...
plotlines = dict(percD=dict(_name='%D', ls='--'),
                 percK=dict(_name='%K')) 

较慢的线percD虚线样式绘制。并且这些行的名称被更改为包含花式的%符号(%K%D,这些符号不能用于Python中的名称定义中

控制标绘的方法

在处理指标观察者时,支持以下方法进一步控制标绘:

  • _plotlabel(self)

    它应该返回一个符合标签的事物列表,该列表将放在指示器观察者名称后的括号中

    RSI指示器的一个示例:

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

    可以看出,此方法返回:

    • 一个int,表示为RSI配置的时段,如果默认移动平均值已更改,则表示特定类别

      在后台,两者都将转换为字符串。在的情况下,将努力只打印类的名称,而不是完整的module.name组合。

  • _plotinit(self)

    在绘图开始时调用,以执行指示器可能需要的任何特定初始化。同样,来自RSI的示例:

    py def _plotinit(self): self.plotinfo.plotyhlines = [self.p.upperband, self.p.lowerband]

    在这里,代码为plotyhlines指定一个值,以在特定y值处绘制水平线(hlines部分)。

    参数upperbandlowerband的值用于此目的,由于最终用户可以更改参数,因此无法事先知道

系统范围打印选项

首先是大脑内plot签名

def plot(self, plotter=None, numfigs=1, iplot=True, **kwargs): 

这意味着:

  • plotter:一个对象/类,包含控制系统范围打印的选项作为属性

    如果传递了None,将实例化一个默认的PlotScheme对象(见下文)

  • numfigs:在多少独立图表中,一个情节必须被打破

    有时一张图表包含太多的条形图,如果放在一个单独的图形中,将很难阅读。这会根据需要将其分解为多个部分

  • iplot:如果在 Jupyter 笔记本中运行,则自动内联打印

  • **kwargs:参数用于更改plotter的属性值,如果没有传递plotter,则更改创建的默认PlotScheme对象的属性值。

绘图方案

此对象包含控制系统范围打印的所有选项。这些选项记录在代码中:

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类定义了一个可以在子类中重写的方法,该子类返回要使用的下一种颜色:

def color(self, idx) 

其中idx是绘制在单个子图上的线的当前索引。例如,MACD绘制了 3 条线,因此idx变量将仅具有以下值:012。下一张图表(可能是另一个指示器)将在0处再次显示计数。

反向交易者使用的默认配色方案(如上所示)为Tableau 10 Color Palette,索引修改为:

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

通过重写color方法或将lcolors变量传递给plot(或在PlotScheme的子类中),可以完全改变颜色。

源代码还包含对Tableau 10 LightTableau 20调色板的定义。


我们一直在努力

apachecn/AiLearning

【布客】中文翻译组