The A5 parity report surfaced coverage gaps and wrong values that all traced to the SEC facts parser and read-time derivation rather than to bad source data. Fixes, each validated by replaying the production parser + derivation against live company facts: - Period identity is derived from period_end against the issuer's fiscal calendar, not SEC's fy/fp fields, which collide (two period ends on one key, one silently discarded) and invert (a period sorting before one that precedes it) often enough to break the quarter chain. Recovers BXP, CRM, CRWD, FRT, MTD, NTAP, PPL, STX, WDAY. Fixed labels are internal ordering keys only (not in any API schema), so a filer whose year ends in early January shifting by one is harmless. - Revenue concept list gains RevenuesNetOfInterestExpense (banks) and the IncludingAssessedTax variant (REITs/consumer); EPS gains the continuing-ops variant (REG/FCX) and, last, basic EPS for a period tagging no diluted variant at all (PPL). All appended, so any issuer that already resolved keeps its concept. - YTD span tolerance 20 -> 25 days, covering 4-4-5 retail calendars whose 36-week YTD-Q3 (251-252d) previously missed by ~2 (COST, PEP, DPZ). - Amendment resolution is per field: a partial 10-K/A (Part III only, no financial facts) no longer blanks the period (DVN). - TTM diluted EPS is suppressed when a split contaminates the trailing window (BKNG's mixed-unit sum produced a P/E of 1.10 that clamped to a perfect fundamental sub-score). A post-filing split with no share-count evidence (KLAC) remains undetectable from this data. - Multi-class share fallback: weighted_avg_diluted_shares is captured and used for market cap when the cover-page count is absent (dimensional, so missing from company facts for META/CMCSA/CHTR/FOXA/NWSA/LEN). Within ~0.6% of the true count on controls; flagged shares_estimated in the API. BRK-B has no weighted-average fact either and stays unavailable. 820 unit tests pass; new tests confirmed to fail against the pre-fix code. Effect is inert until existing rows are reparsed (see reparse path). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
44 lines
1.6 KiB
Python
44 lines
1.6 KiB
Python
"""fundamental_snapshots.weighted_avg_diluted_shares — market-cap fallback
|
|
|
|
Revision ID: 027
|
|
Revises: 026
|
|
Create Date: 2026-07-24 00:00:00.000000
|
|
|
|
Multi-class issuers report the cover-page share count per share class. That is a
|
|
dimensional fact and Company Facts is non-dimensional, so it is absent entirely:
|
|
META has never tagged it, CMCSA stops in 2009, BRK-B in 2011, CHTR in 2016 (when
|
|
the Time Warner Cable deal made it multi-class). `shares_outstanding` is
|
|
therefore null for a large slice of the mega-cap universe, which silently removes
|
|
both `market_cap_est` and `fcf_yield`.
|
|
|
|
The weighted-average diluted count is always present (EPS requires it) and is
|
|
consolidated across classes. Measured against issuers where the true
|
|
point-in-time count IS available, it lands within ~0.6%: GOOGL 0.9936, MRNA
|
|
1.0045, AAPL 0.9974, MSFT 0.9978.
|
|
|
|
Stored as its own column rather than backfilled into `shares_outstanding`, so the
|
|
point-in-time column keeps its strict meaning and the fallback stays an explicit,
|
|
labelled read-time decision. Existing rows are null until a reparse.
|
|
"""
|
|
from typing import Sequence, Union
|
|
|
|
from alembic import op
|
|
import sqlalchemy as sa
|
|
|
|
|
|
revision: str = "027"
|
|
down_revision: Union[str, None] = "026"
|
|
branch_labels: Union[str, Sequence[str], None] = None
|
|
depends_on: Union[str, Sequence[str], None] = None
|
|
|
|
|
|
def upgrade() -> None:
|
|
op.add_column(
|
|
"fundamental_snapshots",
|
|
sa.Column("weighted_avg_diluted_shares", sa.Float(), nullable=True),
|
|
)
|
|
|
|
|
|
def downgrade() -> None:
|
|
op.drop_column("fundamental_snapshots", "weighted_avg_diluted_shares")
|