Code inefficiencies?

Fu510n

Member
Joined
Jan 7, 2025
Posts
15
Likes
10
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...
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);
    }
  }
...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?
 
My thinking is that the loaded data is usually a subset of all available data, sometimes it is only what is visible on the screen. While scrolling back in the past the historical data gets requested and downloaded on demand. I think this is the efficiency the developers are after. Looping through a subset of dowloaded data is not a big deal when it is already in the memory. Some of the studies where such behavior is "harmful" have previously calculated objects stored in additional synchronized arrays and the data loops are skipping unnecessary calculations.
Just a thought.

cheers.
 
Top