Skip to main content

ere

CI PyPI Python

Point-in-time data operations for Polars. Prevent look-ahead bias in quantitative research and backtesting.

The problem

When you join quarterly earnings onto daily prices using a naive merge, every row gets the final value, including restated figures that weren't published yet. Your backtest sees the future and the results are meaningless.

Standard tools have no concept of when a data point became known. ere fixes this by tracking two dates per row:

  • ref_date: when the event occurred (e.g. fiscal quarter end)
  • knowledge_date — the date you actually had it (e.g. SEC filing date)

After any as_of() call, every row satisfies knowledge_date <= query_date. No future information leaks.

Install

pip install ere

Requires Python >= 3.12 and Polars >= 1.0.

Quick start

from datetime import date
import polars as pl
import ere

PRICES = ere.TemporalSpec(ref_date="date", entity="ticker")
EARNINGS = ere.TemporalSpec(
    ref_date="fiscal_quarter_end",
    knowledge_date="filing_date",
    entity="ticker",
)

ere.validate(prices_df, spec=PRICES)
ere.validate(earnings_df, spec=EARNINGS)

# What did we know on Feb 1?
snap = ere.as_of(earnings_df, query_date="2025-02-01", spec=EARNINGS)
# AAPL shows original filing (1.50), not the restatement filed Feb 20 (1.42)

snap_later = ere.as_of(earnings_df, query_date="2025-03-01", spec=EARNINGS)
# now AAPL shows 1.42, the restated value

# Multi-source snapshot at one date
combined = ere.as_of(
    [(prices_df, PRICES), (earnings_df, EARNINGS)],
    query_date="2025-02-15",
)

# Multi-date snapshots for backtesting
rebalance_dates = [date(2025, 1, 31), date(2025, 2, 15), date(2025, 2, 28)]
snapshots = ere.panel(prices_df, spec=PRICES, dates=rebalance_dates, lookback=252)

# Post-hoc audit
ere.audit(earn_snap, as_of_date="2025-02-15", knowledge_date_col="filing_date")

API

Function Purpose
as_of(df, query_date, spec) * Point-in-time snapshot, filtered to what was known at query_date
panel(df, spec, dates) * Multi-date snapshots; returns {date: DataFrame}
panel_iter(df, spec, dates) * Iterator over panel(), yielding (date, DataFrame)
panel_lazy(df, spec, dates) * Fully lazy version. Single inequality join under the hood, tagged by query date
panel_map(df, spec, dates, fn) * Apply a Python function to each snapshot (for logic that doesn't fit as Polars expressions)
validate(df, spec) Check temporal structure (columns, dtypes, no nulls, no time travel)
audit(df, as_of_date) Assert no look-ahead leakage in a result frame
tag_knowledge_date(df, ...) Add a knowledge_date column from a fixed lag
deduplicate(df, spec) Remove duplicate versions
align(sources, date) Per-source PIT snapshots at one date

* Also accepts a list/dict of (frame, spec) sources; see Multi-source snapshots below.

Key concepts

TemporalSpec binds your column names to temporal roles. Define it once per dataset:

SPEC = ere.TemporalSpec(
    ref_date="fiscal_quarter_end",  # when the event happened
    knowledge_date="filing_date",   # when it became known
    entity="ticker",                # optional grouping key
)

Restatements are handled automatically. If a data point is published multiple times (same entity + ref_date, different knowledge_dates), as_of() returns the latest version that was known at the query date.

Multi-source snapshots. Pass a list (or dict) of (frame, spec) pairs anywhere a single (frame, spec) goes. Each source is PIT-aligned independently, then asof-joined into one frame:

sources = [(prices_df, PRICES), (earnings_df, EARNINGS)]

snapshot = ere.as_of(sources, "2025-02-15")            # joined point-in-time view
panels   = ere.panel(sources, dates=rebalance_dates)   # multi-date snapshots

# Entity-less specs (no `entity=`) broadcast across entities automatically:
MACRO = ere.TemporalSpec(ref_date="release_period", knowledge_date="release_date")
with_macro = ere.as_of([*sources, (macro_df, MACRO)], "2025-02-15")

# Want them separate instead of merged? Use align:
per_source = ere.align(sources, "2025-02-15")          # -> [prices_snap, earn_snap]

Examples

Runnable end-to-end scripts live in examples/:

  • quickstart.py — end-to-end backtest walkthrough: restatements, naive-join leakage, multi-date rebalancing.
  • multi_source.py — list/dict sources, entity-less broadcasting, panel/panel_iter/align.
  • panel_lazy.py — benchmarks as_of() loop vs panel_lazy/panel_map on second-granularity orderbook data.

Run any of them with uv run python examples/<name>.py.

License

MIT

Metadata

Release files for ere 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ere 0.3.0
File Size Uploaded Provenance
ere-0.3.0.tar.gz 12.1 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for ere 0.3.0
File Interpreter ABI Platform
ere-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 29.5 kB

Release files / ere-0.3.0.tar.gz

Download URL ere-0.3.0.tar.gz
Size 12.1 kB
Tags Source
SHA-256 checksum
How to use checksums
cf0dbdd58d0409858d1bc405a13b31296a3682ee955da857a93783ad1de8c8c8
BLAKE2b-256 checksum
How to use checksums
18c811318bbf0afed027a5d335f83a599cae041117319e192e9c462680196f46
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 23, 2026.

Transparency log

Release files / ere-0.3.0-py3-none-any.whl

Download URL ere-0.3.0-py3-none-any.whl
Size 17.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e1ae97d543791714f021277d09b12ecc5fc90a38e7e0fc603614429fd19e7295
BLAKE2b-256 checksum
How to use checksums
7b5d303cd779eac4edc769f6b5c9ad9fd54e3a0a98a91fb80cc65d6aadad3da5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 23, 2026.

Transparency log

Security for ere 0.3.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for ere-0.3.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 23, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page