Technical question on indicator "lifecycle"

Hey @BWeis I was about to open a support ticket around this but figured having it here in the community forums might be helpful for others as well.

I found a surprising behavior around some custom indicator code today, and I feel like the explanation can only come from someone of knowledge of the core code that hosts and runs these indicators.

Basically, it looks like there is some sort of special handling that happens for the tools used by an indicator (example here is SMA). If I have that tool hidden behind another class or function object (instead of directly assigned on the indicator class itself), the reference to that tool changes from a function to an object with just one property “state”.

I surmise this has something to do with live updates on the “active” final bar, because the issue pops up on the last bar only.

Here is code that shows the surprising behavior… if useSMAClass is enabled, it breaks. If it’s not enabled, everything works.

Is there a way to work around, or an explanation we can have to keep in mind in order to structure custom indicator code properly?

const predef = require("./tools/predef");
const SMA = require("./tools/SMA");

class test {
    init() {
        this.sma1 = new SMA(this.props.period);
        this.sma2 = new mySMA(this.props.period);
    }

    map(d, i, history) {
        if (this.props.useSMAClass) {
            return this.sma2.map(d, i, history);
        } else {
            return this.sma1(d.value());
        }
    }
}

class mySMA {
    constructor(period) {
        this.sma = SMA(this.period);
    }
    
    map(d, i, history) {
        if (typeof(this.sma) !== "function") {
            console.log(i+1);
            console.log(history.data.length);
            console.log(this.sma);
        }
        this.sma(d.value());
    }
}

module.exports = {
    name: "test",
    description: "test",
    calculator: test,
    params: {
        period: predef.paramSpecs.period(14),
        useSMAClass: predef.paramSpecs.bool(false)
    },
    tags: [predef.tags.MovingAverage],
    schemeStyles: predef.styles.solidLine("#8cecff")
};

Many thanks!

The indicator’s state is preserved after the calculation of completed bars and restored before each calculation of incomplete bar. You can assume that we use a deep cloning of the indicator’s instance with a special treatment for functions: we preserve their state field, if it presents, and then restore it back without touching the function itself. In your example, this.sma1 is a function with state field.
We do not have such special treatment for fields that were instantiated by a class.

1 Like

Fascinating, that makes good sense for the behavior I saw @Victor_Vins. Thanks for clearing it up.