Get free API key

Learn

Point-in-time fundamentals: avoiding look-ahead bias

If a backtest uses results that had not been published yet on a given day, performance looks better than it really was. This guide explains how ZENITH Code's histories use each fiscal period only from its disclosure date, and what they can and cannot do.

eventExample values are taken from API responses as of October 23, 2026. Financial and dividend data are refreshed daily, keyed to 16:30 (TDnet) and 19:00 (EDINET), Japan time.

What you will learn

  • check_circlemarket-cap-history and valuation-history use each fiscal period from its disclosure date. Before that date, the previous period is still used.
  • check_circleWhich period was used is shown in epsPeriod, bpsPeriod, dividendPeriod and sharesPeriod.
  • check_circleWhat is guaranteed is when a period becomes usable. Values are the latest ones, reflecting later annual reports and corrections; first-published versions are not stored.

What look-ahead bias is

Look-ahead bias means using information on a past date that only became known later.

Results for a March fiscal year are not public on March 31. Join them by period-end date and, for the one to two months until the May release, you select stocks using future numbers.

The error is especially common in metrics that combine prices and results, such as PER and PBR.

How ZENITH Code handles it: results from the disclosure date

For market cap and valuation histories, each day uses the fiscal period with the latest period end among those disclosed on or before that day.

  • Disclosure date: the earliest publication time on or after the period end recorded in the period's source information. Usually the earnings summary date.
  • Unknown disclosure date: the period is used from 45 days after period end (the customary deadline for earnings summaries).
  • Price dates before the disclosure date: the previous period is still used. The switch happens on the disclosure date.
  • Split adjustment: prices, per-share values and share counts are all on today's share basis, so metrics do not jump on split dates.
  1. 01

    Period end

    The previous results are still used

  2. 02

    Disclosure date (first publication)

    New EPS, BPS and share count are used from this day

  3. 03

    If the date is unknown

    Used from 45 days after period end

  4. 04

    Next disclosure date

    Switches to the next results

Each day uses the latest-ending period disclosed on or before it (no values shown).

Definitions

Each metric is computed from that day's split-adjusted close and the results usable on that day.

MetricZENITH Code calculationNulls and exceptions
Market capSplit-adjusted close × shares (excluding treasury stock)If the share count is missing, issued shares are used (sharesBasis is issued)
PERSplit-adjusted close ÷ EPSnull when EPS is 0 or below (a loss) or not yet disclosed
PBRSplit-adjusted close ÷ BPSnull when BPS is 0 or below or not yet disclosed
Dividend yieldDividend per share ÷ split-adjusted close (0–1 decimal)0 when no dividend
basis=fy (default)Uses full-year EPS, BPS and dividendsPER matches the screener (latest full-year EPS). PBR uses full-year BPS (the screener uses the latest quarterly BPS)
basis=ttmUses trailing-twelve-month EPS and the latest quarterly BPSDividends stay annual. Switches every quarter

Prices start in January 2010. Each request covers up to 10 years.

Example: Toyota Motor (7203) share count switch

In Toyota's weekly market cap history, the share-count source (sharesPeriod) switches on the August 7, 2026 row. It is the first week-end after the Q1 earnings summary for the fiscal year ending March 2027, published on August 4, 2026.

Before that, the full-year share count for the fiscal year ended March 2026 (13,033,384,474 shares) is used; after it, the Q1-end count (11,841,833,660 shares).

PER over the same weeks (basis=fy) uses full-year results only, so epsPeriod stays at 2026-03/FY. Use basis=ttm to switch every quarter.

Date (last trading day of week)Share source `sharesPeriod`SharesPER EPS source `epsPeriod`
2026-07-242026-03/FY13,033,384,4742026-03/FY
2026-07-312026-03/FY13,033,384,4742026-03/FY
2026-08-072026-06/Q111,841,833,6602026-03/FY

Shares exclude treasury stock. Source: /stable/market-cap-history and /stable/valuation-history (symbol=7203, interval=weekly) as of October 23, 2026. Price-based values are not shown.

Using the API

Request a date range and a sampling interval (interval = daily, weekly or monthly). In a backtest, attach to each decision date the latest row on or before that date.

Example
curl -sG "https://api.zenithcode.net/stable/valuation-history" \
  --data-urlencode "symbol=7203" \
  --data-urlencode "from=2025-01-01" \
  --data-urlencode "to=2025-12-31" \
  --data-urlencode "interval=monthly" \
  --data-urlencode "basis=ttm" \
  -H "x-api-key: YOUR_API_KEY"

Python: attach only values known by each month-end decision date

import requests
import pandas as pd

BASE = "https://api.zenithcode.net/stable"
HEADERS = {"x-api-key": "YOUR_API_KEY"}

def get(path, **params):
    r = requests.get(f"{BASE}{path}", params=params, headers=HEADERS, timeout=30)
    r.raise_for_status()
    return r.json()

# Daily PER / PBR built only from results disclosed on or before each date
val = pd.DataFrame(get("/valuation-history", symbol="7203", basis="ttm",
                       **{"from": "2021-01-01", "to": "2025-12-31"}))
val["date"] = pd.to_datetime(val["date"])

# Your decision dates (e.g. month-end rebalancing)
signals = pd.DataFrame({"date": pd.date_range("2021-01-31", "2025-12-31", freq="ME")})

# merge_asof attaches the latest row on or before each date: no look-ahead
panel = pd.merge_asof(signals, val.sort_values("date"), on="date", direction="backward")
print(panel[["date", "per", "pbr", "epsPeriod", "bpsPeriod"]].tail())

What it does not do

ZENITH Code guarantees which period is used and from when. Account for the following yourself.

  • Value versions are not stored. When an annual report or a correction replaces a value, past dates use the replaced value too. It is not exactly the number visible at the time.
  • The disclosure date is the first publication. Values confirmed by the annual report are used from the summary date, so for companies whose summary and annual report differ, the gap between the two dates is affected.
  • Financial endpoints return the latest values. If you join income-statement yourself, using each row from provenance.announcedAt onward is conservative (later). announcedAt is the publication time of the current source, so periods replaced by the annual report carry its date.
  • Prices start in January 2010. Market cap and PER histories cannot be built before that.

FAQ

For investors and developers

Which results is PER based on the day before an earnings release?
The previous ones. New results are used from their disclosure date, so until the day before the release PER uses the previous period's EPS. Check epsPeriod in the response.
What happens to PER in a loss-making period?
It is null. PER is not computed when the EPS usable on that day is 0 or below.
Are share buybacks reflected in market cap?
Yes. Shares come from the latest disclosed period, excluding treasury stock, so a buyback shows up from the disclosure date of the next results.

For AI builders and researchers

Is this strict point-in-time data?
Timing is point-in-time: each period is used from its disclosure date. Values, however, are the latest version. First-published vintages are not stored, so later corrections and annual-report replacements also apply to past dates.
Can I check programmatically which results were used?
Yes. Each row of valuation-history has epsPeriod, bpsPeriod and dividendPeriod, and market-cap-history has sharesPeriod, in the form 2026-03/FY.
How are periods without a recorded disclosure date handled?
They are used from 45 days after period end, a conservative choice aligned with the customary deadline for earnings summaries.
gavel

Disclaimer

This guide explains how the data works and how to use the API. It does not recommend buying or selling any security and is not investment advice. Example values reflect responses at the time of writing and may change with later filings or corrections. Investment decisions are your own responsibility.