Market Nudge · Self-initiated · Solo build with AI · 2026 · Live
The whole market, one app.
Market Nudge is a four-stream Indian-markets app — live news, prediction markets, a results calendar, and an options-strategy engine priced off the real option chain. I designed it, then directed AI through every layer a designer normally hands off: the API research, the backend, the tests, the deploys. It runs entirely on free infrastructure. ₹0 a month.
One glanceable surface, four streams
What each tab does — and how often it breathes.
Feed
13 sources, deduplicated — "breaking" must be corroborated.
polls 60 sPredictions
Polymarket real-money odds, with volume and probability history.
polls 1 minCalendar
NSE corporate events plus US earnings dates, searchable by scrip.
refreshes 12 hStrategies
Live indices, S/R levels, and a 16-template engine on the real chain.
ticks 3 s01 — PREMISE
One constraint did most of the design work
I trade Indian equities. The information I need before the open is scattered across a news site, a prediction market, an earnings calendar, an option chain and two brokerage screens — and the one thing I actually want, what changed since I last looked, and does it matter, is a feature none of them ship.
The product question was never "can I aggregate feeds". It was: how much of a trading desk can one person assemble out of endpoints that are free and public — and where exactly does that approach break? The ₹0/month rule turned out to be the sharpest design tool in the project. It couldn't be argued with: a source either answered or it didn't, and every feature had to justify itself against a real, measurable supply.
02 — PROCESS
How a designer ships a full product, alone, with AI
I'm a product designer, not a career engineer. AI (Claude Code) is what closed that gap — but not by "writing the app for me". Code arrives faster than trust, so the whole process is built around earning trust: I set the intent and the constraints, the AI types, and nothing ships until it survives a probe, a test, or a measurement. My job was taste, verification and veto.
-
Write the spec like a contract
Before any code: a locked scope document — four tabs, refresh cadences, legal stance, and a section for what v1 refuses to do. Every later argument with myself got settled by pointing at it. The AI builds against the document, not against vibes.
SCOPE.md · 366 lines · locked -
Probe every API before believing it
Each planned data source was an assumption until called. I had the AI write probe scripts that hit every candidate endpoint server-side and log what actually came back. Roughly half the plan didn't survive contact — the full findings are in section 03.
DATA-SOURCES.md · 725 lines of verdicts, with dates -
Build in vertical slices, review like a crit
One feature at a time, landing complete — UI, service, proxy route and tests together. I reviewed diffs the way I review design work: what's the intent, what's the evidence, what would make this wrong? Big decisions live as comments in the code itself, with the measurement that justified them.
6 screens · 12 services · 1 worker -
Break it on purpose
Every test must be seen failing: revert the fix, watch it go red, restore it. That ritual caught a ticker that never started, and a test that passed while checking the wrong thing. A stale feed looks identical to a healthy one — only a test that can fail tells them apart.
303 app tests + 22 backend tests -
Ship small, record everything — especially failures
Deploys are one script, which also snapshots a data file the production network can't fetch at request time. Dead ends get written down with the measurement that killed them — which is what stopped me re-investigating Yahoo Finance three separate times.
deploy_web.sh a failure log that saves future me
Directing AI didn't lower the bar for rigor — it raised it. The AI is the fastest pair of hands I've ever worked with, and it will confidently build the wrong thing. The value I add is the same thing I add as a designer: knowing what to ask for, and refusing to accept unverified answers.
03 — API RESEARCH
Half the data plan died on contact. Good.
Every source was probed server-side before a single screen was built — the way the backend would eventually call it, not the way a browser demo pretends to. The verdicts, from the project's validation log:
| Source | Planned for | Reality when called | Verdict |
|---|---|---|---|
| Moneycontrol RSS | #1 Indian news source | Newest item ~2.3 years stale, on every path tried | Dropped |
| Yahoo Finance | Price history | HTTP 429 on every Indian symbol | Dropped |
| PredictIt | 2nd prediction market | Cloudflare bot-block, 403 even on the homepage | Dropped |
| X / Twitter | Breaking-news signal | Every free path rate-limited or CORS-blocked | Dropped |
| NSE JSON APIs | Chain, indices, calendar | Works — behind a cookie handshake and a retry policy | Core |
| Polymarket | Prediction odds | Clean public API, CORS-open — the app calls it directly | Core |
| Upstox candles | not in the plan | 7.5 years of daily bars, no API key at all | Core |
| Google News RSS | not in the plan | Recovers Reuters via site: queries, free | Core |
Two of those findings rewrote the project's economics. The v2 plan carried a
$50/month news API mostly to get Reuters back (it killed public RSS
in 2023) — a Google News site:reuters.com query returns a hundred fresh
Reuters items for nothing. And a $5/month server for price history
became unnecessary the moment Upstox's historical-candle endpoint answered without
credentials. That's $55/month of planned spend deleted by two probes.
The one I got wrong — and what it taught the code
I'd written BSE off as unscrapeable: every endpoint returned the same 13,850-byte
Angular shell with a clean HTTP 200. The observation was real; my conclusion was
wrong. BSE serves that shell to any caller without a Referer header —
send one, and the API underneath answers properly:
# as documented — no Referer $ curl -s 'https://api.bseindia.com/…/getScripHeaderData/w?scripcode=1' → 200 OK · 13,850 bytes · <!doctype html>… # the Angular shell, again # same call, one header added $ curl -s -H 'Referer: https://www.bseindia.com/' '…?scripcode=1' → 200 OK · {"CurrRate":{"LTP":"78,094.64","Chg":"+166.20","PcChg":"+0.21"}…
One header was the difference between "this exchange is a dead end" and SENSEX ticking live every 3 seconds. A 200 that contains the wrong thing is more expensive than a 500 — status codes are not evidence.
The lesson is wired into the product: the proxy now sniffs every BSE body and fails
loudly if it starts with <, because that failure is otherwise invisible.
04 — ARCHITECTURE
A backend shaped by one browser rule
Almost none of these sources send CORS headers, so a browser fetch succeeds and the browser then refuses to hand JavaScript the response. That single rule decides everything: the app talks to one cooperative origin — a Cloudflare Worker that does each source's handshake server-side, adds CORS, caches per route, and refuses to be anyone else's open relay.
Flutter Web app — one codebase
Installable on a phone · desktop gets the same phone, framed · Cloudflare Pages, static, free tier
Cloudflare Worker — the whole backend, one file
NSE
Indices, option chain, events. Rejects cold callers — homepage cookie warm-up first.
2 s indices · 3 s chainBSE
SENSEX live quote. The Referer header is the whole trick.
2 sUpstox
7.5 yrs of candles, keyless. Instruments file snapshotted at build time — its CDN blocks Worker egress.
12 h instruments13 news feeds
RSS via allowlist. Google News site: queries recover Reuters.
Alpha Vantage
US earnings calendar, CSV.
12 hPolymarket
The rare CORS-open API — the app calls it directly, no proxy needed.
app ↔ sourceWorkers KV + cron — the forward record
Every 5 minutes through market hours, a scoring snapshot is appended. Future win-rates get judged against rows computed before the outcome — lookahead bias is impossible by construction.
Polling that respects how sources actually publish
"Refresh everything every N seconds" is wrong in both directions — too slow for an index, wasteful for a calendar. Each stream's cadence was measured, not guessed, and the proxy caches each route just under its true publish rate, so faster app polling only ever re-reads the edge — load on thirteen publishers never multiplies.
| Stream | App polls | Edge cache | Why that number |
|---|---|---|---|
| Index ticker | 3 s | 2 s | NSE publishes roughly every 5 s. Sampling showed the price moves while the API's own minute-resolution timestamp doesn't — so the code reads the price, never the stamp. |
| Option chain | 4 s | 3 s | One call returns the whole chain, so cost is flat. This TTL was once 300 s — which quietly served traders a frozen chain. Found, measured, fixed. |
| Futures row | 15 s | 10 s | Fresh enough for a panel row while collapsing concurrent clients into one origin call. |
| News | 60 s | 45 s | The floor on how fast a breaking story reaches the strip. Runs weekends too — geopolitics doesn't observe the NSE calendar. |
| Calendars | 12 h | 30 m – 12 h | Corporate actions change daily at most. |
Reliability, measured before it was coded
NSE simply rejects a share of well-formed requests. Measured from Cloudflare's edge: first attempt succeeded 6/12; within three attempts, 11/12. Five attempts were also tried — no better than three, and slower, because NSE rate-limits and rapid knocking is part of the problem. So the retry policy is three, with backoff — chosen by data, not folklore.
The same proxy logic runs locally as a small Dart server, so development behaves like production. Two implementations of one contract is a real risk — so a parity test asserts they agree on routes, cache windows, retries and the allowlist, and fails the build if they drift.
The bug that proved the method
One Monday morning the 1D chart drew Friday's session with today's live price stapled on the end. Cause: Upstox's dated-archive route doesn't contain the in-progress session at all, while its intraday route contains only it — and my own notes, measured on a weekend, had confidently concluded the archive was enough. The note was true; the conclusion was wrong. The fix asks both routes and stitches them, deciding on whether bars came back rather than on the clock — one less thing to get wrong at 09:15, on holidays, and at 15:31.
05 — THE SCREENS
Four tabs, and the decisions inside them
Tab 1Feed — trust is a design material
- The same story arrives from several outlets; the feed deduplicates it — and counts corroborating sources, which is what earns a story the "breaking" treatment. Volume as signal, not noise.
- Every story wears its own age. A market feed that hides staleness is lying politely.
- Absence and failure are different states. "Nothing new" is honest and needs no button; a failed fetch gets a retry. Conflating the two teaches people to ignore both.
Tab 2Predictions — odds with receipts
- Real-money Polymarket probabilities for the macro questions that move Indian markets — each card carrying its volume and close date, so the reader can judge how much conviction sits behind a number.
- Sparkline history under every probability: 20.5% means little; 20.5% after a month at 35% is a story.
- Sized type does the hierarchy — the probability is the headline, everything else steps back.
Tab 3Calendar — two markets, one timeline
- NSE's
event-calendarendpoint alone replaced a seven-URL BSE scraping matrix — results, dividends, buybacks and board meetings from one call. - US earnings dates come from Alpha Vantage's CSV, because Indian portfolios react to Apple and Nvidia too. Both refresh on a 12-hour cadence — calendars change daily at most, so polling faster is pure waste.
- Searchable by scrip, so "when does my holding report" is one query, not a scroll.
Tab 4Strategies — the engine, and a filter I had to kill
- Sixteen option structures priced off the live chain, for the indices and any F&O stock. Support/resistance, RSI and SMAs computed from those free 7.5-year candles.
- The v1 "minimum probability" slider was a trap: ask for 51% and it proudly returned a 96%-probability iron condor — technically correct, useless. Nobody asking for coin-flip odds wants the safest thing in the book.
- So probability became a target: the engine sweeps strike combinations to land on the number you asked for — and when a template can't reach it, the app says so plainly instead of quietly substituting.
06 — OUTCOME
Live, free to run, and honest about what it knows
All four tabs are live at market-nudge.pages.dev. SENSEX ticks at three seconds. The feed corroborates its own breaking news. The strategy engine prices sixteen structures off a live chain. The infrastructure bill is still ₹0.
What building it actually taught me:
-
Status codes are not evidence. Half the data plan died the moment
it was actually called — and BSE, written off as unscrapeable, turned out to be one
Refererheader away from a live tick. Probe before believing. - True notes can still carry wrong conclusions. The Monday-morning chart bug came from my own accurate, weekend-measured documentation — the two candle routes are complements, not alternatives. Verifying facts isn't enough; conclusions need re-testing too.
- On free infrastructure, silence is the failure mode. A stale feed looks identical to a healthy one, so every test must be seen failing before it counts — that ritual caught a ticker that never started and a feature wired to nothing.
- Dead ends are only expensive if you pay for them twice. Recording every failed source with the measurement and date stopped me re-investigating Yahoo Finance three separate times.
And above all: constraints applied early are a design tool, not a limitation — and AI turns one person's judgment into a full team's output, exactly as fast as that judgment deserves.