Skip to content
python.financial

Point-in-time data answers a strict question: what value, security identity, and universe could the strategy actually use at its decision time? The answer must exclude later revisions, restatements, corrections, constituent changes, mappings, and corporate-action facts. A period end or publication date alone is not enough if the vendor delivered the record later.

This is a data property, not a backtest-engine setting. An engine can enforce chronological delivery of the timestamps it receives, but it cannot discover that a vendor stamped a revised number with the original quarter end or omitted a delisted security.

One fact has several clocks

Time Meaning Example
Observation or effective time Period or state described by the fact Quarter ended March 31
Release time When the source disclosed it Filing accepted at 12:30 UTC
Available time When the chosen feed delivered and processed it Vendor record usable at 12:35 UTC
Decision time When the strategy read its inputs Signal evaluated at 12:36 UTC

A revision needs all of these plus a stable entity key, version identifier, and correction or deletion status. available_time <= decision_time is the minimum admissibility rule. For a strategy that decides only at scheduled intervals, its next decision boundary matters too. A 12:35 arrival does not belong in a signal frozen at 12:30.

Executed bitemporal lookup

This example stores the economic observation date separately from each release and models a five-minute vendor delay. The backward as-of join selects only the newest version available by each decision.

import pandas as pd

vintages = pd.DataFrame({
    "series_id": "GDP_Q1",
    "observation_date": pd.to_datetime(["2024-03-31"] * 3),
    "release_time": pd.to_datetime([
        "2024-04-25 12:30Z",
        "2024-05-30 12:30Z",
        "2024-06-27 12:30Z",
    ]),
    "available_time": pd.to_datetime([
        "2024-04-25 12:35Z",
        "2024-05-30 12:35Z",
        "2024-06-27 12:35Z",
    ]),
    "value": [1.1, 1.4, 1.6],
    "vintage": [1, 2, 3],
})

decisions = pd.DataFrame({
    "series_id": "GDP_Q1",
    "decision_time": pd.to_datetime([
        "2024-04-25 12:34Z",
        "2024-04-25 12:36Z",
        "2024-06-01 14:00Z",
        "2024-07-01 14:00Z",
    ]),
})

point_in_time = pd.merge_asof(
    decisions.sort_values("decision_time"),
    vintages.sort_values("available_time"),
    by="series_id",
    left_on="decision_time",
    right_on="available_time",
    direction="backward",
    allow_exact_matches=True,
)
print(point_in_time[["decision_time", "value", "vintage"]].to_string(index=False))

Executed with pandas 2.3.3:

            decision_time  value  vintage
2024-04-25 12:34:00+00:00    NaN      NaN
2024-04-25 12:36:00+00:00    1.1      1.0
2024-06-01 14:00:00+00:00    1.4      2.0
2024-07-01 14:00:00+00:00    1.6      3.0

The first decision is one minute before the modeled availability time, so it receives no value. The last decision receives the third vintage rather than rewriting the earlier rows. pandas documents that a backward merge_asof selects the last right-side key less than or equal to the left-side key. Both sides must be sorted. Use by to prevent one entity's value from leaking into another, and consider tolerance when stale values must expire.

An as-of join cannot repair false source timestamps. If available_time is really a quarter end, a midnight normalization, or the date a modern file was exported, the result is still contaminated.

Revisions are only one case

  • Fundamentals. Store fiscal period end, filing or announcement time, vendor availability, version, accounting basis, currency, and restatement status. A later restatement must not replace the number used before it arrived.
  • Macroeconomic series. Preserve vintages rather than today's revised history. FRED normally serves what is known today, while ALFRED real-time periods support queries for what was known during an earlier interval.
  • Universes and security masters. Membership needs announcement and effective times. Security identity needs stable identifiers, ticker-history intervals, exchange changes, mergers, delistings, and ticker reuse. Today's constituents or symbols cannot define yesterday's investable set.
  • Corporate actions. Announcement, ex-date, record date, payable date, and feed availability serve different purposes. A split adjustment can make a continuous price series, but it must not expose a future split or dividend to a historical signal.
  • News and alternative data. Article timestamps, exchange timestamps, collection time, vendor processing, corrections, and strategy ingestion can differ. Use the clock that bounds actual strategy access.

Adjusted historical prices deserve special care. Back-adjustment is useful for return and indicator continuity, but a provider may recompute the entire past series after a newly announced action. A research store should retain raw prices and action records, document the adjustment method, and ensure a historical decision does not infer an action that was unknown then.

Storage and query design

Prefer an append-only vintage table over an overwritten latest-value table. A useful record includes:

  • stable entity and field identifiers
  • observation or effective interval
  • source release timestamp and its precision
  • vendor arrival and local ingestion timestamps
  • version, correction, cancellation, and deletion status
  • source timezone plus a normalized UTC timestamp
  • raw payload reference, lineage, and checksum

Keep immutable raw snapshots when licensing permits it. Build derived tables reproducibly, record vendor and transformation versions, and make the as-of cutoff an explicit query argument. A daily date is not a substitute for a timestamp when the strategy trades intraday. If the source publishes only a date, state the conservative availability convention rather than inventing precision.

Tests that catch leakage

  1. Prefix invariance. Adding later source rows must not change features or decisions before their availability times.
  2. Late-revision test. A restatement inserted today must not alter an archived query cutoff from last year.
  3. Boundary test. Query immediately before, at, and after release, ingestion, market-open, and rebalance cutoffs.
  4. Universe replay. Include delisted names, historical constituent changes, ticker reuse, and securities with sparse histories.
  5. Timezone test. Exercise daylight-saving transitions, ambiguous local times, holidays, and timestamp precision.
  6. Adjustment test. Reconcile raw prices plus corporate actions with adjusted returns without leaking future actions.
  7. Snapshot replay. Rebuild a historical run from its recorded source snapshot, transformation version, and query cutoff.

What frameworks do and do not guarantee

Zipline Reloaded has bundle readers, asset lifetimes, adjustment tables, Pipeline loaders, and a session-aware simulation clock. Its bundle interface can ingest the required histories. Those mechanisms consume the dates and records supplied by the bundle. They do not create missing constituent history, filing vintages, delistings, or correct corporate-action timestamps.

QuantConnect LEAN advances a Time Frontier and emits bars at EndTime, which helps prevent a bar from arriving before its modeled close. The time-modeling documentation describes that delivery rule. Dataset behavior is still specific to each source. For example, QuantConnect says its Morningstar US Fundamental dataset uses as-originally-reported values and a filing date when present, but approximates some older file dates as 45 days after the as-of date. That documented approximation is materially different from a precise filing timestamp.

The VectorBT family can align, resample, transform, and simulate supplied data. VectorBT PRO adds broader adapters and richer alignment tools for large research workflows, but neither edition can certify a provider's vintages or reconstruct facts absent from the input. The same limit applies to any engine.

Practical acceptance checklist

Before calling a dataset point in time, verify the exact fields used by the strategy. Ask whether the vendor preserves original versions, which timestamp controls availability, how corrections and deletions work, whether delisted securities remain, how symbol changes and corporate actions are dated, and whether historical files can be reproduced. Then query a few known revisions and boundary events manually.

Point-in-time correctness is field-specific and decision-specific. A dataset can handle prices well, approximate old fundamentals, and omit historical index membership at the same time. Record those boundaries in the research report instead of assigning one blanket point-in-time label to an entire platform.

Choose which optional services may run. You can change these settings at any time.