Case study
₹ Rupee Engine
A modular equity-analysis and portfolio engine for Indian markets: CLI, API and dashboard.
- Status
- Active, since Feb 2026
- Coverage
- 2,600+ NSE stocks per full run
- Algorithms
- 13 pluggable, registered
- Interfaces
- CLI · REST API · React dashboard
- -91%Memory for big backtestsFrom about 50 GB to about 4 GB, with the same results.
- 50-70%Faster on the slow partsA run that used to hang now finishes in about 11 minutes.
- 2,600+Stocks scored in one runThe whole market, end to end, with no failed lookups.
The problem
Judging a stock means combining fundamentals, price behaviour and news sentiment, and doing it consistently across a thousand names. Done by hand it is slow and impossible to audit.
I wanted a system where every recommendation is the output of explicit, testable scoring logic, and where the logic itself can be measured against history instead of trusted on instinct.
Architecture
- Public data sources: exchange + fundamentals + news
- Async ingestion: httpx · asyncio · rate limits
- TTL cache: incremental refresh
- PostgreSQL: schema owned by migrations
- Scoring engine: registry of 13 algorithms
- Portfolio optimizer: costs · risk/return
- CLI · REST API · dashboard: token-protected API
- Backtest + calibration: replays history
Explore the stages
Decisions that mattered
Faster and lighter, same answers
- Situation
- Big runs were slow, one hung, and a large backtest ran out of memory on a 64 GB machine.
- What I decided
- Find the real cause with profilers instead of guessing. Accept a change only if the results stay identical. Make a missed shortcut fail loudly, so a speed-up cannot quietly rot.
- Result
- Up to 91% less memory, 50-70% faster, and the hang is gone. Nothing about the output changed.
Fail loudly, never guess
- Situation
- When data is missing, the easy path is to score what is left and carry on.
- What I decided
- Stop with a clear error instead. If most data is missing, or the database is not ready, the run or the API refuses to start.
- Result
- No quietly wrong portfolio. A failure is visible the moment it happens.
Be kind to the data sources
- Situation
- The sources limit how fast I can ask, and a naive run repeated almost all of its work.
- What I decided
- Remember what is already fetched, skip what is stored, and refresh only what is due.
- Result
- A repeat pass over the news sources dropped from about a minute to a few seconds.
What I optimise for
- Measure before and after, every time.
- Fail loudly instead of guessing.
- Same inputs give the same answers: changes to the scoring are fingerprinted and frozen outputs are reviewed.
- Docs are checked against the code, so they cannot drift.
Incidents get a written postmortem and a runbook, not just a fix.
Known gaps and what is next
It runs from one machine, started by hand.
Next Scheduled runs with an alert when one fails.
A data source can change its page and go quiet.
Next A health check per source that says so.
It ranks and sizes a portfolio. It does not trade, and it is not advice.
Next Stay a research tool, on purpose.