Look-Ahead Bias and Point-in-Time Data for Backtesting

Look-ahead bias is using information in a backtest that was not actually available at the decision time — revised macro data, restated financials, or fundamentals used before their filing date. Point-in-time data, which stores each value as it was known on each date, is the standard way to remove it.

Restated fundamentals

Companies restate their financial statements. The revenue figure in today's database for a quarter three years ago may not be the figure the company first reported. A backtest that screens on the restated number is deciding with information investors did not have.

Point-in-time fundamentals fix this by keeping each value as first reported and making it usable only after the filing's acceptance time. FinzData serves SEC fundamentals exactly this way: as first reported, and never visible to a query dated before the filing was accepted.

Revised macro data and vintages

Macroeconomic series are revised after first release — GDP, payrolls and inflation all get rewritten as more source data arrives. Using today's version of a series for a past decision is look-ahead bias, because the first print is all anyone knew at the time.

ALFRED keeps every vintage of FRED series, so you can ask what the number was as published on any date. FinzData carries 20,000+ FRED/ALFRED macro series with every vintage, so a backtest can trade on the first release rather than the final revision.

Filing acceptance times and index membership

Two more sources of look-ahead bias are easy to miss:

  • Filing acceptance times. A 10-Q filed after the close was not tradable information that morning. Point-in-time fundamentals must respect the filing's acceptance time, not just the period end date.
  • Index membership. Testing on today's index constituents over past years uses membership that was only known later. The universe must be rebuilt as it stood on each date.

Point-in-time queries in practice

With FinzData, every tool accepts an as_of parameter, so a backtest can request exactly what was public on each decision date — prices, fundamentals and macro vintages alike:

import finzdata as fd

# Prices as of each decision date
px = fd.Ticker("AAPL").history(interval="1d", start="2010-01-01")

# Basket download for a universe rebuilt per date
basket = fd.download(["SPY", "QQQ"], start="2010-01-01")

AI agents get the same guarantees through the remote MCP endpoint at https://api.finzdata.com/mcp: as_of on every tool, server-side backtests, a deflated Sharpe report and a blind mode. The deflated Sharpe ratio (Bailey and López de Prado, 2014) adjusts a Sharpe ratio for the number of strategy variants tried and for non-normal returns — a useful companion once the data itself is honest.

FAQ

What is look-ahead bias?

Look-ahead bias is using information in a backtest that was not actually available at the decision time — for example revised macro data, restated financials, or fundamentals used before their filing date.

What is point-in-time data?

Point-in-time data stores each value as it was known on each date. When you ask for a series or a fundamental as of a past date, you get exactly what was public then, not today's revised or restated version.

Why do restated fundamentals and revised macro data cause look-ahead bias?

Companies restate financials and statistical agencies revise macro series after first publication. If a backtest uses the final revised number for a past decision date, it is trading on information nobody had at the time.

How does FinzData provide point-in-time fundamentals?

FinzData serves SEC fundamentals point-in-time: each value is stored as first reported and becomes usable only after the filing's acceptance time. Macro series come from FRED/ALFRED with every vintage kept, and every tool accepts an as_of parameter.