Temporal leakage is not limited to trading. It appears whenever a historical training row, evaluation, forecast, or decision accidentally uses information that became available later.
The failure mode is unusually dangerous because it tends to improve offline metrics. A leaking pipeline can therefore look more convincing as it becomes less valid.
TimeSeriesSplit and a gap parameter because ordinary
shuffled or i.i.d. cross-validation is inappropriate for ordered observations:
https://scikit-learn.org/stable/modules/cross_validation.html#time-series-splitlookahead-analysis command because full-dataframe
backtests can accidentally read future candles and report unrealistic results:
https://docs.freqtrade.io/en/latest/lookahead-analysis/These tools address important parts of the problem in their own domains. The remaining practical gap NoFutureData targets is a small, local guard that can be added to an ordinary Python/Jupyter repository without adopting a feature store, backtesting engine, or ML framework.
| Tool | Primary strength | Boundary NoFutureData complements |
|---|---|---|
scikit-learn TimeSeriesSplit |
chronological train/test splits and an optional gap | does not encode when revised source data became known or eligible, and does not review arbitrary pipeline source |
| Feast | point-in-time-correct historical feature retrieval inside a feature store | assumes the feature-store workflow rather than acting as a repository-wide source/data contract guard |
Freqtrade lookahead-analysis |
behavioral lookahead detection for Freqtrade strategy backtests | is specific to Freqtrade strategies and their backtesting/data workflow |
| NoFutureData | repository-local availability contracts, source review gates, point-in-time joins, and invariance checks | deliberately does not replace model evaluation, a feature store, or a domain-specific backtesting engine |
References: scikit-learn documents why ordinary cross-validation is unsuitable
for ordered observations and exposes a gap in TimeSeriesSplit:
https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.TimeSeriesSplit.html
Feast documents point-in-time-correct joins for historical feature retrieval:
https://docs.feast.dev/getting-started/concepts/point-in-time-joins
Freqtrade documents its strategy-specific lookahead-analysis workflow:
https://docs.freqtrade.io/en/latest/lookahead-analysis/
NoFutureData deliberately combines four checks that are often handled separately:
The core has no runtime dependency and is exposed as a Python API, CLI, pre-commit hook, SARIF producer, and GitHub Action. The goal is not to replace domain-specific validation. It is to make a minimum causal boundary cheap enough to run on every pull request.
Passing NoFutureData does not prove a model, experiment, or backtest is valid. Survivorship bias, label leakage, train/test contamination, revised source data, provider publication semantics, and many domain-specific errors require separate checks. Static rules are intentionally review gates and support explicit inline suppressions for legitimate label-building code.
The public planted-leak corpus in benchmarks/ is a conformance suite for shipped
rules, not a claim of universal leakage recall. New rules should be driven by
minimal real-world reproductions and paired with a safe control.