在最近的Canonical vs Non-Canonical 帖子中 MFI ,开发了(aka MoneyFlowIndicator)。
尽管它是以规范的方式开发的,但它仍然提供了一些改进和成为通用的空间。
让我们关注实现的第一lines,即创建典型价格的那些
class MFI_Canonical(bt.Indicator):
lines = ('mfi',)
params = dict(period=14)
def __init__(self):
tprice = (self.data.close + self.data.low + self.data.high) / 3.0
mfraw = tprice * self.data.volume
...
典型的实例化如下所示
class MyMFIStrategy(bt.Strategy):
def __init__(self):
mfi = bt.MFI_Canonical(self.data)
这里的问题应该是显而易见的:“人们需要一个指针的输入,lowhigh其中的特征close和volume组件(又名*lines在backtrader生态系统中)”*
当然,可能的情况是,人们希望从不同的数据源(lines来自data feeds或来自其他指针lines)创建一MoneyFlowIndicator个使用组件,就像想要赋予close更多的权重一样简单,而不必开发一个特定的指针。考虑到行业标准OHLCV的字段排序,多个输入,额外的权重,close实例化可能看起来像这样
class MyMFIStrategy2(bt.Strategy):
def __init__(self):
wclose = self.data.close * 5.0
mfi = bt.MFI_Canonical(self.data.high, self.data.low,
wclose, self.data.volume)
或者因为用户以前使用ta-lib 过并幻想过多输入样式。
支持多种输入
backtrader 尝试尽可能的pythonic,self.datas 并且可以查找包含系统中 data feeds 清单的数字(并且自动神奇地提供给您的策略)的长度。让我们用它来区分调用方想要什么,并正确计算 tprice 和 mfraw
class MFI_MultipleInputs(bt.Indicator):
lines = ('mfi',)
params = dict(period=14)
def __init__(self):
if len(self.datas) == 1:
# 1 data feed passed, must have components
tprice = (self.data.close + self.data.low + self.data.high) / 3.0
mfraw = tprice * self.data.volume
else:
# if more than 1 data feed, individual components in OHLCV order
tprice = (self.data0 + self.data1 + self.data2) / 3.0
mfraw = tprice * self.data3
# No changes with regards to previous implementation
flowpos = bt.ind.SumN(mfraw * (tprice > tprice(-1)), period=self.p.period)
flowneg = bt.ind.SumN(mfraw * (tprice < tprice(-1)), period=self.p.period)
mfiratio = bt.ind.DivByZero(flowpos, flowneg, zero=100.0)
self.l.mfi = 100.0 - 100.0 / (1.0 + mfiratio)
注意
请注意各个组件的参考方式(self.dataX 如 self.data0、 self.data1)
这与使用self.datas[x]相同,如 self.datas[0] ...
让我们以图形方式看到,此指针产生的结果与规范指针相同,当多个输入对应于 data feed的原始分量时,产生相同的结果。为此,它将在策略中运行,如下所示
class MyMFIStrategy2(bt.Strategy):
def __init__(self):
MFI_Canonical(self.data)
MFI_MultipleInputs(self.data, plotname='MFI Single Input')
MFI_MultipleInputs(self.data.high,
self.data.low,
self.data.close,
self.data.volume,
plotname='MFI Multiple Inputs')
无需检查每个值,从图片中可以明显看出,三者的结果相同。
让我们最终看看如果把更多的权重放在上面close会发生什么。让我们这样运行。
class MyMFIStrategy2(bt.Strategy):
def __init__(self):
MFI_MultipleInputs(self.data)
MFI_MultipleInputs(self.data.high,
self.data.low,
self.data.close * 5.0,
self.data.volume,
plotname='MFI Close * 5.0')
这是否有意义留给读者,但人们可以清楚地看到,增加重量close 已经改变了模式。
结论
通过简单地使用pythoniclen,可以将使用具有多个组件(和固定名称)的 data feed 的指针转换为接受多个通用输入的指针。