In __init__
Operations like self.x = (self.data.high + self.data.low) / 2.0 generate a lazily evaluated lines object.
Even this generates that: self.y = self.data.close > self.data.open
In next
Here the [] operator is used to access the values provided by lines objects like the generated self.x or self.y or standard lines like self.data.high
if self.data.close[0] > self.data.open[0]:
do_something()
Thanks to operator overloading the following is equivalent also in next
if self.data.close > self.data.open:
do_something()
But unlike in __init__, this comparison generates a bool.
One can generate a complete indicator just by using operations and logic in __init__. See for example an old friend of everybody like MACD (removing documentation and plotting preparation boilerplate)
class MACD(bt.Indicator):
lines = ('macd', 'signal',)
params = (
('period_me1', 12),
('period_me2', 26), ('period_signal', 9),
('movav', MovAv.Exponential),
)
def __init__(self):
super(MACD, self).__init__()
me1 = self.p.movav(self.data, period=self.p.period_me1)
me2 = self.p.movav(self.data, period=self.p.period_me2)
self.lines.macd = me1 - me2
self.lines.signal = self.p.movav(self.lines.macd, period=self.p.period_signal)
No need to use scalar operations/logic in next. Everything is defined in terms of lines objects.
Some indicators may need next. Some help from things defined in __init__ can be used. For example the ZeroLagIndicator
class ZeroLagIndicator(MovingAverageBase):
alias = ('ZLIndicator', 'ZLInd', 'EC', 'ErrorCorrecting',)
lines = ('ec',)
params = (
('gainlimit', 50),
('_movav', MovAv.EMA),
)
def __init__(self):
self.ema = MovAv.EMA(period=self.p.period)
self.limits = [-self.p.gainlimit, self.p.gainlimit + 1]
# To make mixins work - super at the end for cooperative inheritance
super(ZeroLagIndicator, self).__init__()
def next(self):
leasterror = MAXINT # 1000000 in original code
bestec = ema = self.ema[0] # seed value 1st time for ec
price = self.data[0]
ec1 = self.lines.ec[-1]
alpha, alpha1 = self.ema.alpha, self.ema.alpha1
for value1 in range(*self.limits):
gain = value1 / 10
ec = alpha * (ema + gain * (price - ec1)) + alpha1 * ec1
error = abs(price - ec)
if error < leasterror:
leasterror = error
bestec = ec
self.lines.ec[0] = bestec
Here the base ema for the calculations is defined in __init__ but the core of the operations which is a loop over several values is best done in next.