Last,但并非最不重要的一点是,在这个系列中,关于如何在 backtrader 中使用Python的隐藏功能是一些神奇变量是如何出现的。
self.datas其他人从哪里来?
通常的可疑类(或其子类)StrategyIndicator, 、 Analyzer、 Observer 具有自动魔法定义的属性,例如包含 data feeds的数组。
Data Feeds 将添加到实例中cerebro ,如下所示:
from datetime import datetime import backtrader as bt cerebro = bt.Cerebro() data = bt.YahooFinanceData(dataname=my_ticker, fromdate=datetime(2016, 1, 1)) cerebro.adddata(data) ...
当高于简单移动平均线时,我们对示例的close 获胜策略将持续很长时间。我们将使用信号来缩短范例:
class MyStrategy(bt.SignalStrategy):
params = (('period', 30),)
def __init__(self):
mysig = self.data.close > bt.indicators.SMA(period=self.p.period)
self.signal_add(bt.signal.SIGNAL_LONG, mysig)
它被添加到混合中:
cerebro.addstrategy(MyStrategy)
任何读者都会注意到:
-
__init__不带参数,无论是否命名 -
没有
super调用,因此不会直接要求基类运行其 init -
引用的
self.data定义mysig可能与YahooFinanceData添加到cerebro确实如此!
实际上还有其他属性,这些属性在那里,在示例中看不到。例如:
-
self.datas:包含添加到的所有 data feeds 的数组cerebro -
self.dataX:其中X是一个数字,它反映了数据添加到 cerebro 的顺序(data0将是上面添加的数据) -
self.data:指向self.data0。为了方便起见,这只是一个队列,因为大多数示例和策略仅针对单个数据
可以在文档中找到更多内容:
如何创建这些属性?
在本系列的第 2 篇文章中,发现类创建机制和实例创建机制被截获。后者用于运行此操作。
-
cerebro通过以下方式接收类adstrategy -
它将在需要时实例化它,并将自身添加为属性
-
策略
new的类方法在创建Strategy实例期间被截获,并检查哪些 data feeds 在cerebro它确实创建了上面提到的数组和别名
此机制应用于 backtrader 生态系统中的许多其他对象,以便简化最终用户必须运行的操作。因此:
-
例如,无需不断创建包含命名
datas参数的函数原型,也无需将其分配给self.datas因为它是在后台自动神奇地完成的
这种拦截的另一个例子
让我们定义一个获胜指针,并将其添加到获胜策略中。我们将重新包装 close SMA的想法:
class MyIndicator(bt.Indicator):
params = (('period', 30),)
lines = ('signal',)
def __init__(self):
self.lines.signal = self.data - bt.indicators.SMA
现在将其添加到常规策略中:
class MyStrategy(bt.Strategy):
params = (('period', 30),)
def __init__(self):
self.mysig = MyIndicator(period=self.p.period)
def next(self):
if self.mysig:
pass # do something like buy ...
从上面的代码中,显然有一个计算正在进行MyIndicator:
self.lines.signal = self.data - bt.indicators.SMA
但它似乎无处可做。如本系列的第 1 篇文章所示,该操作会生成一个对象,该对象被 self.lines.signal 分配给并发生以下情况:
-
此对象还会截获其创建过程
-
它扫描堆栈以了解正在创建的上下文,在本例中为
MyIndicators -
在初始化完成后,它会将自己添加到
MyIndicator -
稍后在计算时
MyIndicator,它将依次计算由self.lines.signal
不错,但谁计算MyIndicator
遵循完全相同的过程:
-
MyIndicator在创建过程中扫描堆栈并找到MyStrategy -
并将自己添加到结构中
MyStrategy -
在调用之前
next,MyIndicator被要求重新计算自身,这反过来又告诉self.lines.signal重新计算自己
该过程可以具有多层间接寻址。
对用户来说最好的事情:
-
无需像创建某些内容时那样
register_operation添加调用 -
无需手动触发计算
总结
本系列中 last 文章展示了如何使用类/实例创建拦截来简化最终用户生活的另一个示例::
-
从生态系统中添加需要的对象并创建别名
-
自动注册类和触发计算