Ordinary shares on the main venues
EXACTMarkets: UK + USA. Filter exchange to LSE, NYSE, NASDAQ (TradingView tags AIM names LSE, so one value covers both permitted segments). Instrument: common stock, primary listing only — this alone removes 2,358 cross-listings and fund-like lines.
Throw out the financials
EXACTFilter industry to exclude every bank, insurer, and diversified-financial industry, plus Real Estate Investment Trusts and Investment Trusts/Mutual Funds — 14 industries in all. Property developers stay in: the rule excludes REITs, not builders.
Two full annual reports
PROXYRequire revenue growth (FY) or EPS growth (FY) to be populated — a fiscal-year-on-fiscal-year figure can only exist given two complete annual periods. A blank in both is treated as a fail, never a pass.
Big enough to be real
EXACTMarket cap ≥ £20m for UK names, ≥ $75m for US names. No upper cap.
Liquid enough to trade
PROXYAverage volume (90d) × price ≥ £100k UK / $650k US, and price ≥ 10p / $2 as the spread proxy. The floors are deliberately higher than the frozen £75k/$500k rule: TradingView only offers a mean, a mean sits above the median on skewed volume, so the floors compensate. Watch the pence trap: UK prices quote in GBX.
Real cash coming in
EXACTFree cash flow (TTM) > 0. A blank field excludes the name — it never passes by default.
Profitable, and more than last year
PROXYEPS diluted (TTM) > 0 and EPS diluted growth (TTM YoY) > 0. The gap: the growth field's sign is unreliable when last year was a loss, so the machine reconstructs the prior-year figure and compares directly. In the UI, growth > 0 is close but will misjudge some turnarounds. The biggest single cut in the whole funnel.
Debt under control
EXACTNet debt ÷ EBITDA (TTM) < 3.0. Negative net debt means net cash — the test is skipped, not failed. Negative EBITDA with net debt is a fail, never a "< 3".
In an uptrend, beating its index
PROXYPrice > SMA (200) is a real UI filter. The second half — Perf 6M above the home benchmark's six-month return — needs one number from outside: look up the FTSE All-Share (UK) and S&P 500 (US) six-month figures and filter above them.
Up over the year, ignoring last month
SPREADSHEETThe 12-1 return — total return from 252 to 21 trading days ago, dividend-adjusted — does not exist as a screener column. Approximate with Perf Y > Perf 1M, or compute it exactly from downloaded price history. The same price series confirms the ≥ 13-month listing rule.
The cheapest 30% on EV/EBIT
SPREADSHEETRequire Operating income (TTM) > 0, then export the survivors with Enterprise value and divide: EV ÷ EBIT. No percentile filter exists in the UI — sort per country and keep the cheapest 30% of each. Ties at the cut split alphabetically, so the same inputs always produce the same list.
Rank and take twelve
SPREADSHEETTwo percentile columns over the pooled survivors: cheapness (lowest EV/EBIT = 100) and momentum (highest 12-1 = 100). Average them 50/50, sort, and the top twelve fill the slots — equal money in each. An existing holding stays while it ranks ≤ 25 and sits above its 200-day average.
The screener UI carries you from 8,126 to about 700. The last four steps — exact trading-day returns, benchmark subtraction, the percentile cut, the ranking — are the spreadsheet mile, and they are why this is code: the machine runs that mile identically every month, archives its inputs, and cannot peek at data newer than the screen date. Build it by hand once; you will trust the record more.