How to implement a full repainting FFT-based indicator over N historical bars?

I need to implement a fully repainting indicator in Tradovate that, at each new live bar (incomplete), performs:

  1. An FFT on the N most recent bars before the live one
  2. Applies a frequency cutoff filter
  3. Performs an IFFT (inverse transform)
  4. And displays all N reconstructed values on the N bars preceding the current one

In other words:

  • I need to fully repaint the signal on N bars every time a new live bar arrives.
  • This is an intentional design: I recalculate and rewrite past values on every update.

Why this is NOT like the official FourierMovingAverage example

In the official tutorial here Fourier Moving Average | Tradovate Custom Indicators

  • The indicator computes a new FFT for each historical bar, one by one.
  • It only outputs the current filtered value (re[0]) for the bar being evaluated.
  • As a result, it does not repaint past values after new bars arrive — it computes the past values once during loading.

In contrast, my approach is different:

I compute the FFT only at runtime on the latest N bars, and then redistribute the entire IFFT result back over those same N historical bars — repainting them on every new bar.


The problem

I tried to implement this logic, and logs confirm that:

  • FFT and IFFT are correctly executed on each new live bar
  • An array of N filtered values is available after the inverse transform
  • I attempt to return these values by associating them to indexes index - N + 1 through index

Yet — nothing appears on the chart.


so, the question is:

  • Is it possible in the Tradovate custom indicator system to repaint past bars dynamically (e.g., on every live bar, rewrite the values on the last N historical bars)?
  • Are there any known working examples that do this?
  • Is it necessary to use graphics instead of plots to force this kind of dynamic retroactive rendering?

I would really appreciate guidance or confirmation if this approach is viable or fundamentally unsupported.

Thanks in advance!
— Federico

Aloha, Frederico! You wouldn’t be able to reset or affect the plot lines, that’s a one time pass through. However on the last bar (check data.isLast()), you can loop back through the history object N bars, and use the graphics API to draw what you want on the prior N bars.

Hope this helps, feel free to DM me. Cheers! :call_me_hand:

1 Like

Yes thank you, you confirmed what I was trying was correct in principle. Finally I get what I needed and I post here a version of FFT filtering using that plotting strategy.

const { op, px, du } = require("./tools/graphics");
const FFT = require("fft");

class FilteredIFFTTrail {
    init() {
        this.period = this.props.period || 64;
        this.cutoffPeriod = this.props.cutoffPeriod || 16;
        this.values = [];
    }

    map(d, i, history) {
        const isLive = !d.isComplete();
        const value = d.close();

        this.values.push(value);
        if (this.values.length > this.period + 1) {
            this.values.shift();
        }

        if (isLive && this.values.length >= this.period) {
            const fft = FFT(this.period);
            const re = this.values.slice(-this.period);
            const im = new Array(this.period).fill(0);

            fft.fft1d(re, im);

            const cutoffFreq = this.period / this.cutoffPeriod;
            for (let j = 1; j < this.period; j++) {
                if (j >= cutoffFreq && j <= this.period - cutoffFreq) {
                    re[j] = im[j] = 0;
                }
            }

            fft.ifft1d(re, im);

            const graphics = { items: [] };

            for (let j = 0; j < this.period - 1; j++) {
                const bar1 = history.back(this.period - 1 - j);
                const bar2 = history.back(this.period - 2 - j);
                if (!bar1 || !bar2) continue;

                const x1 = bar1.index();
                const x2 = bar2.index();
                const y1 = re[j];
                const y2 = re[j + 1];

                graphics.items.push({
                    tag: "Shapes",
                    key: `ifft-segment-${x1}`,
                    primitives: [{
                        tag: "Polygon",
                        points: [
                            { x: du(x1), y: op(du(y1), '-', px(1)) },
                            { x: du(x2), y: op(du(y2), '-', px(1)) },
                            { x: du(x2), y: op(du(y2), '+', px(1)) },
                            { x: du(x1), y: op(du(y1), '+', px(1)) }
                        ]
                    }],
                    fillStyle: { color: "#00FFFF" }
                });

                const barTime = bar1.timestamp();
                console.log(`🔵 [IFFT] Segment ${j}: x1=${x1}, y1=${y1.toFixed(2)}, time=${barTime ? new Date(barTime).toISOString() : 'N/A'}`);
            }

            console.log(`✅ Drawing filtered IFFT path ending at index ${i}`);
            return { graphics };
        }

        return null;
    }
}

module.exports = {
    name: "Filtered IFFT Trail",
    description: "Draws the latest IFFT filtered window as a repaint line",
    calculator: FilteredIFFTTrail,
    inputType: "bars",
    areaChoice: "new",
    plots: {},
    params: {
        period: { type: 'number', def: 64, min: 8, max: 512, step: 1, title: "FFT Period" },
        cutoffPeriod: { type: 'number', def: 16, min: 2, max: 256, step: 1, title: "Cutoff Period (keep cycles longer than)" }
    },
    tags: ["fft", "ifft", "graphics", "polygon", "repaint"]
};

I still have not understood

  1. if it is possible to cancel the previous plots before tracing the new one based on the last data update
  2. if it is possible to center the Y axe and the zoom to the traced plot, right now it is around 0 while i have values around 5000
  3. and still how to get a in the map at startup more than 3-400 historical past bar values. Even if in the chart setting I selected 2000 periods, when the indicator re-start from begin, I get less than 400 past bars for ES, MES, CL and 1000 for 6E.
    thank you.