Market-intelligence startup, co-founder

Whole-Market Scanner and Technicals Sweep

A live screener over the whole US equity market with 49 preset scans and 56 filters. A daily batch rebuilds a year of technical indicators for every ticker in about 260 API calls.

Headline number
12,400 tickers, every day
Role
Architected and led
Category
Data Platforms
Updated

Architecture

  1. Grouped-daily bars1 call per session
    Live market snapshot
  2. Technicals sweepdaily, leased
  3. Technicals table12,400 rows
    Fundamentals table
  4. Scanner engine56 filters, typed gates
  5. Members scanner
    Public scanner
    MCP scan tool
A daily leased sweep turns grouped bars into a technicals table. The scanner engine merges live snapshots with stored technicals and fundamentals behind typed gates.

Key takeaways

  • About 12,400 tickers, 49 preset scans in 9 categories, 56 filters
  • Grouped-daily bars make a full-year technicals rebuild cost about 260 calls instead of 12,400
  • Typed availability gates: a filter is disabled until its field is actually populated
  • A database lease guarantees only one replica sweeps at a time

The situation

Members wanted to screen the entire market by technicals and fundamentals in real time. Per-symbol indicator calls cannot reach universe scale on any budget, and a screener that quietly shows stale or missing values is worse than no screener.

What I built

The sweep uses the vendor's grouped-daily endpoint, which returns every ticker's bar for one session in one call. Walking forward across a year of sessions costs about 260 calls and yields RSI, MACD, moving averages, ATR, 52-week and multi-year ranges, performance windows, and volatility for every name. A PostgreSQL lease stops concurrent replicas from running the sweep twice.

The scanner engine merges the live snapshot with stored technicals and fundamentals, then applies filters, sorts, and columns. The rule I care most about is the gate: every column declares what data it requires, and the type system refuses a new column without one. A filter stays disabled until its field is populated. That rule exists because an early bug let a 52-week-high scan return all 12,394 tickers.

The outcome

The screener never presents a value it did not measure. Members, the public scanner, and the MCP server all run the same engine, and three CI invariants guard the gating and the free-tier ladder on every pull request.

Stack

TypeScriptPostgreSQLMarket data REST APIAzure Container AppsNext.js

Need this built inside your organization?

One person, architecture to deployment. Tell me what is stuck and I will tell you where I would start.