◆ New — Strategy Validator, Code Fixer & Prop Compliance Checker are live. Try one free →
Home / Learn / freqtrade startup_candle_count Explained
Python

freqtrade startup_candle_count Explained

In freqtrade, startup_candle_count tells the engine how many extra candles of history to load before your strategy starts acting, so indicators have warmed up and are not producing NaN or partial values. This article explains why warmup is needed, how to size the value from your longest lookback, and the bugs that appear when it is missing or too small. It is educational material about backtest correctness, not financial advice.

What is startup_candle_count in freqtrade?

startup_candle_count is a strategy attribute in freqtrade that tells the engine how many additional historical candles to load and process before your entry and exit logic is allowed to act. Its job is to give every indicator in your strategy enough prior data to produce stable, correct values instead of the NaN or partially-formed values that appear at the very start of a series. You set it as a plain integer on your strategy class:

class MyStrategy(IStrategy):
    startup_candle_count: int = 200

The mechanism is straightforward. Suppose you backtest from 2024-01-01 on a 5-minute timeframe with startup_candle_count = 200. freqtrade will actually load data starting ~200 candles before 2024-01-01, compute all your indicators across that extended range, and only then begin evaluating signals from 2024-01-01 onward. By the time the first tradable candle arrives, every indicator has already had its warmup period fed with real data — so the values are stable rather than half-formed.

Without this, the first N candles of your backtest would contain indicator values that either do not exist yet (NaN) or are computed from too little history to be trustworthy. Acting on those is a correctness bug, and it is one that quietly changes results, which makes it worth understanding precisely.

Why do indicators need a warmup period?

Most technical indicators are functions of a trailing window of prices, so they simply cannot be computed until that window is full. A 20-period simple moving average needs 20 candles before it produces its first real number; ask for it earlier and you get NaN. Worse, some indicators are recursive: an exponential moving average, RSI, or MACD carries state forward from candle to candle, so the earliest values are not merely missing — they are converging. They exist, but they are wrong, and they slowly settle toward correctness as more history flows in.

This "unstable period" is the subtle part. A freshly-started EMA100 does not just need 100 candles; it needs materially more before its value stops depending noticeably on where the calculation happened to begin. freqtrade's own guidance for an ema100 indicator is to set startup_candle_count = 400 — four times the nominal period — precisely because the recursive convergence tail is much longer than the raw lookback.

The consequence for a backtest is direct. If the engine has no warmup buffer, your strategy sees these unstable values on its first candles and may generate entry or exit signals from them. Those signals are artifacts of insufficient history, not of your actual logic. Because a live bot accumulates history naturally over time, this is a discrepancy between backtest and live behavior — a category of problem explored in [why most backtests fail](/learn/why-most-backtests-fail).

How do you size startup_candle_count?

The rule of thumb is: set startup_candle_count to at least the longest lookback among all your indicators, and add generous margin for any recursive ones. Walk through every indicator your strategy computes and take the maximum window, then pad it.

class MyStrategy(IStrategy):
    # Longest lookback here is the 200-period SMA, plus margin for
    # the recursive EMA/RSI convergence tails.
    startup_candle_count: int = 300

    def populate_indicators(self, dataframe, metadata):
        dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200)
        dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50)
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
        return dataframe

Here the longest nominal lookback is the 200-period SMA. A bare minimum would be 200, but because the EMA and RSI are recursive, padding to 300 buys a safety margin so their convergence tails are absorbed inside the warmup rather than leaking into tradable candles. For a purely non-recursive set of indicators, the longest window is enough; the moment a recursive indicator is present, over-provision.

Do not guess blindly, though. freqtrade ships a recursive-analysis command that empirically measures how much your indicator values change as you vary the amount of startup data. When it reports a variance of 0% at a given startup_candle_count, you have loaded enough history for the values to be stable. That turns sizing from a guess into a measurement — set the value, run recursive analysis, and increase it until the variance settles to zero.

What bugs appear when startup_candle_count is missing or too small?

When startup_candle_count is absent or too small, freqtrade does not error out — it uses whatever indicator values happen to be in the dataframe, including the NaN and unstable ones at the head of the series. That silent behavior is what makes the bug dangerous. Concretely:

  • Acting on NaN or partial values. The first candles of your backtest carry indicator values computed from too little history. Entry/exit conditions evaluated against them fire (or fail to fire) for the wrong reasons, injecting phantom trades or suppressing real ones.
  • Backtest/live divergence. A live bot builds history continuously, so after running for a while it always has a full warmup buffer. A backtest without startup_candle_count does not. The two disagree on the earliest candles, and the backtest is the untrustworthy one.
  • Results that shift when you change the start date. If moving your backtest start by a few days changes the outcome noticeably, insufficient warmup is a prime suspect — the unstable head of the series is landing on different candles.

Critically, none of this throws an exception, so it will not surface unless you look for it. It is the same silent-failure profile as [look-ahead bias](/learn/look-ahead-bias): the code runs, the report renders, and the numbers are quietly wrong. Setting a correct startup_candle_count — validated with recursive-analysis — removes this whole class of error before it ever reaches your evaluation.

Warmup, validation, and honest evaluation

Correct warmup is a precondition for trusting any downstream metric, not a performance feature. If your indicators are unstable on the earliest candles, then every statistic derived from that backtest — including whatever you compare across parameter sets — is contaminated at the edges. Fixing startup_candle_count does not make a strategy good; it makes the measurement clean enough to reason about.

Warmup also interacts with how you split data for validation. When you carve history into in-sample and out-of-sample segments, or run [walk-forward analysis](/learn/walk-forward-analysis), each segment's indicators need their own warmup buffer or the boundary candles will be unstable. freqtrade handles this by loading pre-start history for the whole run, but the principle to keep in mind is that a fresh window always needs warming. The broader discipline of separating fit from evaluation is covered in [in-sample vs out-of-sample](/learn/in-sample-vs-out-of-sample) and [overfitting and curve-fitting explained](/learn/overfitting-curve-fitting-explained).

A short checklist: enumerate your indicators, take the longest lookback, pad generously for recursive ones, set startup_candle_count, then run recursive-analysis and raise the value until variance hits 0%. When you move on to signal timing in your own vectorized experiments, the free [Python Backtest Validator](/python) and the [overfitting tool](/backtest/overfitting) can help check that the rest of your pipeline is sound. This article is educational material about backtest correctness; it is not financial advice, and nothing here implies any strategy is or will be profitable.

Key takeaways

Educational only — not financial advice. Trading involves substantial risk of loss.

Catch the bug that compiles.Run auditGet Pro