Valuein
Methodology

Point-in-Time Accuracy

Financial backtests fail when data is available too early — you use information that wasn't publicly known at the time. Valuein timestamps every fact with accepted_at: the exact moment the SEC accepted the filing. Filter by it and your backtest is safe.

report_date
Fiscal period end
filing_date
Date filed with SEC
accepted_at
SEC acceptance timestamp

Why Most Databases Introduce Look-Ahead Bias

Most financial databases store data as it exists today, not as it was known historically. A fiscal year 2021 annual report filed in March 2022 is often backdated to December 31, 2021 — making it appear as if that data was available before it was. Backtests built on this data are invalid.

Timeline for a 2022 10-K Filing

Dec 31, 2022
report_date

Fiscal period ends. Results for the full year are computed internally. The public knows nothing yet.

Feb 15, 2023
filing_date

Company submits the 10-K to SEC EDGAR. Still not indexed in full — processing occurs over hours.

Feb 15, 2023 17:42 UTC
accepted_at

SEC accepts and timestamps the filing. This is the earliest moment any investor could have seen this data. Filter by this.

Now run a dated query against a whole filing history. Everything accepted on or before the as_of date is returned; the later restatement stays walled off — invisible, exactly as it would have been on that day.

query: get_company_fundamentals(as_of_date="2021-06-30")What a query dated 2021-06-30 returns, and what it cannot see.
  1. 10-Q Q2 2020

    accepted 2020-07-30

  2. 10-K FY2020

    accepted 2021-02-24

    as originally reported

  3. as_of · 2021-06-30

    The query stops here. Filings below were accepted later.

  4. 10-K/A FY2020

    accepted 2021-11-09

    restatement, filed later

  5. 10-Q Q3 2021

    accepted 2021-12-03

Filed by the query dateFiled later, not visibleThe 10-K/A restatement is invisible to this query. No look-ahead.

The hidden trap

If a data vendor stores this filing against fiscal_year = 2022 with no timestamp, a backtest that says "use 2022 annual data as of Jan 1, 2023" will include it — but the filing wasn't accepted until Feb 15, 2023. Your simulated portfolio used information that didn't exist yet. This introduces look-ahead bias and inflates backtest performance.

The Three Key Fields

accepted_at
fact
TIMESTAMPTZ

The exact UTC timestamp the SEC accepted the filing that disclosed this fact. Each fact row inherits accepted_at from its parent filing on indexing, so the filter works identically on either table. This is your PIT anchor — use it exclusively for backtest-safe queries. It represents the earliest moment any investor could have read this data.

Always filter: WHERE accepted_at <= your_date

filing_date
filing
DATE

The date the SEC received the filing. Very close to accepted_at but lacks the exact time component. Suitable for rough date-range filtering but accepted_at is more precise for PIT analysis.

Safe for range filtering, less precise than accepted_at

report_date
filing
DATE

The fiscal period end date (e.g. December 31 for a calendar-year company). This is NOT a PIT field — using it as a filter introduces look-ahead bias because the data wasn't known until the filing date weeks or months later.

For display purposes only — never use as a PIT filter

These tables carry accepted_at; the SDK filters every PIT view to accepted_at <= as_of.
Core financialsDerived
The point-in-time tables. 4 tables, 4 foreign-key relationships. Full text below the diagram.∞1∞1∞1∞1entity● cik name statusfiling● accession_id form_type accepted_at◇ superseded_byfact● fact_id accepted_at value_as_filed value_currentratio◇ entity_id ratio_name accepted_at is_ttm
Relationships (text)
  • filing references entity via entity_id → cik (many → 1)
  • fact references entity via entity_id → cik (many → 1)
  • fact references filing via accession_id (many → 1)
  • ratio references entity via entity_id → cik (many → 1)

Wrong vs. Right Queries

The difference between a biased and a valid backtest often comes down to a single WHERE clause.

Wrong — look-ahead bias
sql
-- WRONG: look-ahead bias.-- Meant to rank companies by fiscal 2021 revenue "as of 2022-01-01",-- but most fiscal 2021 10-Ks were filed in February and March 2022,-- and taking the latest vintage pulls in restatements filed years later.SELECT  r.symbol,  f.numeric_value / 1e9 AS revenue_billionsFROM fact fJOIN "references" r ON r.cik = f.entity_idWHERE r.is_active  AND r.is_primary_ticker  AND f.standard_concept = 'TotalRevenue'  AND f.fiscal_period    = 'FY'  AND year(f.period_end) = 2021     -- WRONG: the period is not when it was knownQUALIFY ROW_NUMBER() OVER (  PARTITION BY f.entity_id ORDER BY f.accepted_at DESC) = 1ORDER BY revenue_billions DESC;
Right — PIT-safe
sql
-- RIGHT: point-in-time safe using accepted_at.-- Each company's latest annual revenue the SEC had accepted by 2022-01-01.-- A company whose fiscal 2021 10-K came later shows its fiscal 2020 figure,-- which is exactly what an investor could see that day.SELECT  r.symbol,  f.period_end,  f.numeric_value / 1e9 AS revenue_billions,  f.accepted_at                                         -- visible timestampFROM fact fJOIN "references" r ON r.cik = f.entity_idWHERE r.is_active  AND r.is_primary_ticker  AND f.standard_concept = 'TotalRevenue'  AND f.fiscal_period    = 'FY'  AND f.accepted_at     <= TIMESTAMP '2022-01-01 00:00:00'  -- RIGHT: PIT filterQUALIFY ROW_NUMBER() OVER (  PARTITION BY f.entity_id ORDER BY f.period_end DESC, f.accepted_at DESC) = 1ORDER BY revenue_billions DESC;

