How to Identify Future Functions in Backtesting
The most direct way to check for future functions in a backtest is to run one test using the "closing price" and another using "yesterday's closing price" — if the two curves differ dramatically, your strategy has data that "peeks into the future."
1. First, determine whether your strategy uses "closing price to decide today's trade"
This is the most common form of future function.
Problem code:
ma30 = df['Close'].rolling(30).mean(); signal = df['Close'] > ma30. In daily backtesting, the system calculates the moving average using the current day's close, generates the signal for that same day, and then measures P&L with that same close. In live trading, at 10 a.m. you have no idea what the 3 p.m. close will be. This is a classic case of "seeing the answer before doing the problem."Correct approach:
ma30 = df['Close'].rolling(30).mean().shift(1); signal_real = df['Close'] > ma30; trade_signal = signal_real.shift(1). The moving average must be based on yesterday's close, the trading signal must be generated from data already fixed after yesterday's close, and the order is executed in the next period.Pass criteria: You can find
shift(1)in the code and confirm that the data source timestamp used to generate the signal is at least one period earlier than the execution timestamp.
2. Check for ZIG (zigzag) turning functions
These functions are a major source of forward-looking bias.
Typical functions: ZIG, PEAK, PEAKBARS, TROUGH, TROUGHBARS, FLATZIG, and BACKSET all belong to the future-function family.
Why they fail: A ZIG function only confirms a turning point after the price has moved by more than N%. In a backtest, when it "looks back" it plots peaks and valleys with deceptive precision. But in live trading, today's turning point can only be confirmed after tomorrow's or even the day-after-tomorrow's price data arrives — the signal shifts with the latest candle, and a "buy" signal that appeared yesterday may vanish today.
Pass criteria: Search your strategy code for the function names listed above. If any of them appear, the strategy cannot be assumed safe for live trading by default.
3. Check whether financial statement data uses revised values
This issue appears often in on-chain data or fundamental strategies.
Problem description: A company releases its Q1 2025 report on April 30, 2025, but issues a correction on May 15, 2025, adjusting some figures. If you fill the revised data retroactively into all Q1 time points during backtesting, any trades between April 30 and May 15 would have access to "data revised in the future," introducing a future-function flaw.
Correct approach: Use the announcement date as the data change point, not the reporting period date. When computing factors, use only the announced data available up to the current trading day, and filter corrected data strictly by announcement date, not report date.
Pass criteria: Your data usage logic contains an explicit filter based on the "announcement date," and you can verify through code that the data used on any given trading day was indeed publicly available on that day.
4. Perform a "shift-back verification" test
This is the most direct and effective verification method.
How to do it: If you suspect an indicator uses future data, shift the entire signal generation logic backward by one period (using
shift(1)) and run the backtest again. If the return curve remains nearly unchanged, the original strategy likely does not rely on future data; if it drops significantly or turns negative, the original strategy was indeed "peeking into the future."Pass criteria: The divergence between the shifted-signal backtest and the original backtest serves as a judgement — the larger the gap, the more severe the future-function problem.
5. Common reasons for failure
Failure reason: relying on the default behavior of the backtesting tool. Some backtesting frameworks load all data into a
dfat once and compute indicators in bulk. Even if your code logic looks correct, if the framework does not enforce "time-window isolation," certain indicator calculations may still implicitly reference future data.
How to confirm you have completed the checks correctly:
After performing the above checks, before going live, run a paper-trading simulation for 3 to 5 days. Future functions cannot take effect in a simulation — because a simulation follows real time, pushing data tick by tick, and past data will not be retroactively corrected. If the trading signal frequency during the simulation differs significantly from the same period in historical backtesting, your backtest code definitely contains a logical flaw that "peeks into the future," and you need to go back and re-inspect it.
