Quant Memo
Core

Missing Data and Forward Fill

Financial time series are full of gaps, from holidays to halted stocks to late data feeds, and how you fill those gaps can accidentally leak information a real trader never had.

Prerequisites: Resampling and Frequency Conversion

Real market data has holes. A stock gets halted for an hour, an exchange holiday skips a day entirely, a vendor's feed drops a field, or two assets that should line up on the same calendar simply don't — a US stock trades Monday, its European ADR doesn't. Every one of these shows up in a dataframe as NaN, and what you do with that NaN is a modeling decision, not a formatting one.

The most common fix is forward fill: carry the last known value forward until a new one arrives. It is popular because it is the closest thing to "reasonable" — if you don't know today's price, yesterday's is your best guess. But forward fill is also the easiest way to accidentally tell your backtest something it couldn't have known.

Forward fill answers "what was the last value I actually observed?" — which is exactly what a live trading system does, since it can't see the future either. The danger is using forward fill on data whose true value at a given timestamp is different from its last observed value, like a stale corporate action or a delayed print, which makes the fill silently wrong rather than silently missing.

Filling strategies compared

MethodWhat it doesWhen it's right
Forward fill (ffill)Carries the last known value forwardPrices, when nothing traded — the last trade is the current price until proven otherwise
Backward fill (bfill)Carries the next known value backwardRarely correct for live use — it looks into the future
Linear interpolationDraws a straight line between the two nearest known pointsSmooth physical quantities (e.g., temperature), not prices, which don't interpolate meaningfully
DropRemoves the row entirelyWhen a feature is required and there's no honest way to guess it
Fill with a constant (e.g., 0)Replaces gaps with a fixed valueOnly when 0 is a genuinely meaningful default, like missing volume meaning no trades
forward fill flat — only uses the last known value interpolation sloped — needs the future endpoint to draw
Forward fill only ever uses the past; interpolation needs to know the future value it's aiming at, which a live system would not have yet.

Worked example

A stock's daily closing prices: Mon 50.00, Tue NaN (halted), Wed NaN (halted), Thu 52.00, Fri 51.50.

Forward filling gives: Mon 50.00, Tue 50.00, Wed 50.00, Thu 52.00, Fri 51.50. Tuesday and Wednesday both show the same 50.00 — reasonable, since the stock genuinely did not trade and 50.00 was the last real price. Compute a daily return series on the filled data and Tuesday's and Wednesday's returns come out as exactly 0%, which is correct: nothing happened, so nothing should be reported as having happened.

Now contrast with linear interpolation, which would give Tuesday 50.67 and Wednesday 51.33 — smoothly walking the price from 50.00 to 52.00 across the halt. Those numbers were never real prices anyone could have traded at; a backtest that marks a position to that interpolated value on Tuesday is pricing off data that didn't exist yet, since the 52.00 endpoint wasn't known until Thursday.

What this means in practice

The test for any fill method is: could a system running live, at that exact timestamp, have produced this value using only data available up to that moment? Forward fill passes that test for prices. Interpolation fails it, because computing the value at Tuesday requires already knowing Thursday's close. The same logic applies to fundamentals data — filling a missing quarterly earnings figure with the next reported quarter's number is backward fill wearing a disguise, and it is one of the most common sources of look-ahead bias in factor research.

fillna() with no arguments and no thought is a common source of silent backtest inflation. Always ask which direction in time the fill method pulls information from before applying it to anything that will touch a trading signal — forward-only fills are safe by construction, anything that uses future rows is not.

Related concepts

Practice in interviews

Further reading

  • McKinney, Python for Data Analysis (ch. 7, 'Data Cleaning and Preparation')
ShareTwitterLinkedIn