Last,但并非最不重要的一点是,在这个系列中,关于如何在 backtrader 中使用Python的隐藏功能是一些神奇变量是如何出现的。
self.datas
其他人从哪里来?
通常的可疑类(或其子类)Strategy
Indicator
, 、 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 文章展示了如何使用类/实例创建拦截来简化最终用户生活的另一个示例::
-
从生态系统中添加需要的对象并创建别名
-
自动注册类和触发计算