Keep useful stock research when consensus earnings data is missing
Missing consensus earnings data does not automatically invalidate every broker report returned by a research request. Treat reports and consensus as separate evidence blocks. Continue calculations supported by individually verified reports, keep market consensus fields empty and explicitly block the conclusions that need them. An empty consensus array establishes neither zero earnings nor a company with no analyst coverage.
This guide runs a fictional A-share packet through a small Python handler. It preserves two usable broker valuation rows while refusing three consensus-dependent outputs. It is an educational adapter example, not a live provider test or an available CoTrading automation feature. A future research workbench would need verified provider contracts, durable storage and operational monitoring before offering this behavior to users.
Diagnose the packet before interpreting the business
A successful transport response and a useful research response are different observations. An outer success flag may mean that one report source returned data even when a second consensus source failed or returned nothing. Inspect each block, its shape and its provenance before summarizing the company. Do not convert a partially populated response into an overall statement that earnings expectations were unavailable everywhere.
The local research-tool implementation examined for this workflow concerns A-share reports and a separate best-effort consensus lookup. Report windows and result limits restrict what it can observe. A successful report fetch can therefore coexist with an empty consensus block. This static code observation does not establish why a particular live request was empty, whether a provider was unavailable or how many analysts cover the security.
Use a normalized packet between the provider and the calculation layer. The downloadable example expects ok, a data object, a report list and a consensus_eps block. Report rows have explicit identifiers, brokers, fiscal years, currencies, earnings bases and source references. This schema is intentionally defined for the tutorial; raw tool responses require a separately tested adapter rather than being assumed interchangeable.
Keep four kinds of absence separate
Record the following consensus states before calculating anything:
| Input | Example status | Supported interpretation |
|---|---|---|
| Missing field or null | missing_block | No usable block was supplied |
| Empty list | empty_cause_unverified | The supplied block contains no observations |
| Object instead of list | invalid_block_shape | The packet does not meet this contract |
| Nonempty list | requires_separate_provider_context_check | Coverage and definitions still require verification |
The final row deliberately stops short of accepting a market estimate. Having one value is insufficient evidence about contributor coverage, aggregation method, fiscal period or revision timing. This handler verifies the missing-data branch; it does not implement the complete successful-consensus branch. Extending that branch requires new fixtures and a documented provider definition.
Python’s JSON documentation explains the corresponding object, array and null representations. Those representations support structural validation, not financial interpretation. A null becomes None, but its cause still comes from the research record. Never infer a provider outage solely from a null or an empty array.
Calculate the broker-specific rows that remain usable
Freeze a synthetic quote of CNY20 and target fiscal year 2027. Broker B1 supplies diluted EPS of CNY1.2 per share; broker B2 supplies CNY1.4 per share. Both source references are fictional fixtures. They are not recommendations, actual reports or an assertion that these earnings will occur.
| Report | Broker | EPS | Supported forward PE |
|---|---|---|---|
| r1 | B1 | 1.2 | 20 / 1.2 = 16.6667 |
| r2 | B2 | 1.4 | 20 / 1.4 = 14.2857 |
These are two broker-specific scenarios under a frozen price. They are not two observations of the market consensus. Keep the fiscal year and source on each result, retain full precision internally and round only for display. The script uses decimal arithmetic; its assertions compare the computed ratios with the exact decimal divisions rather than rounded strings.
The fixture assumes the adapter has established the per-share unit and security identity. Before adapting real data, verify those fields alongside currency, diluted versus basic earnings, publication time and forecast availability at the research cutoff. Mixing a total-profit forecast with a share price produces a meaningless ratio even if both inputs are valid numbers.
Block dependent outputs rather than filling them with a proxy
The handler leaves market_consensus_eps and consensus_pe as None. Its blocked list also includes earnings_surprise_vs_consensus. These are intentional omissions: none can be supported by the empty block. The available report rows retain their calculated status, so the user can inspect what remains useful without confusing it with the blocked comparison.
Do not average 1.2 and 1.4 and call 1.3 the market consensus. A limited response may omit other brokers, duplicate the same institution or contain forecasts from different dates. Even a correctly calculated mean of this sample would describe this sample only. The executable explicitly records report_mean_substituted: false and asserts that both market-level fields remain empty.
Present the output as a partial research result, followed by the supported report table and the three blocked dependencies. Attach an unresolved-data task for verifying the consensus provider. Avoid an overall green completion label that suggests all requested analysis ran. Equally, avoid discarding the verified report calculations merely because one independent source is missing.
Run the missing-data path and its counterexamples
Download the complete executable example, save it as R560.py and run:
python -I -B R560.py
It uses the Python standard library and synthetic in-memory input. No API credentials, model calls or historical forecast downloads are involved. Read the resulting partial, invalid_values, outer_failure and empty sections. A zero exit code means the embedded assertions passed for these fixtures; it does not certify an external service or the financial reliability of an actual report.
The main path checks both broker ratios and the consensus omissions. A second packet contains a nonfinite EPS and a zero EPS, with a malformed consensus block. Both report rows keep a null PE but receive different rejection states. A failed outer packet returns tool_failed and blocks every calculation. An empty report list returns no_usable_report_rows, rather than pretending that an empty table is a completed company assessment.
The Decimal finite check matters because a successfully parsed value can still be NaN or infinity. Reject those before division. A nonpositive EPS is a different issue: the example labels the PE unavailable for this workflow rather than manufacturing a conventional positive multiple. Neither case should be silently converted to EPS zero.
Define the recovery and publication contract
When the missing source later returns, create a new research version with its own retrieval time and evidence. Verify the consensus definition before enabling the blocked calculations. Preserve the earlier partial version so readers can distinguish the information available then from the information available now. A later estimate must not silently enter a historical decision record.
Keep provider exceptions separate from row-level validation failures. This small handler expects normalized required report fields; malformed identities should be rejected by the adapter before calling it. It is not a general parser for arbitrary packets. A production extension should add explicit coverage counts, duplicate handling and row rejection records, with fixtures covering the exact schema promised to callers.
Before publishing a partial result, confirm that each displayed number traces to a usable source row, that missing market-level fields remain empty and that blocked tasks are visible beside the result. Record the frozen price and target year. The useful deliverable is an honest, reproducible subset of the requested research, with a precise route to completing the missing part.
Keep a control packet for future changes
Store the empty-consensus fixture with its expected blocked fields when extending the adapter. A new provider integration should not change those fields merely because report parsing became more permissive. Re-run the outer-failure and invalid-EPS cases as well, so improvements to one source cannot accidentally publish unsupported market-level numbers from another branch.
FAQ
Does an empty consensus list prove that no analysts cover the stock?
No. It only shows that this packet supplied no consensus observations. Coverage, permissions and provider failures require separate evidence.
Can I replace consensus with the average of the reports I received?
You can label a separately checked sample statistic as such, but this example does not calculate one. It must not be presented as market consensus or used to unlock consensus-dependent conclusions.