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

5 min read · practitioner

Read the universe, and find out what is in it

"All US stocks" is a phrase that feels precise and is not. This lesson makes you look at what is actually behind it, because every screen you ever write inherits whatever you got wrong here.

Ask for the list

One call returns every instrument on an exchange:

/exchange-symbol-list/US

Run on 2026-08-25 it returned 51,215 rows. Here is the first one, exactly as it came back:

{"Code": "^MGTN", "Name": "CBOE MAGNIFICENT 10 INDEX", "Country": "USA",
 "Exchange": "US", "Currency": "USD", "Type": "INDEX", "Isin": null}

Read it twice. The first row of "all US stocks" is not a stock. It is an index, and an index has no shares, no earnings and no market cap. Screen it on a P/E and you will get either nothing or nonsense.

What 51,215 is actually made of

Counted from the same response:

Type Count
FUND 20,884
Common Stock 18,012
ETF 5,801
Mutual Fund 5,154
Preferred Stock 699
Warrant 355
Unit 166
Notes 138

Barely a third of "the US market" is common stock. The largest single group is funds. If your screen quietly includes them, your "cheapest companies" list contains things that are not companies, and you will not notice, because they have codes and names and prices like everything else.

This is the single most common way a screener produces confidently wrong output. Not a bug in the code — a universe nobody looked at.

Filter the universe before you filter the fundamentals

Two decisions, made explicitly and written into the plan:

const TRADEABLE = new Set(["Common Stock"]);   // your call, stated

Whether preferred stock belongs is a real question with a real answer for your purposes. What is not acceptable is not having decided. Write the choice down; your future self will want to know whether the absence of ETFs was a decision or an accident.

Do not fetch 51,215 rows to show 40

Pulling the whole list into your app and filtering it in JavaScript is the instinct, and it is wrong twice over: it is a large response for no reason, and the fields you want to filter on are not in it. Notice what the row above does not contain — no price, no market cap, no sector, no earnings. It is an index of what exists, not data about it.

Filtering happens server-side at the /screener endpoint, which is the next lesson. Fetch the symbol list when you need to know what exists; screen when you need to know which ones match.

Exchanges are not countries

/exchange-symbol-list/{CODE} takes an exchange code, and the list of them comes from /exchanges-list. US is a convenience covering the American venues; LSE, XETRA and the rest are individual exchanges. A screen across two exchanges is a screen across two currencies and two sets of accounting conventions, which unit 3 lesson 12 is entirely about.

The finance behind it

An index in a stock screen is the same mistake from the data side, and the API domain walks through why the endpoint answers at all: Why does an index have no financial statements?

Try it now

Pull the symbol list for the exchange you care about and count it by Type yourself. Then answer one question in your PLAN.md: which types are in your universe, and why. If your answer is "stocks", go back and decide about preferred stock, ETFs and units — because the API will not decide for you and something will end up in your results.