Survivorship Bias

Look-ahead bias is temporal — using today's data in the past. Survivorship bias is structural — only analyzing companies that still exist today. Both inflate backtest returns and both are invisible unless your dataset is specifically built to prevent them.

Delisted companies

Valuein tracks all entities including those that were delisted, acquired, or went bankrupt. The Pro and Institutional tiers include 28,000+ entities — active and inactive.

Historical index membership

The index_membership table records an effective_date / removal_date for each company's spell in each index from 1996, reconstructed from public records, with [) interval semantics. A 2010 S&P 500 backtest uses the 2010 constituents, not today's.

PIT universe construction

Use get_pit_universe(as_of_date) to reconstruct the investable universe on any historical date — free of additions that happened after.

Delisted companies stay inBankrupt, acquired, failed or taken private: kept on Pro and Institutional.
  1. Enron Corp

    ENRNQ

    bankrupt2001

  2. Lehman Brothers

    LEH

    bankrupt2008

  3. Bear Stearns

    BSC

    acquired2008

  4. Countrywide Financial

    CFC

    acquired2008

  5. Blockbuster Inc

    BLOAQ

    bankrupt2010

  6. Whole Foods

    WFM

    acquired2017

  7. Sears Holdings

    SHLD

    bankrupt2018

  8. Twitter Inc

    TWTR

    taken private2022

  9. SVB Financial

    SIVB

    failed2023

get_pit_universe(date) returns the market as it stood on that date, not as it survived.

Survivorship-bias-free universe constructionsql
-- Survivorship-free universe: who was in the S&P 500 on 2020-03-01.-- Removal is exclusive: a company removed on that date is not a member.-- Companies removed since then are still here (their data stays on-- Pro and Institutional).SELECT  im.cik,  im.effective_date,  im.removal_dateFROM index_membership imWHERE im.index_name = 'SP500'  AND im.effective_date <= DATE '2020-03-01'  AND (im.removal_date IS NULL OR im.removal_date > DATE '2020-03-01');

PIT in the Python SDK

Create the client with as_of (a timezone-aware datetime) and every point-in-time table — fact, ratio, factor scores, earnings signals, prices and smart money — is filtered to accepted_at <= as_of. Your SQL stays the same.

pit_backtest.pypython
from datetime import datetime, timezone from valuein_sdk import ValueinClient, ValueinError sql = """SELECT f.period_end,       f.numeric_value / 1e9 AS revenue_bn,       f.accepted_atFROM fact fJOIN "references" r ON r.cik = f.entity_idWHERE r.symbol = 'AAPL'  AND r.is_active  AND f.standard_concept = 'TotalRevenue'  AND f.fiscal_period    = 'FY'QUALIFY ROW_NUMBER() OVER (PARTITION BY f.period_end ORDER BY f.accepted_at DESC) = 1ORDER BY f.period_end DESC""" try:    # as_of hides every fact the SEC accepted after 2023-01-01: no SQL filter needed.    with ValueinClient(as_of=datetime(2023, 1, 1, tzinfo=timezone.utc)) as client:        df = client.run_query(sql)        print(df)  # every accepted_at is on or before 2023-01-01         # The index as it stood on a past date, delisted members included.        print(client.pit_universe("2020-03-01").head())except ValueinError as e:    print(f"Error: {e}")

Frequently Asked Questions

Why is accepted_at sometimes later than filing_date?
The SEC processes filings asynchronously. A filing submitted on February 14 may not receive its EDGAR acceptance timestamp until late that evening or early the next day. accepted_at captures the exact time of acceptance — always later than or equal to the submission time.
Can I trust filing_date for PIT backtests?
It's usable for rough filtering but accepted_at is strictly more accurate. Some data providers conflate the two. In Valuein's schema, filing_date is a DATE (day precision) and accepted_at is a TIMESTAMPTZ (time of day included). For production backtests, always use accepted_at.
How do I handle the fact that Q2 and Q3 10-Q cash flow figures are year-to-date?
Use COALESCE(derived_quarterly_value, numeric_value) on cash flow concepts. The pipeline stores the quarter-only figure in derived_quarterly_value: the year-to-date difference for Q2 and Q3, and Q4 (the year minus the first three quarters) on the FY row. This makes all four quarters directly comparable without manual adjustments.
Does the sample tier support PIT queries?
Yes. The sample tier includes accepted_at on all fact rows. You can build and validate PIT query patterns on free sample data before moving to Benchmark, Pro or Institutional.
Is PIT enforced for AI agents too, or only in SQL?
Both. Every time-series MCP tool accepts an as_of_date and applies the same accepted_at filter server-side, so an agent physically cannot see future information. get_pit_valuation_ratios computes backtest-safe multiples (P/E, P/S, P/B, EV/EBITDA, FCF yield) on any historical date from the daily price series plus PIT fundamentals, and run_backtest composes those same PIT readers into a bounded factor/forward-return grid — point-in-time is a property of the platform, not a convention your code has to remember.

Ready to build a PIT-safe backtest?

Start with the free sample tier — all PIT fields are included. Register for the free Benchmark tier for full history on S&P 500 constituents, or upgrade for the complete universe of 28,000+ companies.

Index names are trademarks of their owners; Valuein is not affiliated with or endorsed by any index provider.