Debug a stock screener that returns no results
An empty stock screen can mean that no company satisfies the request, that the stored thresholds use the wrong units, or that the required observations are unavailable. Those situations need different responses. Preserve the original screen, inspect its inputs, and run small diagnostic experiments before changing any investment requirement. Producing more names is not itself a successful repair.
This guide uses three fictional stocks to distinguish a genuine empty intersection from a percentage-unit error and incomplete coverage. The script performs the proposed calculations locally with synthetic inputs. It does not call a market provider, evaluate historical returns or demonstrate an existing CoTrading troubleshooting page.
Preserve a baseline that can be repeated
Save the stock universe, source snapshot, cutoff date, rule version, operators and thresholds. Record whether the first run actually completed. A failed request that returns an empty array must not be summarized as a successful search with zero candidates. Keep transport status separate from the count of evaluated stocks.
Our confirmed screen requires PE strictly below 20 and annual revenue growth at least 10%. Growth is a ratio, so the stored floor is 0.10. The synthetic universe contains AAA with PE 18 and growth 0.08, BBB with PE 24 and growth 0.15, and CCC with PE 30 and missing growth. Both required fields are available for two of the three rows. All values here are fictional and use the agreed definitions.
Run this baseline without edits. AAA fails growth, BBB fails PE and CCC lacks a growth observation while already failing PE. The known complete observations yield no candidate. The missing observation still belongs in the coverage report: it is a different fact from a measured growth value below the floor.
Check units before relaxing requirements
Compare the condition table against the data dictionary. A request for 10% growth can be represented by 10 in percentage points or by 0.10 as a ratio. Either convention can work if the field and threshold agree. Applying a threshold of 10 to ratio-valued growth means requiring 1,000%, a different economic condition.
Inspect a few raw rows before deciding which convention the source uses. Preserve the original string and the normalized numeric value. Do not infer units only because the largest observed value looks small: a weak company could actually have low growth, and a percentage column can contain unusually large values. Unit metadata is stronger evidence than a distributional guess.
The SEC EDGAR API documentation is one official example of financial facts retaining unit and period context. It does not define the fields of an arbitrary screening provider. Check the documentation and underlying disclosures for the actual source you use. A unit repair changes the implementation to match the confirmed requirement; a relaxation changes the requirement itself. Keep separate records for those actions.
Measure individual conditions and their intersection
Build a diagnostic table with total rows, observed rows, passing rows and unknown rows for each field. In this fixture, the PE condition passes AAA alone. The growth condition passes BBB among the two observed growth rows. Neither fact implies that their intersection contains a stock. The candidates passing different conditions are different companies.
| Experiment | PE rule | Growth rule | Passing stocks |
|---|---|---|---|
| Original | below 20 | at least 0.10 | none |
| Relax PE only | below 25 | at least 0.10 | BBB |
| Relax growth only | below 20 | at least 0.05 | AAA |
Sequential attrition counts can help locate where the remaining set becomes empty, but they depend on condition order. Also examine each condition on the original universe. A rule applied late can appear harmless simply because an earlier rule already removed its failures. The two views answer different diagnostic questions and should not be confused.
Run one-condition experiments
Keep the saved baseline immutable and create named proposal configurations. Each proposal changes one numerical requirement while leaving the data, universe and other requirements fixed. This makes the recovered candidates attributable to that change. The researcher can then decide whether the broadened scope still answers the original question.
def screen(pe_limit=20, growth_floor=.10):
return [r["symbol"] for r in rows
if r["growth"] is not None
and r["pe"] < pe_limit
and r["growth"] >= growth_floor]
baseline = screen()
pe_proposal = screen(pe_limit=25)
growth_proposal = screen(growth_floor=.05)
The complete standard-library fixture is docs/growth/research/round-5/examples/R522.py. Its executed output is baseline [], PE-only proposal ["BBB"], growth-only proposal ["AAA"], with growth coverage 2/3. Assertions also check that a ratio threshold of 10 returns no results and that rerunning the original function still returns the unchanged baseline. The comparison uses values away from rounding boundaries; for exact financial thresholds, the Python decimal documentation describes a suitable explicit decimal representation.
Download the complete example. Use Python 3.12+ with the standard library only; all inputs are synthetic. After downloading, run python R522.py.
The script’s missing-value guard prevents unsupported rows entering the passing list. It is not a complete three-state reporting engine: a production diagnostic should separately list known failures and unresolved records, including each failed or missing condition. Preserve that limit when reusing this short example.
Separate a data repair from a genuine policy choice
Consider the unit-error counterexample. If the stored growth floor is 10 but the confirmed request and data dictionary say ratio-valued 10%, correct the implementation to 0.10 and label the action a unit repair. In this fixture, the repaired screen still has zero candidates. That is useful evidence: the unit bug was real, yet it did not fully explain the empty result.
By contrast, reducing the confirmed growth requirement to 5% is an intentional relaxation. It produces AAA because that company grows at 8%. Calling this a bug fix would hide the changed research scope. Likewise, allowing PE below 25 admits BBB at PE 24; it does not prove the original PE threshold was wrong.
Missing data require a third path. Retrieve the defined observation, preserve its source and rerun the affected row. Do not lower the threshold to work around an unavailable field. If no source supports the field, report the screen as only partially evaluated and describe which part cannot be completed.
Close with a decision table and a rerun condition
Deliver the unchanged baseline, coverage summary, diagnosed implementation defects and independent proposals. For each proposal include the exact changed condition, recovered count and names, plus any unresolved data. Ask the decision-maker to select the scope change before it becomes the saved production rule. A zero-result baseline can remain the correct final result.
Rerun after correcting a confirmed unit defect, acquiring missing observations or receiving an explicitly changed requirement. Compare against the old snapshot with the appropriate label, so readers can distinguish repaired code from revised data or revised policy. This procedure applies across stock markets only where the definitions and coverage have been checked separately; it does not turn current data into a historical universe or prove that a broader screen is better.
Keep a diagnostic change log
For each experiment, store the parent baseline identifier, the changed parameter, the unchanged input reference and the resulting member set. The PE-only and growth-only proposals should both point directly to the original baseline. Do not run the second proposal on top of the first proposal, because that would test two relaxations while reporting only one.
After selecting a repair, replay the original failure fixture and the two unaffected fixtures. A unit conversion change should repair the representation without altering the intended operators. A coverage repair should add an observed value without changing the threshold. This small replay helps identify accidental policy changes introduced during troubleshooting.
The final diagnostic can conclude that no policy change is appropriate. In that case, archive the baseline as a completed zero-result screen with its coverage boundary and a date for the next data-driven review.
FAQ
Should the system automatically loosen conditions until names appear?
No. Show reproducible proposals and preserve the original request until a scope change is chosen.
Does zero after a unit repair mean the repair was unnecessary?
No. The implementation can be wrong even when the corrected candidate count is unchanged.