Limited historical bars at indicator startup in Tradovate (without API)

I need to collect a sufficient amount of historical data at the start of a custom indicator — typically between 600 and 1000 bars — using 1-minute, 5-minute, or 15-minute timeframes. I’m working on Tradovate with a basic Apex account, which should allow access to at least 1–2 months of historical data.

However, I’ve noticed that at indicator startup, I can retrieve only around 300 bars for symbols like ES, CL, and GC, while for 6E I receive up to approximately 1000 bars.

Where are these limits defined?
Is there a way to increase the amount of historical data retrieved at initialization?

I need this historical base because I apply a frequency transform over the last M closing prices.

Below is a fragment of my map() code:

map(bar, index, history) {
    const close = bar.close();
    const timestamp = bar.timestamp();

    // Inizializzazione
    if (this.initialized === undefined) {
        this.bars = [];
        this.hasProcessed = false;
        this.initialized = false;
        this.lastLiveTime = null;
        this.lastHistoricalComplete = null;
        this.estimatedTF = null;
    }

    // Gestione delle barre incomplete
    if (!bar.isComplete()) {
        this.lastLiveTime = timestamp;
        console.log(`🚀 [${index}] Trovata barra incompleta (live): ${new Date(timestamp).toISOString()}`);
        console.log(`⛔ [${index}] Barra incompleta scartata (${new Date(timestamp).toISOString()})`);
        return null;
    }

    // Stima del timeframe
    if (!this.estimatedTF && history && history.prior()) {
        const priorTimestamp = history.prior().timestamp();
        this.estimatedTF = timestamp - priorTimestamp;
        console.log(`🕒 TimeFrame stimato: ${this.estimatedTF / 60000} minuti`);
    }

    // Salvataggio della barra storica
    this.bars.push({ close, date: timestamp });
    console.log(`📌 [${index}] Barra storica: close=${close.toFixed(4)}, time=${new Date(timestamp).toISOString()}`);

    // Verifica se abbiamo raggiunto la barra storica immediatamente precedente alla prima barra live
    if (this.lastLiveTime && this.estimatedTF) {
        const expectedLastHistoricalTime = new Date(this.firstLiveTime.getTime() - this.estimatedTF);
        if (timestamp.getTime() === expectedLastHistoricalTime.getTime() && this.bars.length >= 600) {
            this.initialized = true;
            console.log(`✅ [${index}] Raggiunta ultima barra storica: ${new Date(timestamp).toISOString()}`);
        }
    }

    // Se non ancora inizializzato o già elaborato, non fare nulla
    if (!this.initialized || this.hasProcessed) return null;

    // Elaborazione dei dati
    const required = this.maxPeriod * this.periodMultiplier;
    const windowBars = this.bars.slice(-required);
    const slice = windowBars.map(b => b.close);
    console.log(`✅ [${index}] Slice estratta: ${slice.length} elementi`);
    console.log(`   ↪︎ Inizio: ${slice.slice(0, 3).map(v => v.toFixed(2))}`);
    console.log(`   ↪︎ Fine:   ${slice.slice(-3).map(v => v.toFixed(2))}`);

    let detrended = this.hpFilter(slice);
    if (!detrended.length) return null;

    detrended = this.minMaxScale(detrended);
    const windowed = this.kaiserWindow(detrended);

    const periods = [];
    for (let p = this.minPeriod; p <= this.maxPeriod; p += this.periodStep) {
        periods.push(p);
    }

    const transformed = this.goertzelTransform(windowed, periods);
    const dominant = this.selectDominantCycles(transformed);
    const best = this.optimizeCycles(dominant, windowed);
    const composite = this.extendSignal(dominant, best, windowed.length);
    const relIndex = windowed.length - 1 + windowed.length;

    this.hasProcessed = true;
    console.log(`🚩 [${index}] CDC=${composite[relIndex].toFixed(3)} Detrended=${detrended[windowed.length - 1].toFixed(3)}`);

    return {
        CDC: composite[relIndex],
        Detrended: detrended[windowed.length - 1]
    };
}

Tradovate caps the maximum bars on chart load to 5,000 bars, but you can scroll backwards through the chart to load more bars. That is, assuming there are more trades back further for that futures contract. You can also chart the Continuous Contract by adding an @ symbol, such as @NQ, but that chart will not be able to place trades.

The Chart Editor is where you will find the box to edit “Bars to Load”:

Hope this helps.

Thank you, John,

Partially yes. I wasn’t aware that the minimum number of downloadable bars could be set manually — good to know that.

However, when the indicator starts, I don’t see the full number of past bars I’ve defined. Specifically:

  1. By default (e.g., for MES), I saw that there are 999 minimum loaded past bars in the chart editor. I tried increasing it to 2000.
  2. When I scroll the chart horizontally, I can see 500, 1000, or even more past bars, which confirms that the subscription and data provider do support more than 300 bars.

Yet, when my indicator initializes at the startup, I only get about 300 past bars for MES; and 1000 for 6E. From what I understand, the map method is called from the earliest historical bar up to the most recent live (in-progress) bar, in chronological order. I believe this assumption is correct, since I logged everything.

Still, I may be missing something — perhaps a parameter that controls the starting index for historical data download?

Thank you.

You need to save a base template that has the minimum bars on load set to 5000. Name it something like 000-BASE so that it always is the top template. Then for every new template, load the 000-BASE template first to always have the minimum bars on load set to 5000.

This gets me a bit confused. Do you mean that setting the minimum number of downloaded periods in the chart settings is not enough to have them available at indicator initialization?

Why do I still observe different behaviors between instruments like ES and 6E?

Isn’t there really any setting or function in the Tradovate JavaScript environment that explicitly controls how many past bars are downloaded and made available to custom indicators?

Thank you.

Federico.

Every time you open up a new chart tab, that chart starts with the default Tradovate “Minimum Bars to Load” set to 100 (as well as the default Tradovate color scheme, candle colors, Renko bar settings, Bid-Ask Volume settings, etc ). That is why you need to create a starting template of your default settings. Then add your indicator from there.

Thank you again.

I have opened a new chart and set “minimum number of bars to load” parameter to 2000:

Then, i saved this chart as the model “base 2000 bars”.

I opened a new chart, applied the base 2000 bars template and added my custom indicator that log the size of the bars history …

… and it worked!

Thank you so much!

I just want to point out that this behavior is not very intuitive for end users.
If an indicator requires more bars than the default and changing the chart setting “Minimum number of bars to load” to a higher value still doesn’t make it work, it will likely be perceived as a bug.

Is there any way to force the bar load programmatically? Or at least to make the chart setting effective without going through a template?

Thanks again for your help!