Imagine a dashboard reporting that a company's revenue grew 75% in one year. The numbers came from financial statements. The arithmetic checks out. Nothing crashed.

There's just one problem: the dashboard compared standalone revenue from one year with consolidated revenue from the next. The resulting growth rate describes neither business consistently.

At MarketDeck, we're building a connected financial research workspace for Indian markets, including filing-backed company research, screening, interactive charts, and quantitative analysis. One design principle behind our company research is simple: a financial figure is not meaningful without its reporting context.

This article walks through a small, runnable Python example of that principle. It's a standalone teaching example using fictional numbers, not a copy of MarketDeck's production code or a claim about any real listed company.
The invisible data bug
Suppose a fictional company reports the following amounts (all in ₹ crore):
Reporting year Accounting basis Revenue
FY2024 Standalone 800
FY2024 Consolidated 1,100
FY2025 Consolidated 1,400

Two tempting calculations produce completely different stories:

  • Wrong comparison: 1,400 ÷ 800 − 1 = 75%.
  • Like-for-like comparison: 1,400 ÷ 1,100 − 1 = 27.27%. The first calculation mixes reporting bases; the second compares consolidated annual revenue with consolidated annual revenue. Even the second figure would need further review if the company's consolidation perimeter or accounting policies changed significantly.

This isn't an exotic edge case. Indian listed companies can file results in both standalone and consolidated formats. NSE also supports structured XBRL financial reporting, where units, periods and taxonomy elements matter. A dashboard that discards those fields loses information it needs to compare figures responsibly.
Treat every number as a record, not a float
The usual toy data model is something like:
revenue = 1400

That's fine for a one-line calculation. For a research application, it is under-specified. We should be able to answer:

  • Which issuer and metric does this number belong to?
  • Which fiscal period does it represent: quarter, full year or trailing twelve months?
  • Is it standalone or consolidated?
  • Which currency and unit are being used?
  • When did the result become publicly available?
  • Which filing or record supports it? Here's one deliberately minimal Python model that keeps those answers attached. It uses only the standard library and runs on Python 3.10+.
"""Standalone, synthetic demonstration for the MarketDeck DEV article. Not production MarketDeck source code. Python 3.10+; no external dependencies. """ from dataclasses import dataclass from datetime import date, datetime from decimal import Decimal @dataclass(frozen=True) class Fact: issuer: str metric: str period_end: date period_type: str # FY, Q, TTM, etc.  basis: str # standalone or consolidated  units: str # INR crore, INR lakh, etc.  amount: Decimal published_at: datetime # timezone-aware public availability timestamp  source_id: str def find_fact(facts, *, issuer, metric, period_end, basis, as_of): if as_of.tzinfo is None or as_of.utcoffset() is None: raise ValueError("as_of must have a timezone") eligible = [ f for f in facts if f.issuer == issuer and f.metric == metric and f.period_end == period_end and f.period_type == "FY" and f.basis == basis and f.units == "INR crore" and f.published_at <= as_of ] if not eligible: raise LookupError("No comparable fact known by this date") # In a real dataset, explicitly model revisions/supersession.  return max(eligible, key=lambda f: f.published_at) facts = [ Fact( "FictionalCo", "revenue", date(2024, 3, 31), "FY", "standalone", "INR crore", Decimal("800"), datetime.fromisoformat("2024-05-10T18:00:00+05:30"), "DEMO-2024-ST", ), Fact( "FictionalCo", "revenue", date(2024, 3, 31), "FY", "consolidated", "INR crore", Decimal("1100"), datetime.fromisoformat("2024-05-15T18:00:00+05:30"), "DEMO-2024-CON", ), Fact( "FictionalCo", "revenue", date(2025, 3, 31), "FY", "consolidated", "INR crore", Decimal("1400"), datetime.fromisoformat("2025-05-20T18:00:00+05:30"), "DEMO-2025-CON", ), ] as_of = datetime.fromisoformat("2025-06-01T12:00:00+05:30") prior = find_fact(facts, issuer="FictionalCo", metric="revenue", period_end=date(2024, 3, 31), basis="consolidated", as_of=as_of) current = find_fact(facts, issuer="FictionalCo", metric="revenue", period_end=date(2025, 3, 31), basis="consolidated", as_of=as_of) growth = (current.amount / prior.amount - Decimal("1")) * Decimal("100") print(f"Comparable revenue growth: {growth:.2f}%") print(f"Sources: {prior.source_id} -> {current.source_id}") # As of April 2025, the FY2025 number has not yet been published. try: find_fact(facts, issuer="FictionalCo", metric="revenue", period_end=date(2025, 3, 31), basis="consolidated", as_of=datetime.fromisoformat("2025-04-01T12:00:00+05:30")) except LookupError: print("Early query: correctly rejected an unpublished figure") else: raise AssertionError("Look-ahead check failed") # A naive implementation using FY2024 standalone revenue gives an invalid 75%. naive_mixed_basis_growth = (Decimal("1400") / Decimal("800") - 1) * 100 assert naive_mixed_basis_growth == Decimal("75") assert growth.quantize(Decimal(".01")) == Decimal("27.27") 

