I was wondering if there was a particular reason why calculateValues() in many studies appears to be looping over the entire data series on every bar close (or even worse, update), e.g. in Bollinger Bands...
...I realize there are checks to see if a given bar is "complete", but logic like the above seems to be relatively inefficient (i.e. at least check first if the end of the series is complete and potentially avoid looping altogether once the initial calculations have been generated).
Thoughts?
Java:
@Override
protected synchronized void calculateValues(DataContext ctx)
{
int topPeriod = getSettings().getInteger(TOP_PERIOD);
int bottomPeriod = getSettings().getInteger(BOTTOM_PERIOD);
int topShift = getSettings().getInteger(TOP_SHIFT);
int bottomShift = getSettings().getInteger(BOTTOM_SHIFT);
double topStd = getSettings().getDouble(TOP_STD);
double bottomStd = getSettings().getDouble(BOTTOM_STD);
Object input = getSettings().getInput(Inputs.INPUT);
var series = ctx.getDataSeries();
int latest = series.size() - 1;
var method = getSettings().getMAMethod(Inputs.METHOD, Enums.MAMethod.SMA);
int end = latest;
if (topShift < 0) end -= topShift; // calculate future values
// Calculate top and middle lines
boolean updates = getSettings().isBarUpdates();
for (int i = topPeriod; i <= end; i++) { // <- HERE
if (series.isComplete(i, Values.TOP)) continue;
if (!updates && !series.isBarComplete(i)) continue;
Double stdDev = series.std(i, topPeriod, input);
Double ma = series.ma(method, i, topPeriod, input);
if (stdDev == null || ma == null) {
continue;
}
series.setDouble(i + topShift, Values.MIDDLE, ma);
series.setDouble(i + topShift, Values.TOP, ma + stdDev * topStd);
series.setComplete(i, Values.TOP, i >= 0 && i < latest); // latest bar is not complete
checkTopBand(ctx, i);
}
// Calculate bottom line
end = latest;
if (bottomShift < 0) end -= bottomShift; // calculate future values
for (int i = bottomPeriod; i <= end; i++) { // <- HERE
if (series.isComplete(i, Values.BOTTOM)) continue;
if (!updates && !series.isBarComplete(i)) continue;
Double stdDev = series.std(i, bottomPeriod, input);
Double ma = series.ma(method, i, bottomPeriod, input);
if (stdDev == null || ma == null) continue;
series.setDouble(i + bottomShift, Values.BOTTOM, ma - stdDev * bottomStd);
series.setComplete(i, Values.BOTTOM, i >= 0 && i < latest); // latest bar is not complete
checkBottomBand(ctx, i);
}
}
Thoughts?