使用指标
指示器可在平台的两个位置使用:
-
内部战略
-
内部其他指标
行动中的指标
-
指标总是在策略的
__init__
期间实例化 -
在
next
期间使用/检查指标值(或其衍生值)
有一个重要的公理需要考虑:
- 在
__init__
期间声明的任何Indicator
(或其派生值)将在调用next
之前进行预计算。
让我们来看看不同的操作模式。
__init__
vsnext
事情是这样的:
-
在
__init__
期间涉及行对象的任何操作都会生成另一个行对象 -
在
next
期间,任何涉及行对象的操作都会生成常规 Python 类型,如 float 和 bools。
在__init__
期间
__init__
期间的操作示例:
hilo_diff = self.data.high - self.data.low
变量hilo_diff
保存对行对象的引用,该对象在调用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
现在生成的行对象将包含一个布尔数组。
在next
期间
操作示例(逻辑运算符):
close_over_sma = self.data.close > self.sma
使用等效数组(基于索引 0 的表示法):
close_over_sma = self.data.close[0] > self.sma[0]
在这种情况下,close_over_sma
产生一个布尔值,它是比较两个浮点值的结果,[0]
运算符返回的值应用于self.data.close
和self.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
。这同样适用于其他构造,如Or
和If
显然,在__init__
期间的“声明式”方法将next
(实际策略工作发生的地方)的膨胀保持在最低限度。
(别忘了还有一个加速因素)
笔记
当逻辑变得非常复杂并涉及多个操作时,通常最好将其封装在Indicator
中。
一些注释
在上述示例中,与其他平台相比,backtrader
中简化了两件事:
-
声明的
Indicators
既没有得到父参数(如创建它们的策略),也没有调用任何类型的“寄存器”方法/函数。尽管如此,该策略仍会触发对
Indicators
和任何行对象(如sma - ema
等)的计算 -
ExponentialMovingAverage
正在实例化,没有self.data
这是故意的。如果没有通过
data
,则父(本例中为正在创建的策略)的 1st数据将在后台自动传递
指示标绘
首先,也是最重要的:
-
已声明的
Indicators
自动绘制(如果调用了脑波图) -
操作中的行对象不会被打印(如
close_over_sma = self.data.close > self.sma
)有一个辅助
LinePlotterIndicator
,如果需要,可通过以下方法绘制此类操作:py close_over_sma = self.data.close > self.sma LinePlotterIndicator(close_over_sma, name='Close_over_SMA')
name
参数为该指示器持有的单行命名。
控制标绘
在Indicator
的开发过程中,可以添加plotinfo
声明。它可以是元组的元组(2 个元素)、一个dict
或一个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+的指标将声明如下:
py class DIPlus(bt.Indicator): plotinfo=dict(plotname='DI+')
让情节“更美好”
-
plotabove
(默认为False
)指标通常在其操作数据下方绘制(带有
subplot=True
的指标)。将此设置为True
将使指示器标绘在数据上方。 -
plotlinelabels
(默认为False
)用于“指标”上的“指标”。如果计算 RSI 的 SimpleMovingAverage,则绘图通常会显示相应绘图线的名称“SimpleMovingAverage”。这是“指示器”的名称,而不是正在绘制的实际线。
这种默认行为是有意义的,因为用户通常希望看到 SimpleMovingAverage 是使用 RSI 创建的。
如果该值设置为
True
,则将使用 SimpleMovingAverage 内的行的实际名称。 -
plotymargin
(默认为0.0
)指标顶部和底部留下的保证金金额(
0.15
->15%)。有时matplotlib
图太过靠近轴的顶部/底部,可能需要留一个边距 -
plotyticks
(默认为[]
)用于控制绘制的 y 比例记号
如果传递的是空列表,“y 记号”将自动计算。对于随机变量,将其设置为众所周知的行业标准(如:
[20.0, 50.0, 80.0]
可能是有意义的一些指示器提供了
upperband
和lowerband
等参数,这些参数实际上用于操纵 y 记号 -
plothlines
(默认为[]
)用于控制沿指示器轴绘制水平线。
如果传递空列表,则不会绘制水平线。
对于像随机变量这样的东西,为众所周知的行业标准划一条线可能是有意义的,比如:
[20.0, 80.0]
一些指示器提供了
upperband
和lowerband
等参数,实际用于操纵水平线 -
plotyhlines
(默认为[]
)用于使用单个参数同时控制 PlotyTrack 和 Plothline。
-
plotforce
(默认为False
)如果出于某种原因,您认为某个指示器应该正在绘制,但它没有绘制……将其设置为
True
作为最后手段。