HAP
All work05 / 09

Dashboards & Reporting

Peer-Group Divergence & Market Intelligence Dashboard

An OpenBB-powered dashboard with a Next.js front end proxying a FastAPI Python backend that does the real quant work in pandas. Its centerpiece is a divergence scanner that finds the one name in a peer group that is NOT moving with the others, backed by social-sentiment, screener, technical, and multi-chart views. Everything runs against free market-data tiers without ever blowing through provider quotas.

Stack

Next.js 16 (App Router)React 19 / TypeScriptFastAPI (Python)pandas / numpyOpenBB SDKSQLiteRecharts + custom SVG

Concepts

Robust statistics (leave-one-out z-score)Stale-while-revalidate cachingProvider routing + budget guardSocial signal scoringTechnical indicators

How it works

The whole flow, traced from your first tap.

Browser (Next.js)Next API proxyFastAPI + pandasData feeds + SQLite
  1. 01

    Browser (Next.js)

    Pick a peer group and hit scan

    You choose one of 35 editable peer groups — or paste your own 3-to-80 symbol set with a benchmark — and the page can also auto-scan straight from a shareable URL like /divergence?groups=semiconductors.

    React 19App RouterDeep links
  2. 02

    Next API proxy

    Request crosses the proxy

    The browser only ever calls same-origin /api routes; a thin proxy forwards each one to the FastAPI backend and returns the upstream JSON, so the two-process app feels like one and a dead backend surfaces as a clean 502.

    Route handlersno-store fetch
  3. 03

    FastAPI + pandas

    Backend pulls daily closes, quota-safely

    It fetches 6 months of daily closes for every member in parallel, routing across twelvedata, fmp, and marketstack with per-provider per-minute and per-day budgets persisted in SQLite — when one provider is exhausted the router skips to the next instead of burning quota, and a 30-minute history cache keeps repeat scans nearly free.

    ThreadPoolExecutorProvider routingBudget guard
  4. 04

    FastAPI + pandas

    It scores who is breaking ranks

    pandas builds an aligned close matrix, computes per-window returns, then for each name derives a leave-one-out robust z-score against its peers plus a 60-day correlation and beta versus the equal-weight peer index — flagging a confirmed diverger only when correlation is high enough that the name should have moved with the group but did not.

    Robust z-score (median/MAD)60d corr + betanumpy
  5. 05

    Browser (Next.js)

    You read the divergers, ranked and labeled

    Results return sorted by max absolute z-score with human-readable labels and per-window returns versus the group median, and any ticker opens in the popup chart board where up to 9 hand-rolled SVG candlestick charts support wheel-zoom and drag-pan.

    RechartsCustom SVG candlesticks
  6. 06

    Data feeds + SQLite

    Cross-check with technicals and social buzz

    From there you can pivot a name into technicals (Wilder-style RSI(14), SMA20/50/200, MACD and RVOL all computed in pandas) or the social scanner, which ranks Reddit and Stocktwits chatter using abnormal-buzz metrics against a rolling 30-day hourly baseline stored in SQLite — and never blocks, serving the last completed scan instantly while a fresh one runs in the background.

    Wilder RSI / MACD / RVOLReddit + StocktwitsSWR + SQLite

The problem

Retail tools tell you what is going up, not what is acting strangely. If every semiconductor name dumps but two of them hold flat, that relative strength is the signal — yet spotting it means eyeballing dozens of charts, and the moment you automate the scanning you start hammering rate-limited free data APIs until they cut you off.

What we built

A two-process app: a Next.js front end that proxies same-origin /api calls to a FastAPI backend where pandas does the math. It covers a market overview, a screener, technical analysis, a popup multi-chart board, headline news aggregation, a social-sentiment scanner, and the divergence scanner — all reading from a shared, quota-aware market-data layer. Peer groups are editable JSON (35 curated baskets across semis, crypto, defense, photonics), so the universe is user-curated data, not hardcoded.

Finding the odd one out: leave-one-out robust z-scores

For each peer group the backend computes 1, 5, and 20-day returns per member, then scores each name against its peers using a robust z-score built on the leave-one-out median and MAD (scaled by 1.4826), so a single big mover cannot mask itself by dragging the group statistics. It also computes a 60-day correlation and beta of each name against the equal-weight peer index excluding itself — a divergence only counts when the stock normally tracks the group and its z-score clears the threshold, which filters out habitual lone movers. Results come back with plain-English labels like Held up while group fell or Lagged group rally.

Outcome

A genuinely useful daily-driver dashboard that surfaces relative-strength anomalies and early social buzz in seconds. Warm responses land in 20-200ms because slow endpoints serve their last result instantly and refresh in a single-flight background thread, and the per-provider budget guard means cold scans of 200+ symbols never trip free-tier limits.

Interested in something similar?

Tell us what you need and we'll figure out how to ship it.

Get in touch