指针可以在平台的两个地方使用:
内部策略
其他指针内部
指针在行动
指针总是在策略中的
__init__期间实例化next使用/检查指针值(或其派生值)
有一个重要的公理需要考虑:
- 在
__init__期间声明的任何Indicator(或其派生值)都将在调用next之前预先计算。
让我们来看看操作模式的差异。
__init__与next
事情如下:
在
__init__期间任何涉及线对象的操作都会生成另一个线对象在
next期间任何涉及行对象的操作都会产生常规的 Python 类型,例如浮点数和布尔值。
在__init__期间
__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
使用等效数组(基于索引 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传递,则父级的第一个数据(在这种情况下是正在创建的策略)将在后台自动传递
指针绘图
首先也是最重要的:
声明的
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 个元素)、 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)是否在不同的窗口中绘制指针。对于移动平均线等指针,默认值更改为
Falseplotname(默认值:'')设置要在绘图上显示的绘图名称。空值意味着将使用指针的规范名称 (
class.__name__)。这有一些限制,因为 Python 标识符不能使用例如算术运算符。像 DI+ 这样的指针将声明如下:
class DIPlus(bt.Indicator): plotinfo=dict(plotname='DI+')让剧情“更精彩”
plotabove(默认值:False)指针通常绘制在他们操作的数据下方(那些
subplot= True)。将此设置为True将使指针绘制在数据上方。plotlinelabels(默认值:False)用于“指针”上的“指针”。如果计算 RSI 的 SimpleMovingAverage,绘图通常会显示相应绘制线的名称“SimpleMovingAverage”。这是“指针”的名称,而不是实际绘制的线。
这种默认行为是有意义的,因为用户通常希望看到使用 RSI 创建了 SimpleMovingAverage。
如果该值设置为
True,则将使用 SimpleMovingAverage中行的实际名称。plotymargin(默认值:0.0)在指针顶部和底部留下的保证金量 (
0.15-> 15%)。有时matplotlib绘图离轴的顶部/底部太远,可能希望留出余量plotyticks(默认值:[])用于控制绘制的 y 刻度刻度
如果传递了一个空列表,则会自动计算“y ticks”。对于像随机指针这样的东西,将其设置为众所周知的行业标准可能是有意义的,例如:
[20.0, 50.0, 80.0]一些指针提供了实际用于操纵 y 刻度的参数,例如
upperband和lowerbandplothlines(默认值:[])用于控制沿指针轴绘制水平线。
如果传递一个空列表,则不会绘制水平线。
对于像随机指针这样的东西,为众所周知的行业标准画线可能是有意义的,例如:
[20.0, 80.0]一些指针提供实际用于操纵水平线的参数,
upperband和lowerbandplotyhlines(默认值:[])用于使用单个参数同时控制 plotyticks 和 plothlines。
plotforce(默认值:False)如果由于某种原因您认为某个指针应该在绘图而它没有在绘图……作为最后的手段,将其设置为
True。