使用指标

指标可以在平台的两个地方使用:

  • 内部策略
  • 其他指标内部

指标可以在两个地方使用:

  1. 指标总是策略的__init__中实例化
  2. 在策略的next中使用/检查 指标值(或其派生值)

有一个重要的原则需要考虑:

  • 在调用期间声明的任何Indicator(或其派生的值)__init__ 都将在next调用之前预先计算。

让我们来看看操作模式的差异。

__init__对比next

事情如下:

  • 任何涉及线对象的操作都会生成另一个线对象__init__
  • 任何涉及对象的操作都会产生常规的 Python 类型,如浮点数和布尔值。next

__init__中的操作示例:

hilo_diff = self.data.high - self.data.low

该变量hilo_diff保存对lines对象的引用,该对象在调用之前预先计算next,可以使用标准数组表示法访问[]

它显然包含数据馈送的每个条形图的高点和低点之间的差异。

这也适用于混合简单的线条(如 self.data 数据馈送中的那些)和复杂的线条如指标:

sma = bt.SimpleMovingAverage(self.data.close)
close_sma_diff = self.data.close - sma

现在close_sma_diff再次包含一个线对象。

使用逻辑运算符:

close_over_sma = self.data.close > sma

现在生成的lines对象将包含一个布尔数组。

在next中的操作示例(逻辑运算符):

close_over_sma = self.data.close > self.sma

在这种情况下close_over_sma,产生一个布尔值,它是比较两个浮点值的结果,[0]运算符返回的值应用于self.data.closeself.sma

__init__与_next比较

逻辑简化(以及易用性)是关键。 计算和大部分相关逻辑可以在 __init__ 期间声明,在 next 期间将实际操作逻辑保持在最低限度。

实际上还有一个附带的好处:速度(由于开头解释的预先计算)

__init__期间生成买入信号 的完整示例:

class MyStrategy(bt.Strategy):

    def __init__(self):

        sma1 = btind.SimpleMovingAverage(self.data)
        ema1 = btind.ExponentialMovingAverage()

        close_over_sma = self.data.close > sma1
        close_over_ema = self.data.close > ema1
        sma_ema_diff = sma1 - ema1

        buy_sig = bt.And(close_over_sma, close_over_ema, sma_ema_diff > 0)

    def next(self):

        if buy_sig:
            self.buy()

Python 的and操作符不能被覆盖,迫使平台定义自己的And. 这同样适用于其他结构,如 OrIf。

很明显,__init__ 期间的“声明式”方法将 next(实际策略工作发生的地方)的膨胀降至最低。

(别忘了还有一个加速因素)

当逻辑变得非常复杂并涉及多个操作时,通常将其封装在 Indicator.

一些笔记

backtrader在上面的示例中,与其他平台相比,有两点被简化 :

  • 声明Indicators的既没有获得参数(比如创建它们的策略,也没有调用任何类型的“注册”方法/函数。尽管如此,该策略仍会计算由于操作而生成的 Indicators任何对象(例如sma - ema
  • ExponentialMovingAverage正在实例化而没有self.data这是故意的。如果没有data传递,则父级的一个数据 (在这种情况下是正在创建的策略)将在后台自动传递

指标绘图

首先也是最重要的:

  • 声明Indicators自动绘制(如果调用 cerebro.plot)
  • 操作中的线对象不会被绘制(如close_over_sma = self.data.close > self.sma)如果需要,有一个辅助LinePlotterIndicator工具可以使用以下方法绘制此类操作:
close_over_sma = self.data.close > self.sma
LinePlotterIndicator(close_over_sma, name='Close_over_SMA')
  • name参数为该指标持有的单行命名。

控制绘图

在开发过程中可以添加Indicator一个声明。plotinfo它可以是元组的元组(2 个元素)、adict或 an OrderedDict。看起来像:

class MyIndicator(bt.Indicator):

    ....
    plotinfo = dict(subplot=False)
    ....

稍后可以按如下方式访问(和设置)该值(如果需要):

myind = MyIndicator(self.data, someparam=value)
myind.plotinfo.subplot = True

该值甚至可以在实例化期间设置:

myind = MyIndicator(self.data, someparams=value, subplot=True)

subplot=True传递给指标的(在幕后)实例化成员变量plotinfo

提供以下plotinfo参数来控制绘图行为:

  • plot(默认True)是否要绘制指标
  • subplot(默认True)是否在不同的窗口中绘制指标。对于移动平均线等指标,默认更改为False
  • plotname(默认'')设置要在绘图上显示的绘图名称。空值表示class.__name__将使用指标 ( ) 的规范名称。这有一些限制,因为 Python 标识符不能使用例如算术运算符。

    像 DI+ 这样的指标将声明如下:

class DIPlus(bt.Indicator):
    plotinfo=dict(plotname='DI+')
  • 让剧情“更精彩”
  • plotabove(默认False)指标通常绘制subplot=True在它们所操作的数据下方(带有 的)。将此设置为True将使指标绘制在数据上方。
  • plotlinelabels(默认False)用于“指标”上的“指标”。如果计算 RSI 的 SimpleMovingAverage,绘图通常会为相应的绘制线显示名称“SimpleMovingAverage”。这是“指标”的名称,而不是实际绘制的线。

    这种默认行为是有意义的,因为用户通常希望看到使用 RSI 创建了 SimpleMovingAverage。

    如果该值设置为TrueSimpleMovingAverage 内的行的实际名称,则将被使用。

  • plotymargin(默认0.0)在指标顶部和底部留下的保证金量 ( 0.15 -> 15%)。有时,matplotlib绘图离轴的顶部/底部太远,可能希望有一个边距
  • plotyticks(默认[])用于控制绘制的 y 刻度刻度

    如果传递了一个空列表,则会自动计算“y ticks”。对于像随机指标这样的东西,将其设置为众所周知的行业标准可能是有意义的,例如:[20.0, 50.0, 80.0]

    一些指标提供参数,例如upperbandlowerband实际用于操纵 y 刻度

  • plothlines(默认[])用于控制沿指标轴绘制水平线。

    如果传递一个空列表,则不会绘制水平线。

    对于像随机指标这样的东西,为众所周知的行业标准画线可能是有意义的,例如:[20.0, 80.0]

    一些指标提供参数,例如upperbandlowerband实际用于操纵水平线

  • plotyhlines(默认[])用于使用单个参数同时控制 plotyticks 和 plothlines。
  • plotforce(默认False)如果由于某种原因您认为某个指标应该在绘图而它没有在绘图……将其设置True为最后的手段。