Build a Stock Scanner Series — Part 1 of 6

Scanner Philosophy — Why Most Screeners Fail

Everyone uses stock screeners. Almost nobody profits from them. The difference between a Finviz filter and an institutional scanner is four pillars: Filter, Score, Rank, Validate. This is where we start building yours.

Scanner Architecture 4 Pillars Data Quality Hit Rate Analysis
Build a Stock Scanner That Actually Works1/6
The Screener ParadoxThe 4 PillarsInstitutional EdgeUniverse ProblemData QualityThe PipelineKey Takeaways
The Screener Paradox

Why Most Screeners Fail

Here is a stat that should bother you: over 90% of retail traders who use stock screeners lose money. Not because screening is a bad idea — it is, in fact, the foundation of every systematic trading approach — but because the way most people screen is fundamentally broken.

The typical retail workflow looks like this:

The Retail Screener Workflow

  1. Open Finviz or TradingView screener
  2. Set a few filters: RSI < 30, volume > 1M, market cap > $1B
  3. Get 47 results
  4. Pick the one with the coolest chart
  5. Buy it
  6. Lose money
  7. Blame the screener

The problem is not the screener. The problem is that filtering is only 25% of the job. The other 75% — scoring, ranking, and validation — is where the edge lives.

Think about what a basic screener does: it applies binary pass/fail filters to a universe of stocks. RSI below 30? Pass. Volume above 1 million? Pass. That is it. No ranking, no scoring, no context about whether the market is in a bull run or a crash. A stock that barely passes every filter gets treated the same as one that crushes every metric.

The result is a flat list of "candidates" with zero signal about which ones are actually worth trading. You are left making the final decision based on gut feel, chart pattern recognition (which is notoriously unreliable), or whatever the latest Reddit thread says.

The Core Problem

A screener that only filters is like a search engine that only matches keywords without ranking results. Google became Google because of PageRank — the scoring algorithm. Your scanner needs the same thing.

The Three Fatal Flaws

Flaw What Happens The Fix
No Scoring All results treated equally. A stock at RSI 29 is "passed" just like RSI 15 (which is much more oversold) Composite scoring that quantifies HOW MUCH a stock passes each criterion
No Regime Awareness Momentum filters in a bear market = buying the dip into a crash. Oversold filters in a bull market = missing the trend Detect the market regime FIRST, then select which strategy to weight heavily
No Validation No way to know if your filters historically produce profitable trades. You are flying blind Backtest every scanner output. Track hit rates by strategy. Kill what does not work
The 4 Pillars of a Real Scanner

Filter, Score, Rank, Validate

A scanner that actually generates alpha is built on four pillars. Each one is necessary. Skip any one and your scanner is a random number generator with a nice UI.

1

Filter

Apply technical and fundamental criteria to reduce 10,000 stocks to 50-100 candidates. Use a flexible DSL, not hardcoded rules.

2

Score

Assign a composite score (0-100) to each candidate based on multiple weighted factors. Boost for catalysts, penalize for risks.

3

Rank

Sort by score. Take only the top 10. Enforce diversification: no more than 2 from the same sector, mix geographies.

4

Validate

Backtest historically. Track live results with weekly retrospectives. Kill strategies with hit rates below 40%.

The Scanner Equation
Alpha = Filter(universe) + Score(candidates) + Rank(scored) + Validate(results)

Notice how each stage dramatically reduces the number of stocks. The funnel is doing the heavy lifting for you — transforming thousands of names into a handful of high-conviction setups that you can actually research and trade.

Why Each Pillar Matters

Pillar 1: Filter — The Gatekeeper

Filters are the first pass. They exist to eliminate, not to select. A good filter removes 95% of the universe in milliseconds. The key insight: filters should be strategy-specific. A momentum strategy and a mean-reversion strategy need completely different filters — they are looking for opposite things.

This is why you need a DSL (Domain-Specific Language) for your filters instead of hardcoded rules. In Part 2, we will build one that lets you swap filter sets instantly based on what the market is doing.

Pillar 2: Score — The Differentiator

Once you have 50-100 candidates that passed the filter, you need to answer: which ones are the best? A composite scoring system assigns points for technical strength, momentum, risk profile, and catalyst proximity. It also penalizes for red flags: insider selling, dilution risk, high short interest with no catalyst.

The scoring system is the brain of your scanner. We build it in Part 3.

Pillar 3: Rank — The Selector

Ranking is not just sorting by score. It includes diversification constraints: you do not want 10 tech stocks, even if they all score 95/100. Real ranking enforces sector limits, geographic diversity, and beta balance. It also applies regime-weighted strategy preferences — if the market is risk-off, you want more defensive setups at the top.

Pillar 4: Validate — The Truth Machine

