Skip to content

Latest commit

 

History

12 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

StockTracker

A stock trade-recommendation tracker. A SEBI-registered research analyst publishes a trade call — instrument, entry, stop loss and up to three targets — and the system tracks it against live market prices until it hits a target, hits the stop loss, or expires.

The tracking is the product. Everything else is scaffolding around it.


What it does

  1. An analyst creates a recommendation — picks an instrument (equity, F&O or commodity), sets entry (a fixed rate or a range), a stop loss, and up to three targets, plus a validity window.
  2. The system subscribes to that instrument's live price and watches it.
  3. It resolves the outcome automatically — target hit, stop loss hit, or expired without triggering — and records P&L at the moment of close.

A recommendation moves through: openclosed, with a result of tp (target), sl (stop loss), timeout (expired), or manual (closed by the analyst).


The tracking algorithm

Three services, deliberately decoupled. Prices flow one way, through Redis.

AngelOne SmartAPI (WebSocket2)
          │
          ▼
  MarketPriceFetcher ──writes──▶  Redis price cache
                                        │
                                   reads│
                                        ▼
   OpenTradeRegistry  ◀──────▶  GlobalTradeTracker ──▶ MongoDB
      (open trades)              (SL / TP / expiry)

1. Price ingestion — services/MarketPriceFetcher.ts

Holds a single AngelOne WebSocket connection and writes every tick into Redis. It never serves a request directly; it only fills the cache.

Every 10s it re-scans what needs watching and re-subscribes:

  • tokens of all currently open trades (read from the Redis registry, not the DB)
  • tokens with a pending on-demand CMP request

A REST fallback polls every 5s for tokens the socket hasn't delivered.

This is the only component that talks to the broker API. Centralising it means the tracker can scale to thousands of trades without multiplying API calls.

2. Open-trade registry — services/OpenTradeRegistry.ts

A Redis-backed set of open trades, bootstrapped from MongoDB once at startup ([OpenTradeRegistry] Bootstrapped: N trades). Adding or closing a trade updates Redis immediately, so neither the fetcher nor the tracker ever scans the database in its hot loop.

3. Trade tracking — services/GlobalTradeTracker.ts

The loop that decides outcomes. Runs every 1000 ms, processing trades in parallel chunks of 20. It reads prices from Redis and never calls the broker API itself.

Each cycle, for every open trade:

  • Entry trigger — a trade posted with an entry away from the market stays untriggered until price reaches the entry level or range.
  • Target hit — checks targets in order; a hit records which target and closes with result: "tp".
  • Stop loss hit — closes with result: "sl". If a target had already been hit, the trade closes at the last hit target instead of the stop.
  • Direction awareness — buy and sell calls invert every comparison.

Persistence is batched: live LTP and P&L are flushed to MongoDB every 60s for crash recovery, while state changes (trigger, target, stop, close) are written immediately. Once a day an expiry sweep closes trades that passed their validity without ever triggering.

4. Validity and market hours

Validity presets (Intraday, BTST, 1 Week … 1 Year, or a custom date) resolve to a concrete expiry date. Market hours are IST:

Segment Hours
Equity (NSE/BSE) 09:15 – 15:30
Commodity (MCX) 09:00 – 23:30

An end-of-session sweep runs at 15:16 (equity) and 23:16 (MCX) on weekdays to finalise anything the live tracker missed.


Architecture

front/    Next.js 15 · App Router · NextAuth · Tailwind · Redux Toolkit
server/   Express · TypeScript · MongoDB (Mongoose) · Redis · BullMQ · Socket.IO

Frontend routes

Route Purpose
/ redirects to sign-in
/auth/provider/signin phone + OTP sign-in and analyst registration
/auth/signup/serviceprovider/subprofile/[id] team-member invite signup
/dashboard/serviceprovider/recommendations/create the create form
/dashboard/serviceprovider/recommendations/myrecommendations open and closed calls
/dashboard/serviceprovider/recommendations/performance hit rate and P&L

Backend API

Mount Purpose
/api/auth OTP request/verify, sign-in, analyst signup
/api/scorecard create, modify, close and read recommendations; live CMP
/api/scripts instrument master — symbol, expiry, strike, token lookup
/api/services subscription plans (used by the share-with selector)
/api/data notifications and analyst profile reads
/api/market-data market data helpers
/health liveness probe

Real-time updates reach the browser over Socket.IO; scorecard state changes are broadcast via Redis pub/sub so multiple server instances stay in sync.


Running locally

Prerequisites: Node 20+, MongoDB, Redis, and AngelOne SmartAPI credentials.

# Redis (Docker is easiest)
docker run -d --name stocktracker-redis --restart unless-stopped -p 6379:6379 redis:7-alpine

# Backend  → http://localhost:8080
cd server && npm install && npm run dev

# Frontend → http://localhost:3000
cd front && npm install && npm run dev

server/.env

MONGOOSE_URL=mongodb://localhost:27017/stocktracker
PORT=8080
JWTSECRET=<random 32-byte base64>
NEXTAUTH_URL=http://localhost:3000
NEXT_PUBLIC_BACKEND_URL=http://localhost:8080

# AngelOne SmartAPI — required for live prices and tracking
TOTP=<totp secret>
ANGEL_API_KEY=<key>
ANGEL_ID=<client id>
ANGEL_PASS=<pin>

REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_USERNAME=
REDIS_PASSWORD=
REDIS_USE_TLS=false

front/.env.local

NEXT_PUBLIC_BACKEND_URL=http://localhost:8080
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=<random 32-byte base64>
NEXT_PUBLIC_APEX_DOMAIN=stocktracker.app   # optional; drives subdomain + cookie scope

On a healthy boot the backend logs:

Server up and running on port :- 8080
ScriptMaster sync: N entries already present
[OpenTradeRegistry] Bootstrapped: N trades
MarketPriceFetcher: Starting with WebSocket2 streaming (subscription refresh every 10s)
GlobalTracker: Starting with 1000ms interval, chunk size 20

If those last three lines are missing, tracking is not running.


Deployment

  • Frontend → Vercel. NEXT_PUBLIC_BACKEND_URL is left empty so browser calls stay relative and route through the /api proxy rewrite in next.config.js, avoiding mixed-content blocks. Server-side code needs an absolute origin instead, via BACKEND_INTERNAL_URL.
  • Backend → Docker on EC2, deployed by .github/workflows/deploy-server.yml on push to main. .env lives on the box and is not in the repo.

docker run --env-file is stricter than a shell: no spaces around =, no quotes, no export. A line like KEY = value fails the whole container start.


Notes

  • OTP delivery goes through ProactiveSMS. The message body is bound to a registered DLT template — rewording it (including the sender name) without registering a new template will get every OTP silently rejected by the operator.
  • Instrument master syncs daily at 06:00 IST from AngelOne (~123k instruments) and backs the symbol / expiry / strike pickers.
  • Sub-profiles let an analyst add team members with per-module permissions; a read-only member can view recommendations but not publish them.

About

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages