market-lab: Designing a Screener That Refuses False Confidence
A static data product for every stock on India's National Stock Exchange
A stock screener is dangerous when it feels cleaner than the market it describes. Most screeners let a user sort by a number, then leave caveats scattered across columns. I wanted market-lab to do the opposite: rank the NSE, but force every row to carry the reason to be skeptical.


What was broken
The problem was not that screeners lack data. The problem is that they present data as if the user already knows how to weigh it. A high score can hide bad liquidity. A tempting small cap can be impossible to enter cleanly. A short-term signal can be read like a long-term thesis. The interface needed to make those mistakes harder.
- Lead with a sortable number
- Treat liquidity as secondary
- Hide the counter-case in extra columns
- Let users infer the time horizon
- Pair score with the objection
- Show order impact beside turnover
- Write the argument in plain language
- Make horizon part of the row
Interactive preview
Try the score-with-doubt rule
Strong candidate, but the row still carries the strongest objection.
My role
I designed and built the product as a full stack static data system: Python data pipeline, scoring model, validation step, generated JSON, TypeScript board, light/dark visual system, SEO surface and scheduled publishing. The interesting design work was deciding what the interface was allowed to imply.
The architecture is a design decision
I chose a static architecture because the product does not need a live server to be useful. A scheduled job can fetch the market data, compute scores, verify the output, write static files and publish to a CDN. That choice keeps the experiment inexpensive, resilient and easy to inspect.
| Layer | Design concern | Engineering choice |
|---|---|---|
| Data | Do not let stale or malformed rows become confident UI | Normalize the exchange feed before scoring and publish only generated data |
| Scoring | Avoid one magic number pretending to be truth | Calculate multiple signals and expose the weakest one beside the strongest |
| Interface | Let a user compare quickly without hiding risk | Dense row layout with score, risk, turnover, impact, horizon and thesis together |
| Delivery | Keep the public product cheap and durable | Static files on a CDN instead of an always-on app server |
The row is the product


The hardest UI decision was resisting the detail-page instinct. In a financial product, burying the caveat is the same as removing it for most users. So the row had to carry the complete minimum argument: ticker, score, risk, horizon, turnover, order impact, case for and case against.


That row design is where product design and engineering meet. The pipeline has to produce the fields. The TypeScript model has to preserve them. The UI has to keep them aligned. The visual system has to make the warning readable without turning the board into an alarm dashboard.
Responsive density without dropping the warning
The responsive problem was not fitting a desktop table onto a phone. It was preserving the minimum responsible argument when horizontal comparison disappeared. On desktop, a row supports cross-stock scanning. On mobile, each row becomes a research card: identity and score lead, the positive thesis and weakest signal stay together, and the remaining evidence follows in a deliberate reading order. Nothing safety-critical is pushed into an undiscoverable overflow menu.


| System rule | Desktop expression | Mobile expression |
|---|---|---|
| Score never travels alone | Score, thesis, weakness, horizon and liquidity align in one dense row | The card keeps score, risk, thesis and weakest signal above the fold |
| Navigation stays available | Research destinations use the wide application shell | Five primary destinations become a persistent, thumb-reachable bottom bar |
| Status remains contextual | Session freshness and market breadth sit above the ranking table | Status becomes stacked disclosure cards that preserve labels and tap targets |
| Themes preserve hierarchy | Color tokens separate surface, data and warning roles | The same semantic tokens maintain contrast without changing information order |
How I kept the score honest


| Signal | Why it exists | How it appears |
|---|---|---|
| Opportunity score | Gives the user a starting order for research | Large enough to scan, never alone |
| Risk band | Prevents a high score from feeling universally good | Chip near the row identity, not hidden at the end |
| Liquidity and order impact | Shows whether a real position can enter without moving the price too much | Displayed as practical rupee-order context |
| Argument against | Forces the product to state why the score might be misleading | Written beside the positive thesis in plain language |
Every feature in the suite








Failure states are part of the financial model
A research product becomes dangerous when missing data looks like weak data, or when a failed refresh quietly leaves yesterday's confidence on screen. I moved reliability into the shared data boundary: malformed numbers become unavailable, duplicate or damaged rows are counted, and a score is suppressed when its risk, liquidity or horizon context is not strong enough to support it.


| Failure class | Unsafe behavior | Designed response |
|---|---|---|
| Initial data failure | Render an empty board or fabricate zero-like values | Withhold scores, expose the failure reason and offer retry plus methodology |
| Background refresh failure | Replace useful context with a generic error | Keep the last-known screen, mark it stale and let the user retry |
| Malformed or partial rows | Let missing risk or liquidity appear neutral | Mark fields unavailable, count rejected rows and suppress unsupported rankings |
| Restrictive filters | Treat zero results like a system outage | Explain the active constraint and give a direct path to clear or widen filters |
| Invalid portfolio or assistant input | Accept a success-shaped answer | Attach the error to the field or request and preserve the user's recoverable work |
Design engineering craft
This project is not impressive because it has a table. It is impressive because the table is the last mile of a system: generated data, typed fields, sort behavior, responsive density, theme-specific contrast, static routing and public deployment. I worked across product judgment, interaction design, semantic visual tokens, TypeScript implementation, pipeline verification and operational cost. A row that looks clean but drops a warning on mobile would be a product failure, not a CSS bug.
Accessibility was a release gate, not a final audit
The accessibility sweep covered every primary view, factsheets, assistant setup, both themes, and the loading, empty, degraded and error states. I fixed landmarks and headings, linked labels and errors, keyboard row activation, focus visibility and restoration, disclosure semantics, live status announcements, textual alternatives for financial signals, reduced motion, non-color risk communication and narrow-screen reflow.
| User need | Implementation evidence | How I checked it |
|---|---|---|
| Understand status without color | Risk and quality use text, iconography and semantic labels as well as color | Light/dark contrast checks and non-color state inspection |
| Operate the board without a pointer | Rows, filters, disclosures, factsheets and assistant controls have keyboard semantics | Tab-order, focus visibility, Enter/Space activation and focus-return tests |
| Hear updates and errors | Loading, result counts, assistant responses and failures use appropriate status or alert behavior | Automated role/name checks plus critical live-region inspection |
| Zoom or use a narrow viewport | Cards reflow without two-dimensional page scrolling and primary controls retain usable targets | 320, 390 and 430 pixel viewports plus 200%-equivalent reflow |
What I can and cannot claim
This was a solo experiment, so the evidence is end-to-end ownership: model rules, data boundaries, responsive interaction, accessibility, recovery, tests and deployment. It is not evidence of cross-functional leadership, and the rankings are not evidence of investment returns. The product should be evaluated on research quality: time to compare a shortlist, whether users notice the counter-argument, recovery from stale or failed data, and whether confidence drops appropriately when evidence is incomplete.
What I would improve next
The next version should make score movement easier to audit over time. I would add a change log for why a score moved after each trading session, expose the raw fields that contributed to the final judgment, and extend the accessibility pass with structured testing across multiple screen-reader and browser combinations.