‹ Build a Screener Lesson 12 of 17
Contents Lesson 12 of 17

5 min read · professional

Reviewing for numbers that lie

Lens three, and the one with no error message. Leaks and cost eventually announce themselves. A number in the wrong units renders beautifully, sorts correctly, and is simply false.

Every example below is from a real response captured on 2026-08-25.

The fraction that looks like a percentage

{"code":"NVDA","dividend_yield":0.0002}

Render that as 0.0002% and you are wrong by a factor of a hundred: it is 0.02%. Render it as 0.0002 with a % sign glued on and you have said the same false thing.

What makes this dangerous is that both the wrong and the right answers look plausible on screen. A yield of 0.02% for NVIDIA is correct and unremarkable; 0.0002% is absurd if you think about it, and nobody thinks about it while scanning forty rows.

The rule: whenever a field is a rate, find out once whether it is a fraction or a percentage, write the answer in a comment next to the conversion, and never do that conversion anywhere else.

The floating-point tail

From the same response, Apple's one-day change:

{"code":"AAPL","refund_1d":0.98999999999995,"refund_1d_p":0.32}

That is 0.99, arrived at by subtracting two decimals in binary floating point. It is not an API bug; it is how computers do arithmetic, and every language does it.

Two consequences for review:

Never render a raw float. toFixed(2) at the column, always. Without it a column shows 0.98999999999995 beside 4.07 and the table stops looking like a tool.

Never compare floats for equality. refund_1d === 0.99 is false here. If you must compare, compare a rounded value or use a tolerance.

The number so large it stops being read

{"market_capitalization":5049593888768}

Five trillion, and nobody can see that at a glance. A column of raw market caps is unreadable, and unreadable is a correctness problem: you cannot spot the wrong one.

Format to a unit a person holds in their head — 5.05T, 4.53T — and keep the raw value for sorting. Two representations, one source, and never sort the formatted string: alphabetically "5.05T" comes before "999B", so a descending sort puts the smaller company on top.

Missing is not zero

A company with no reported earnings has no earnings_share. If your render does r.earnings_share.toFixed(2) it throws; if it does (r.earnings_share ?? 0).toFixed(2) it prints 0.00, which is a claim you just invented. Zero earnings and unknown earnings are different facts, and a screener that conflates them will rank an unknown as if it earned exactly nothing — above every loss-maker and below every profitable name, a position it has no evidence for.

A dash. Always a dash. That is why render returns string | null in unit 2 lesson 2.

Two currencies in one column

The response carries currency_symbol. A screen across exchanges returns prices in different currencies, and a column that shows the number without the symbol invites a comparison that means nothing. Sorting by such a column is worse: it ranks by an arbitrary mix of scales.

Either keep one currency per screen, or show the symbol on every row and refuse to sort on it. Silent totalling of mixed units is the same error as the pence trap in course 1, one level up.

The lens, as five questions

  1. Is this a rate, and is it a fraction or a percentage?
  2. Is this a raw float, and where is the rounding?
  3. Is this big enough to be unreadable, and is sorting done on the raw value?
  4. Can this be missing, and does missing render as a dash rather than zero?
  5. Could two rows here be in different units?

The finance behind it

Two currencies in one column is a quoting question before it is a code question: When you buy EUR/USD, what are you actually buying?

Try it now

Run a screen returning at least twenty rows and check every numeric column against the five questions. Then do the decisive test: pick the row with the smallest dividend yield, work out the real percentage by hand from the raw JSON, and compare it with what your table shows. If they differ, you have shipped the hundred-times error, and you are in good company.