Learn › EAs and automated trading

Repainting Indicators and Lookahead Bias: Why Great Backtests Fail Live

ZigZag redraws its last leg until it confirms and fractals need future bars. How future data leaks into backtests and EAs, with a worked example of the fake profit.

Intermediate 9 min read 21 October 2026

What you will learn
  • A repainting indicator changes the values of past bars, so the historical chart looks more accurate than it ever was live
  • ZigZag only knows a high or low is finished after price has turned a fair way. In our gold data, price had already retraced about half of the previous leg when the pivot confirmed
  • A backtest that uses finished pivots wins every trade even on random prices, while one that waits for confirmation makes about zero. The whole gap is information from the future
  • The simplest check is to step the chart one bar at a time, or run the EA on a demo account and compare live signals with what the chart draws afterwards

Ever seen an indicator whose buy and sell arrows land exactly on every bottom and top? Pictures like that usually come from repainting, where an indicator goes back and changes the values of bars that have already closed, or from lookahead bias, where a backtest quietly uses information nobody had at the time. Both make past results look better than they were, and they are a big reason an EA or rule set that looks very accurate behaves differently live.

Repainting vs lookahead bias

  • Repainting is about the indicator. Values shown on old bars can change when new bars arrive, so what you see on the historical chart is not what you would have seen while those bars were forming.
  • Lookahead bias is about the test. The backtest uses data that did not yet exist at that moment, for example using a bar’s close to decide an entry at the same bar’s open.

The two often come together. Measuring a repainting indicator on a finished chart is looking into the future without realising it. It is a lot like hindsight bias, except this time the spreadsheet does it for you.

ZigZag: the last leg isn’t real yet

ZigZag draws lines between important highs and lows (called pivots) and skips the small swings in between. The default ZigZag in MT4 and MT5 is Depth 12, Deviation 5, Backstep 3. The exact calculation differs by platform, but the principle is the same everywhere.

  1. While price is still rising, the latest high is a “provisional high”. Every time price makes a new high, the line is redrawn to it.
  2. The high is only confirmed once price has come back down far enough, or a set number of bars has passed.
  3. By the time it confirms, price has already travelled a good way back. That part of the reversal is something nobody could have traded.

For this example we use a simple ZigZag on closing prices. Price must reverse at least 3 price points from a high or low to confirm it, and we compute it one bar at a time, just like watching a live chart.

Bar 26: latest high is bar 19, not confirmed yet Bar 40: a new high, so the leg is redrawn to bar 36 Bar 52: price falls 3 from the high, bar 44 is confirmed Confirmed leg Latest leg, can still redraw Close
Illustrative random series, not a real market. ZigZag on closing prices with a 3-point reversal threshold. Each panel uses only data up to that bar; the dashed line is the latest leg, which can still change.

Step by step:

  • Bar 26: the provisional high is bar 19 at 109.22. The current price of 106.50 is 2.72 points below it, just short of confirming. Someone looking here might think the top is in.
  • Bar 40: price has made a new high, so the line that pointed at bar 19 is redrawn to bar 36 at 109.89.
  • Bar 52: the close of 107.00 is 3.58 points below the high at bar 44 (110.58). That clears the threshold, so the high confirms.

From its first provisional print to confirmation, this high moved 14 times. When it confirmed, price had already fallen 3.58 ÷ 10.58 = 33.8% of the up leg from 100 to 110.58. On the finished chart, all you see is one neat line from bottom to top.

Our data: how late is a pivot known

In our historical measurements on gold (XAUUSD), M1 chart, 2022–2026, using M1 bar data and ZigZag at several sizes (depth 13, 20, 50, 100 and 300 bars), we found:

  • When a pivot confirmed, price had already retraced a median of 44–50% of the previous leg, at every size and in every year. Put simply, in a typical case about half of a reversal is over before we know there is a pivot. The average is higher, around 60%, because in roughly one case in six price had already gone back past the start of that leg by the time the pivot confirmed. Because the median barely changes with size, it comes from the definition of ZigZag itself, not from any habit of the market.
  • With a large ZigZag (depth 300 on M1), across 3,860 legs over 5 years, the latest pivot moved a median of 13 times and took a median of 357 bars, about 6 hours, from first appearing to settling. Only 6% never moved at all.

