指标(Indicators)的使用
前言
在框架内,指标可以使用在两个地方
- 策略(Strategies)内
- 另外一个指标(Indicators)内
指标(Indicators)的操作
- 指标总是在策略的__init__内实例化
- 指标的值或者其派生值在next()内使用和检查
一个重要的原理需要考虑
在__init__内声明的任何指标(或者派生值)将在被next调用之前预先计算
让我们来看操作模式的差异
__init__
vs next
工作原理如下:
任何涉及lines objects的操作在__init__
内都会生成另一个lines objects
任何涉及lines objects的操作在next()
内都会生成Python类型,如floats ,bools
在__init__内
举一个在__init__内操作的例子
hilo_diff = self.data.high - self.data.low
变量hilo_diff
引用的是一个lines object,在next()调用之前计算,并且可以通过标准数组索引读取,他显然包含的是每个data的high-low的差
他可以被当作简单线或者复杂的线,类似指标的使用,
sma = bt.SimpleMovingAverage(self.data.close)
close_sma_diff = self.data.close - sma
close_sma_diff
也是一个lines object.
使用逻辑运算符:
close_over_sma = self.data.close > sma
close_over_sma
包含的是一组布尔值
在next()内
举一个在next()内的例子(逻辑操作符)
close_over_sma = self.data.close > self.sma
等效于一个数组(索引从0开始)
close_over_sma = self.data.close[0] > self.sma[0]
在这里close_over_sma
是self.data.close[0] 和 self.sma[0]通过[0]索引得到的两个浮点数,经过逻辑计算的结果,一个布尔值
__init__
vs 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
。这同样适用于其他操作符,如Or和If。很明显,__init__内的“声明性”方法将next()(实际策略发生的地方)的体量保持在最低限度。(别忘了还有一个速度因素)
注释: 当逻辑变得非常复杂并且涉及多个操作时,将其封装在指示器中通常要好得多。
其他注释:
在上面的例子中,与其他平台相比,backtrader简化了两件事:
声明的指示器既不需要父参数(如策略的生成也不是任何形式的“注册”方法/函数然后被调用)。 策略会跳过指标和任何lines object的计算(如sma-ema
)
ExponentialMovingAverage没有数据就可以实例化,这是故意的,如果没有传递数据(策略生成期间),则后天会自动传递父数据的第一个
指标(Indicators)的绘图
首先:
如果调用cerebro.plot() 指标会自动绘制,期中:运算得到的lines object不会被绘制(如: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参数为该指示符所包含的line object指定名称
其次:
在指示器的开发过程中,可以添加plotinfo声明
他可以是两个元素的元组,字典或者有序字典.比如:
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 (default: True) | 是否绘制该指标 |
subplot (default: True) | 是否在子窗口绘制该指标。对于像移动平均线这样的指标,默认值改为False |
plotname (default: ‘’) | 设置要在绘图中显示的绘图名称。空值表示指标的规范名称(class.name)被使用。这有一些限制,因为Python关键字不能被使用,如算术运算符。 |
plotabove (default: False) | 指标通常绘制在它们所操作的数据的下方(带有subplot=True的指标)。将其设置为True将使指示器绘制在数据上方。 |
plotlinelabels (default: False) | 意思是“指标”上的“指标”。如果计算RSI的SimpleMovingAverage,该图通常会显示相应绘制线的名称“SimpleMovingAverage”。这是“指标”的名称,而不是实际绘制的线(line)的名称。这种默认行为是有意义的,因为用户通常希望看到使用RSI创建了一个SimpleMovingAverage。如果将该值设置为True,则将使用SimpleMovingAverage中的实际线(line)的名称。 |
plotymargin (default: 0.0) | 指示器顶部和底部的空白量(0.15 - 15%)。有时,matplotlib图过于靠近轴的顶部/底部,可能需要一个边距 |
plotyticks (default: []) | 用于控制绘制的y刻度刻度.如果传递空列表,则会自动计算“y刻度”。对于没有要求的,将其设置为众所周知的行业标准是有意义的,例如:[20.0,50.0,80.0].一些指标提供了诸如upperband和lowerband之类的参数,这些参数实际上用于操纵y刻度 |
plothlines (default: []) | 用于控制沿指示轴绘制水平线。 |
plotyhlines (default: []) | 用于同时控制plotyticks and plothlines |
plotforce (default: False) | 如果出于某种理由,你认为一个指标应该绘制,但它没有绘制,那么将此设置为True作为最后的手段。 |