Expected output:
Comparable revenue growth: 27.27%
Sources: DEMO-2024-CON -> DEMO-2025-CON
Early query: correctly rejected an unpublished figure

All DEMO-* identifiers and numbers above are invented for the tutorial. They are not exchange filing identifiers or actual stock-market data.
What the code protects against

  1. Mixed accounting bases. The selector requires the same basis for both years. A standalone figure cannot quietly enter a consolidated comparison.

  2. Mixed reporting periods. It asks explicitly for an FY observation and matches a specified fiscal year-end. In a production system, quarters, year-to-date amounts and trailing-twelve-month values need equally explicit period types and duration checks. The same date alone is not sufficient to establish that two figures have the same reporting duration.

  3. Mixed units. It requires a declared unit. A production implementation should also normalise values carefully—₹ lakh, ₹ crore, INR, and USD are not interchangeable. The unit filter here is deliberately strict rather than performing conversions silently.

  4. Look-ahead leakage. published_at <= as_of keeps figures unavailable at the simulated query time out of the result. Fiscal year-end is not the same thing as publication date. For event-driven simulations, the exact publication/dissemination time and the next executable market session can both matter.

  5. Untraceable output. The calculation returns source identifiers beside the result. In a real application, that identifier should resolve to a specific original filing and, where possible, the relevant statement and accounting element.

There's an important limitation here: a source link is necessary but not enough. A restatement, changed consolidation perimeter, incorrect taxonomy mapping or missing filing could still make a number economically non-comparable. If your system ingests amendments, it needs explicit revision/supersession handling. Simply choosing the latest available record works only if your dataset models and validates that policy.
How that changes the UI
A trustworthy dashboard shouldn't make readers reverse-engineer a headline metric. Alongside a growth percentage, I'd want to display something like:
Field Research UI should explain
Value 27.27% (illustrative)
Comparison FY2025 vs FY2024
Basis Consolidated → consolidated
Inputs ₹1,400 crore and ₹1,100 crore
Availability Dates both records were first public
Evidence Original filings and financial-statement elements
Exceptions Missing data, revisions or comparability warnings

This is not about making interfaces unnecessarily complicated. It's about giving users a clean headline and a way to inspect it when the detail matters.

At MarketDeck, our existing Research Terminal connects financial history with reporting context, valuation, peer research and source tracing. Our company research also includes Source Trace ratio cards designed to show formulas, periods and missing-input explanations. The example in this post is intentionally simplified; it illustrates the design reasoning rather than documenting the internal implementation line-for-line.
Three test cases I'd add before shipping
The script already tests one incorrect accounting comparison and one too-early query. A production data pipeline needs more checks:

  1. Restatement test: a later amended filing must not overwrite the earlier as-of history retroactively.
  2. Context test: annual, quarterly, year-to-date and trailing values must not become substitutes just because their end dates align.
  3. Provenance test: missing source records, mismatched currencies or incompatible reporting bases must produce a visible missing/uncertain result—not a fabricated zero or silent fallback. Also worth testing: fiscal-year changes, mergers, revised taxonomy mappings, stale observation windows and timezone handling around market close.

The aim is not to promise that every financial number can be made perfectly comparable. It is to make the conditions under which it is comparable inspectable.
Bigger lesson for developers
It's easy to spend most of our time polishing the front end of a financial dashboard: chart animations, filters, and fast search. Those things matter. But a chart can be beautifully rendered and still answer the wrong question.

Once a system tracks what was reported, for which period, on which basis, when it became known, and where it came from, the product becomes more useful for more than charts. The same structured evidence can support human research, screening, reproducible experiments and—eventually—AI-assisted interfaces that need grounded numbers instead of plausible-sounding guesses.

That's the direction we're building toward at MarketDeck: accessible quantitative research, with the context needed to question the output. The broader AI-connected experimentation and data-access vision remains future work, not something this demo claims is already live.
Explore MarketDeck: See source-aware research in practice
Building financial tools or learning to investigate Indian companies? Explore MarketDeck, an India-first financial research platform combining company fundamentals, stock screening, charting, derivatives analysis, portfolio research and interactive mathematical tools.

  • Research Terminal: Work through company financial history and reporting context, examine valuation and peers, and follow links back to filing evidence.
  • MarketDeck Screener: Explore Indian companies with screening and company-research tools rather than relying on a single unexplained metric.
  • Research Standards: Read how MarketDeck describes methodology, data limitations, provenance and research boundaries. Try the current platform → marketdeck.in. We're building toward a more integrated quantitative workspace with AI-assisted research and permissioned data services. Those broader integrations are our direction, not an end-to-end product claimed to be live today.

If you build data-heavy products, what's the most subtle “valid data, wrong interpretation” bug you've encountered?
References and further reading

  • NSE: XBRL filing information — financial-report taxonomy, period and unit context.
  • NSE: Corporate filings announcements — filing and dissemination timestamps.
  • NSE: Integrated Financial Filing circular (April 2025) — evolving PDF and XBRL filing processes.
  • MarketDeck Research Terminal — a working example of company research with sources and reporting context. Educational and software-engineering content only. No investment recommendations. All demonstration amounts are fictional.