One consequence: if you place a Stop loss at the pivot after it confirms, that stop is typically about half the previous leg wide. These figures are historical measurements on a single market and do not predict future results.

On a historical chart ZigZag seems to know every top and bottom. In real time it always knows later than you think, and that delay is the price of a line that doesn’t lie.

Other tools that quietly look ahead

ToolWhere it looks aheadHonest use
Fractal (Bill Williams)A high must be above 2 bars on the left and 2 on the right. The arrow sits on the middle bar, but you only know after both right-hand bars closeCount the signal as happening 3 bars after the high
Centered moving averageThe line is shifted back half its length, so the last values need bars that don’t exist yet. Some versions fill them in temporarily and fix them laterUse a normal MA that isn’t shifted back
Higher-timeframe valuesAn H4 bar that hasn’t closed keeps changing, but on the historical chart every M15 bar inside it usually shows the final H4 valueRead the closed H4 bar (shift 1)
Signals on the forming barBar 0 changes on every tick, and an arrow can appear and vanish before the bar closesDecide when the bar closes, read values from bar 1

The higher-timeframe case is very common, and it is why many multi-timeframe indicators look so accurate on history. On TradingView, pulling another timeframe with request.security() with lookahead switched on, without offsetting the value by one bar, lets past bars see closing prices that hadn’t happened yet. In MQL, Close[0] or iClose(_Symbol, PERIOD_H4, 0) is the latest price of a bar that hasn’t closed, not its real close. For more on reading several timeframes, see multi-timeframe analysis.

Example: a lookahead backtest vs an honest one

Using the same prices as the figure above, we test a “follow the ZigZag reversal” rule two ways.

  • Lookahead: buy at the bottom, sell at the top, using finished pivots as they appear on the historical chart.
  • Honest: buy or sell at the close of the bar where the pivot confirms, then reverse when the next pivot confirms.
LegLookaheadHonest
Low bar 0 → high bar 44 (buy)100 → 110.58 = +10.58bar 5: 103.34 → bar 52: 107.00 = +3.66
High bar 44 → low bar 54 (sell)110.58 → 106.65 = +3.93bar 52: 107.00 → bar 58: 111.51 = −4.51
Low bar 54 → high bar 60 (buy)106.65 → 112.96 = +6.31bar 58: 111.51 → bar 67: 108.63 = −2.88
High bar 60 → low bar 75 (sell)112.96 → 101.94 = +11.02bar 67: 108.63 → bar 78: 105.19 = +3.44
Total+31.84, 4 wins out of 4−0.29, 2 wins out of 4

The first leg shows the mechanism. The honest version enters 3.34 points after the bottom and exits 3.58 points after the top, so what’s left is 10.58 − 3.34 − 3.58 = 3.66 points. Every leg pays twice like this, and any leg shorter than what is given up becomes a loss.

Extending the same random series to 2,000 bars gives 118 trades for both versions.

+860.9 Lookahead uses final pivots +4.0 Honest waits for confirmation −19.6 Honest + costs 0.2 per trade
Totals in price points on the same random series as above, extended to 2,000 bars, not a real market. Same rule; the only difference is using finished pivots or waiting for each pivot to confirm.

The lookahead version makes +860.9 points, 7.30 per trade, and wins every trade. The honest version makes +4.0 points, 0.03 per trade, winning 42 of 118 trades (35.6%). After an assumed cost of 0.2 points per trade, the honest version becomes −19.6, while the lookahead version still shows +837.4 and looks as good as ever.

We repeated this on 200 random series of 2,000 bars each (this one among them). The lookahead version averaged +820.8 points per series, the honest version averaged −3.1, and was positive in only 94 of the 200. That is what should happen on random prices with no pattern to find. All of the lookahead profit is manufactured from future data.

Waiting for confirmation is a filter, not just a cost

