For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

Multi-Data Indicator implementation help.

• Hi there,

As I've slowly been piecing together my bt set-up, the time has come to try get some indicators working. I'm having some trouble understanding how the indicator ecosystem works, and just how I can achieve what I would like.

Here are the requirements (for each asset):

1. calculate the change each day
2. compute an average of this change over 'x' periods
3. compute a standard deviation of this change of 'x' periods
4. compute the square root of 'x' periods
5. calculate (#4*(#2/#3))
Optional: 6) calculate SMA of #5
6. Plot #5 (and #6) (I know that I don't have a plotlines() just yet, trying to get it at least working before dealing with that)

Here is the current implementation of my code, note, it does not work. I'm a fairly new programmer, so perhaps something glaringly obvious is wrong. My main suspect is that it may have something to do with the fact I am doing computations for each asset in self.datas (in next()), but only having one lines output? Also, I realise I'm doing 'nothing' with the dict() entries, I was trying that as a way to handle the problem, but it yielded the same error as the current iteration.

``````import backtrader as bt
import numpy as np

class MQN(bt.Indicator):
lines = ('mqn', 'ma')

params = (
('len', 35),
('ma_len', 20),
)

def __init__(self):
self.changes = dict()
self.avg_chng = dict()

def next(self):
for i, d in enumerate(self.datas):
cur = d.close
prev = d.close[-1]

change = cur - prev
self.changes[d] = change

average = bt.indicators.MovingAverageSimple(change, period=self.p.len)
self.avg_chng[d] = average

stdev = bt.indicators.StandardDeviation(change, period=self.p.len)
sqroot = np.sqrt(self.p.len)

mqn = sqroot * (average/stdev)
ma = bt.indicators.MovingAverageSimple(mqn, period=self.p.ma_len)

self.lines.mqn = mqn
self.lines.ma = ma
``````

If someone could help me understand what can be done in the bt.indicator ecosystem (as I have other indicators that do similar things to this), and help me to achieve the indicator outcome, that would be simply amazing!

• I've also now tried this approach, still hanging an error.

``````import backtrader as bt

class MQN2(bt.Indicator):
lines = ('mqn', 'ma')

params = (
('len', 35),
('ma_len', 20),
)

def __init__(self):
self.cur = self.data.close
self.prev = self.data.close[-1]
self.change = self.cur - self.prev
self.avg_chng = bt.indicators.MovingAverageSimple(self.change, period=self.p.len)
self.stdev = bt.indicators.StandardDeviation(self.change, period=self.p.len)
self.sqroot = self.p.len ** 0.5

def next(self):

mqn = self.sqroot * (self.avg_chng/self.stdev)
# ma = bt.indicators.MovingAverageSimple(mqn, period=self.p.ma_len)

self.lines.mqn = mqn
# self.lines.ma = ma``````

• Yet another iteration. Getting closer I feel, but this one hangs on:

``````self.l.mqn = mqn
``````

with:

``````TypeError: must be real number, not LinesOperation
``````
``````import backtrader as bt
import numpy as np

class MQN3(bt.Indicator):
lines = ('mqn',)

params = (
('len', 35),
('ma_len', 20),
)

def __init__(self):

def next(self):
d = self.data.get(size=self.p.len)

print(len(d))
print(d)

avg_chng = bt.ind.SMA(d, period=self.p.len)
stdev = bt.ind.StdDev(d, period=self.p.len)
sqroot = (self.p.len ** 0.5)

print("{} {} {}".format(avg_chng, stdev, sqroot))

mqn = (sqroot * (avg_chng/stdev))
print(mqn)
# ma = bt.indicators.MovingAverageSimple(mqn, period=self.p.ma_len)

self.l.mqn = mqn
# self.lines.ma = ma
``````

'd' is collecting the most recent 35 closes, as it should.
'sqroot' is giving the correct multiplier.
With the print string, I can't see the values for 'avg_chng' and 'stdev', just the objects themselves. So potentially this is where i'm getting something wrong?

I'm also unsure of how to turn 'd' into a list of 'changes' (d[i] - d[i-1]) and pass this to SMA and StdDev.

Can anyone help me understand where i'm going wrong? :)

• Managed to get something running!

``````import backtrader as bt
import numpy as np

class MQN4(bt.Indicator):
lines = ('mqn', 'ma',)

params = (
('len', 35),
('ma_len', 20),
)

def __init__(self):

def next(self):
d = self.data.get(size=self.p.len+1)

changes = []

for i in range(1, len(d)):
changes.append(d[-i] - d[-i-1])

avg_chng = sum(changes) / self.p.len
stdev = np.std(changes)
sqroot = (self.p.len ** 0.5)

mqn = sqroot * (avg_chng/stdev)

self.l.mqn = mqn

# ma = bt.ind.SMA(self.l.mqn, period=self.p.ma_len)
# self.l.ma = ma
``````

This gives me what I would like! For one asset. How could I modify (or utilise!) 'lines' so that I can have a separate output on each asset? i.e. N separately computed indicators for N assets.

Furthermore, is there any way to remove the "gap" at the beginning, i.e. remove the buffering of the indicator? Is it possible to feed through (t-x) data but begin the backtest at (t)? Or any other way?

• Sorry for the relentless stream of replies, haha. I have solved the problem, with multiple data (assets).

``````import backtrader as bt
import numpy as np

class MQN(bt.Indicator):
lines = ('mqn', 'ma',)

params = (
('len', 35),
('ma_len', 20),
)

def __init__(self):

def next(self):
for i, d in enumerate(self.datas):

data = d.get(size=self.p.len+1)
changes = []

for i in range(1, len(data)):
changes.append(data[-i] - data[-i-1])

if len(changes) == self.p.len:
avg_chng = np.average(changes)
stdev = np.std(changes)
sqroot = np.sqrt(self.p.len)

mqn = sqroot * (avg_chng/stdev)

self.l.mqn = mqn

ma = self.l.mqn.get(size=self.p.ma_len)
self.l.ma = np.average(ma)
``````

Calling this in my strategy, and passing in the specified data (asset) does the trick and plots each separate indicator, with its respective SMA.

I hope my documentation of progress here has/will be useful to some.

My final questions are:

1. Is the above code the most efficient/cleanest/best way to go about handling the operations I'm doing? As mentioned earlier, I have several other indicators, similar in nature to this one, so I would like to make sure I really nail the right way before making my way through programming all of them.

2. Is there a way/hack to eliminate the "instantiation lag" that occurs with indicators in BT? Is it possible to pass in data from before the start of the backtest so that any indicators are already fully instantiated at t=0?

• ``````def __init__(self):
``````

Before I read the messages. See please the article below and why that isn't a good idea.

• Before I read the messages. See please the article below and why that isn't a good idea.

Will do, thank you!

If you could respond to the questions as well, that would be amazing! :)

1. Is the above code the most efficient/cleanest/best way to go about handling the operations I'm doing?

The fact is that backtrader allows you to do it in a declarative way or in an iterative way (and to mix both). There seems to a fixation out thee in many cases in using `numpy` (imported as `np`) for whatever reason which I fail to understand, even if it is meant to only calculate a single value. But if it suits you, there is no reason to do it otherwise.

1. Is there a way/hack to eliminate the "instantiation lag" that occurs with indicators in BT? Is it possible to pass in data from before the start of the backtest so that any indicators are already fully instantiated at t=0?

There is NO lag. Your reasoning and understanding is wrong. If you want a `20-period` moving average you need `20` data points to calculate it. Full stop. If you want your indicators at YOUR DEFINED `t=0` to be available, work with a data set which has an earlier start datetime.

});