A scanner without validation is faith-based trading. You must track every output: did the entry trigger? Did it hit TP1? Did it stop out? Over time, you build a statistical picture of your scanner's edge (or lack thereof). In Part 5, we build a backtesting engine. In Part 6, we build a live retrospective system.

The Institutional Edge

What Institutional Scanners Do Differently

Hedge funds and prop desks do not use Finviz. They build custom systems that incorporate layers of intelligence retail traders never see. Here is what separates a $50B fund's scanner from a retail screener:

Feature Retail Screener Institutional Scanner
Filters Static (RSI < 30, P/E < 20) Dynamic DSL with regime-dependent parameters
Scoring None — binary pass/fail Multi-factor composite (technical + catalyst + risk)
Regime None — same filters in bull and bear Auto-detects regime, shifts strategy weights daily
Data EOD prices, maybe 1 year 200+ days OHLCV, splits-adjusted, with volume profile
Catalysts None Insider buys, SEC filings, analyst upgrades, earnings dates
Risk Layer None Cost-to-borrow, dilution detection, sector correlation
Validation None — "trust the process" Backtested, live-tracked with weekly retrospectives
Output Flat list of tickers Scored, ranked, with entry/stop/target and catalyst calendar

The good news: you can build most of this yourself. The data is available (often free or cheap). The computation is trivial for modern hardware. The only barrier is knowledge — which is exactly what this series provides.

Key Insight

The institutional edge is not proprietary data or faster computers. It is process. A systematic, multi-layered approach that removes emotion and replaces it with statistics. That is exactly what we are building.

The Universe Problem

Scanning 10,000 vs. Curating 500

The first decision you make when building a scanner is also the most consequential: what is your universe?

There are over 10,000 stocks listed on US exchanges alone. Add international markets and you are looking at 40,000+. Scanning all of them is technically possible but practically terrible. Here is why:

The Curated Universe Approach

Instead of scanning everything, institutional scanners work with a curated universe of 300-800 quality names that meet minimum criteria:

Python
# Universe selection criteria
def build_universe(all_stocks):
    """Filter to quality names only."""
    universe = []
    for stock in all_stocks:
        if (
            stock.market_cap > 500_000_000      # $500M+ market cap
            and stock.avg_volume_20d > 500_000  # 500K avg daily volume
            and stock.price > 5.0              # No penny stocks
            and stock.listed_years >= 2        # At least 2 years listed
            and stock.has_options                # Options available (liquidity proxy)
        ):
            universe.append(stock)
    return universe  # Typically 400-800 stocks

This is not just about speed — though scanning 500 stocks is 20x faster than scanning 10,000. It is about signal quality. Every stock in your universe should be one you could actually trade: liquid enough to enter and exit, large enough that technical analysis works, and with clean enough data to compute reliable indicators.

Universe Size Typical Pass Count Signal Quality Processing Time
10,000+ (full US) 150-300 Low — many false positives from illiquid/micro-cap stocks 30-60 seconds
2,000 (mid/large cap) 40-80 Medium — still some noise from edge cases 5-10 seconds
500 (curated quality) 15-30 High — every candidate is tradeable 1-2 seconds

The Multi-Market Expansion

Once your scanner works for US stocks, you can expand geographically. Add 50-100 European names (DAX, CAC 40, FTSE 100 components), 30-50 Asian names (Nikkei, HSI components), and ETFs (sector, commodity, bond). Your total universe grows to 600-800, but every name is quality. This is what we cover in Part 6.

Data Quality

The "Bar Quality" Problem

Your scanner is only as good as its data. This sounds obvious, but the number of scanners built on bad data is staggering. Here are the data problems you must solve before writing a single filter:

1. Splits and Dividends

When a stock splits 4:1, the historical price drops by 75% overnight — but that is not a real price move. If your scanner sees AAPL at $40 in 2019 and $175 in 2024, it looks like a 337% gain. But AAPL had a 4:1 split in August 2020, so the actual gain is different. You must use split-adjusted data.

Python
# Always use adjusted close prices
import yfinance as yf

# WRONG: unadjusted prices include split artifacts
# data = yf.download("AAPL", period="2y")["Close"]

# RIGHT: adjusted prices account for splits and dividends
data = yf.download("AAPL", period="2y", auto_adjust=True)
close = data["Close"]
volume = data["Volume"]

# Verify: no single-day drops > 30% (split artifact check)
daily_returns = close.pct_change()
assert (daily_returns.abs() < 0.50).all(), "Possible unadjusted split detected"

2. Minimum History Requirement

Your indicators need history. An EMA(200) needs at least 200 bars to be meaningful. A Bollinger Band Width comparison needs at least 20 bars of BBW history, which itself needs 20 bars of price — so 40 bars minimum. A volume spike detection comparing current volume to 20-day average needs 20 bars.