Once you see how late pivots are, it’s tempting to wait less. But in our backtests on gold M1, 2022–2026 run as one continuous test (ticks generated from M1 bars for the whole period), a pullback system built on a large ZigZag got worse every time the wait was shortened.

Bars waited for the pivot to confirmNet profit ÷ maximum drawdown
30011.73
2009.09
1008.05
307.52
16.68

Another experiment switched to a frame known instantly, with no waiting at all. The number of trades rose from 2,210 to 5,247, but the total turned slightly negative and drawdown rose from 6.71% to 39.58%. The reason: a high that survives hundreds of bars without being broken is one the market has confirmed, while an instant frame lets fake highs in too. This is one market and one system, and backtest results do not predict future results. But it points in a clear direction: the cure for lateness is not peeking at the future, and it isn’t necessarily jumping in early either.

How to check whether an indicator or EA looks ahead

  1. Step the chart bar by bar. Use the MT5 Strategy Tester in Visual mode, or Bar Replay on TradingView, and watch whether arrows or lines on old bars change. If they do, it repaints.
  2. Record live signals. Run it on a demo account for a week, screenshot every signal as it appears, then compare with a freshly reloaded chart. If they don’t match, its historical results can’t be trusted.
  3. Ask when each value was known. Every variable in a backtest needs an answer to “known as of which bar?”. A signal from a closed bar should be entered at the next bar’s open, not the same bar’s open.
  4. Read the right ZigZag value in an EA. The latest non-zero value in the ZigZag buffer is the leg that can still move. Use the one before it, or check the confirmation threshold yourself.
  5. Be suspicious of results that are too good. A very high win rate, almost no losing streaks and a straight-line equity curve usually point to leaked data rather than skill. More in backtest vs live results.

Hand-written backtests in Excel or Python carry the most risk, because the whole data set sits in one table and a one-row shift is enough to look ahead. The MT5 Strategy Tester feeds data to the EA in time order, but results can still be distorted if the EA reads a repainting indicator or the data quality is poor. Read more in MT5 tick data quality.

Combining it with risk management

A lookahead backtest doesn’t just inflate profit, it also shrinks drawdown, because the losing trades disappear. If you size positions from that drawdown, your lots will be bigger than the account can survive. Set your position size from the Stop loss using honest backtest results only, and be ready for the losing streaks a pretty historical chart never shows.

Before trusting a backtest, ask of every number: at that bar, did we really know this yet?

Even an honest backtest can fool you another way if you try dozens of rule sets and keep the best one. Read on in multiple testing and data snooping and walk-forward testing.

Common mistakes

  • Buying an indicator because its arrows hit every bottom on the historical chart, without ever watching it live
  • Using the last ZigZag leg as a signal while it can still move many more times
  • Measuring results from the bar that made the high or low instead of the confirming bar
  • Reading a higher-timeframe value from a bar that hasn’t closed and treating it as that bar’s real value
  • Deciding on the forming bar but backtesting with values from the closed bar
  • Cutting the confirmation wait so far that fake signals flood in

Frequently asked questions

Are repainting indicators useless?

No, as long as you know which values are confirmed. ZigZag is good for seeing the structure of past swings. The trouble starts when you trade the unconfirmed last leg, or measure results on a chart that has already been drawn. Use only confirmed pivots, and time your entries from the confirming bar, not from the bar that made the high or low.

Can the MT5 Strategy Tester look into the future?

The tester feeds the EA one tick at a time in order, so the EA cannot read future bars. Results can still be distorted in other ways, for example by reading a repainting indicator and using its last leg as a signal, or by testing on open prices only with an EA that makes decisions inside the bar. Backtests written by hand in Excel or Python are far more likely to look ahead.

Why does the backtest get so much worse once I remove lookahead?

Because most of the original result came from knowing the future, not from the rules. Once the future data is gone, what remains is the real skill of the rules, which may be small or nothing. An honest result that disappoints is worth more than a beautiful one you can't trade.

This is general education, not investment advice. Trading is risky and you may lose all of your capital.

Tools Chat on LINE