Python 的隐藏力量(3)
原文: https://www.backtrader.com/blog/posts/2016-11-25-hidden-powers-3/hidden-powers/
最后,但并非最不重要的一点是,在本系列中,关于如何在backtrader中使用 Python 的隐藏功能,一些神奇的变量是如何显示的。
self.datas
和其他人来自哪里?
通常的可疑类(或其子类)Strategy
、Indicator
、Analyzer
、Observer
具有自动神奇地定义的属性,例如包含数据提要的数组。
数据馈送被添加到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
调用,因此不会直接要求基类进行初始化 -
mysig
的定义引用了self.data
,可能与cerebro
中增加的YahooFinanceData
实例有关的确如此!
实际上还有其他一些属性,在示例中没有看到。例如:
-
self.datas
:包含添加到cerebro
的所有数据源的数组 -
self.dataX
:其中X
是一个数字,反映数据添加到大脑的顺序(data0
将是上面添加的数据) -
self.data
:指向self.data0
。因为大多数示例和策略只针对单个数据,所以为了方便起见,只需使用 ahortcut
更多信息可在文档中找到:
这些属性是如何创建的?
在本系列的第 2篇文章中,可以看到类创建机制和实例创建机制被截获。后者是用来做这件事的。
-
cerebro
通过adstrategy
接收类 -
它将在需要时实例化它,并将自身添加为属性
-
策略的
new
类方法在Strategy
实例的创建过程中被拦截,并检查cerebro
中有哪些数据源它确实创建了上面提到的数组和别名
该机制应用于backtrader生态系统中的许多其他对象,以简化最终用户的操作。像这样的:
-
例如,不需要不断创建包含名为
datas
的参数的函数原型,也不需要将其分配给self.datas
因为它是在后台自动完成的
这种拦截的另一个例子
让我们定义一个获胜指标,并将其添加到获胜策略中。我们将重新包装关闭 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
但似乎什么地方也做不到。如本系列的 1st文章所示,该操作生成一个对象,该对象被分配给self.lines.signal
,发生如下情况:
-
此对象还拦截其创建过程
-
它扫描堆栈以了解正在创建的上下文,在本例中是在
MyIndicators
实例中 -
在初始化完成后,加入
MyIndicator
的内部结构 -
稍后计算
MyIndicator
时,它将依次计算self.lines.signal
引用的对象内的操作
好,但是谁来计算MyIndicator
遵循完全相同的过程:
-
MyIndicator
在创建过程中扫描堆栈并找到MyStrategy
-
并添加到
MyStrategy
的结构中 -
就在调用
next
之前,MyIndicator
被要求重新计算自身,这反过来又告诉self.lines.signal
重新计算自身
该过程可以有多个间接层。
对用户来说最好的东西是:
-
创建某些内容时,无需添加类似于
register_operation
的调用 -
无需手动触发计算
总结
本系列的最后一篇文章展示了如何使用类/实例创建截取使最终用户的生活更轻松的另一个示例:
-
从需要的生态系统中添加对象并创建别名
-
自动注册类和触发计算