Rule of thumb: require 252 trading days (1 year) minimum, prefer 504 days (2 years). Anything less and your indicators are unreliable in the early bars.

3. Delistings and Survivorship Bias

If you only scan currently listed stocks and backtest against the same list, you have survivorship bias. The stocks that went bankrupt, got delisted, or merged out of existence are invisible in your data. Your backtest will overestimate returns because it never saw the losers.

Survivorship Bias Example

In 2008, a momentum scanner on today's S&P 500 would have found many "survivors" that recovered beautifully from the crash. But back in 2008, the S&P 500 had different members — Lehman Brothers, Washington Mutual, Bear Stearns were all in it. A scanner that never saw these blow-ups would massively overestimate its performance.

4. Volume Data Integrity

Volume is critical for confirmation signals, but volume data has its own problems:

Python
# Data quality validation pipeline
def validate_bar_data(df, ticker):
    """Check data quality before feeding to scanner."""
    issues = []

    # 1. Minimum history
    if len(df) < 252:
        issues.append(f"Only {len(df)} bars (need 252+)")

    # 2. Missing data
    missing_pct = df.isnull().sum().max() / len(df) * 100
    if missing_pct > 2:
        issues.append(f"{missing_pct:.1f}% missing data")

    # 3. Suspicious returns (unadjusted splits?)
    max_daily = df["close"].pct_change().abs().max()
    if max_daily > 0.50:
        issues.append(f"Suspicious {max_daily:.0%} daily move")

    # 4. Volume sanity
    zero_vol_days = (df["volume"] == 0).sum()
    if zero_vol_days > 5:
        issues.append(f"{zero_vol_days} zero-volume days")

    if issues:
        print(f"[WARN] {ticker}: {', '.join(issues)}")
        return False
    return True
The Complete Pipeline

Scanner Architecture Overview

Now let us put it all together. Here is the complete pipeline that we will build over the next five parts of this series:

The Daily Cycle

A production scanner runs on a daily cycle. Every morning (or evening, depending on your market), the following happens:

6:00 AM

Regime Detection. Check SPY, VIX, DXY, TLT, HYG/LQD, BTC. Determine if the market is Risk-On, Neutral, or Risk-Off. Adjust strategy weights accordingly.

6:05 AM

Data Refresh. Pull latest OHLCV for your 500-stock universe. Validate data quality. Compute all indicators (EMAs, RSI, MACD, ATR, BBW).

6:10 AM

Filter. Run 4 strategy-specific DSL filters against the universe. Each filter produces 15-30 candidates. Deduplicate and merge.

6:15 AM

Score & Rank. Apply composite scoring to all candidates. Add catalyst boosts (insider buys, earnings). Penalize risks (dilution, high CTB). Sort by regime-weighted score. Select top 10.

6:20 AM

Enrich. For each of the 10 finalists: compute ATR-based entry/stop/target levels. Pull analyst targets, insider activity, earnings dates. Build the trade card.

6:25 AM

Publish. Generate the morning report. Send alerts via Telegram/Discord. Log everything for the retrospective.

The entire process takes under 30 minutes, most of which is data fetching. The computation itself is measured in seconds. This is achievable on a $5/month VPS — you do not need a Bloomberg terminal.

Scanner is Not a Strategy

Critical Distinction

A scanner finds candidates. You make the trade decision. The scanner says "here are 10 stocks that meet my criteria, ranked by score, with entry/stop/target levels." But the final call — whether to actually enter the trade — is yours.

Why? Because the scanner does not know about:

  • Breaking news that just hit 5 minutes ago
  • Your portfolio's current exposure (already 3 tech positions? skip the 4th)
  • Liquidity conditions at the exact moment of entry
  • Your risk tolerance and current P&L state

The scanner narrows 500 stocks to 10 high-probability candidates. That is a 98% reduction in your decision space. But the last 2% is human judgment, and it should stay that way.

What We Will Build in This Series

Part What You Build Key Concept
1. Philosophy (this article) Mental model for scanner architecture Filter + Score + Rank + Validate
2. DSL & Filters A flexible filter language with 4 strategies Expression evaluation, strategy-specific filters
3. Scoring Multi-factor scoring with boosts and penalties Composite scoring, catalyst integration, risk detection
4. Regime Detection Auto-adaptive regime detector with 6 indicators Market regime, dynamic strategy weighting
5. Backtesting Historical validation engine with walk-forward testing Win rate, profit factor, overfitting avoidance
6. Production Live daily pipeline with alerts and retrospectives ATR-based levels, multi-market, cost optimization
Key Takeaways

Key Takeaways — Part 1

Part 2 of 6
Building a Filter Language — Your Scanner's Brain
Build a Stock Scanner That Actually Works1/6