Learn
Point-in-time fundamentals: avoiding look-ahead bias
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,dividendPeriodandsharesPeriod. - 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.
01
Period end
The previous results are still used
02
Disclosure date (first publication)
New EPS, BPS and share count are used from this day
03
If the date is unknown
Used from 45 days after period end
04
Next disclosure date
Switches to the next results
Definitions
Each metric is computed from that day's split-adjusted close and the results usable on that day.
| Metric | ZENITH Code calculation | Nulls and exceptions |
|---|---|---|
| Market cap | Split-adjusted close × shares (excluding treasury stock) | If the share count is missing, issued shares are used (sharesBasis is issued) |
| PER | Split-adjusted close ÷ EPS | null when EPS is 0 or below (a loss) or not yet disclosed |
| PBR | Split-adjusted close ÷ BPS | null when BPS is 0 or below or not yet disclosed |
| Dividend yield | Dividend per share ÷ split-adjusted close (0–1 decimal) | 0 when no dividend |
basis=fy (default) | Uses full-year EPS, BPS and dividends | PER matches the screener (latest full-year EPS). PBR uses full-year BPS (the screener uses the latest quarterly BPS) |
basis=ttm | Uses trailing-twelve-month EPS and the latest quarterly BPS | Dividends 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` | Shares | PER EPS source `epsPeriod` |
|---|---|---|---|
| 2026-07-24 | 2026-03/FY | 13,033,384,474 | 2026-03/FY |
| 2026-07-31 | 2026-03/FY | 13,033,384,474 | 2026-03/FY |
| 2026-08-07 | 2026-06/Q1 | 11,841,833,660 | 2026-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.
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.announcedAtonward is conservative (later).announcedAtis 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
epsPeriodin 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,bpsPeriodanddividendPeriod, and market-cap-history hassharesPeriod, in the form2026-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.
Related articles
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.

