Project dossier
EquityFlow
Real-time paper trading workstation with contract-aware execution and live market streams.
What it solves
Overview
EquityFlow lets users practice stocks, futures, options, and commodity trading with virtual capital, live data streams, order validation, portfolio tracking, and market diagnostics. Interview focus: explain provider preference and fallback, Groww/Upstox auth, Indian market-hours logic, request caching, SSE quote streams, risk scoring, margin estimation, trading charges, command parsing, alert rules, replay lab behavior, and why paper execution must still respect real instrument contracts.
Target audience
System design
Architecture
The platform is split between a Next.js trading terminal and a FastAPI backend. The backend streams market data, validates instrument contracts, executes virtual orders, and recalculates positions and P&L. The source code includes a FastAPI backend with Groww-primary and Upstox fallback market data, CORS/env validation, NSE and MCX holiday calendars, provider preference, SSE streaming, Next.js terminal layouts, command parsing, risk engine, strategy payoff calculations, alerts, request caching, and replay tests.
Architecture diagram
Trading terminal
Dense market workspace with watchlists, order tickets, positions, trade history, and diagnostics.
Market data layer
Provider adapters fetch quotes and stream updates to the frontend through server-sent events.
Execution layer
Validates order type, lot size, expiry, margin, and instrument-specific rules before simulating fills.
Portfolio layer
Maintains virtual cash, positions, mark-to-market P&L, risk, and order history.
Provider resilience layer
Groww and Upstox adapters normalize tokens, provider preference, quote freshness, and fallback behavior before the UI sees market data.
Risk and strategy layer
Margin estimates, charges, leverage, concentration, warnings, and option strategy payoff tables make paper trading more realistic.
Terminal command layer
A command parser turns typed workstation commands into order, alert, layout, watchlist, chart, and navigation actions.
Implementation surface
Tech stack
Trading workstation UI with SSR-friendly routing and dense data surfaces.
Typed order tickets, positions, quote payloads, and UI state.
Async backend for quotes, execution, portfolios, and diagnostics.
Live price updates without repeated polling.
Market data provider integration and fallback strategy.
IST-aware NSE and MCX market-hours calculations with holiday overrides.
Client-side request deduplication and freshness control for quote and market pages.
Unit coverage for risk engine, replay math, alerts, request cache, command parser, and trading logic.
Estimates brokerage-style fees so paper P&L is not unrealistically clean.
Operational flow
How it works
The user watches live instruments, places virtual orders, the backend validates contract rules, simulates fills at market prices, and streams portfolio changes back to the terminal.
Load instruments
The backend exposes stocks, F&O contracts, and commodities with metadata such as lot size, expiry, and tick size.
Stream market prices
The terminal opens an SSE connection so active watchlist prices update as quote events arrive.
Validate order ticket
The backend checks order side, quantity, lot size, expiry, margin, and stop-loss rules.
Simulate execution
Orders are filled virtually according to type and current quote, then written to the order ledger.
Update portfolio
Positions, realized P&L, unrealized P&L, exposure, and cash are recalculated after fills and quote changes.
Check market session state
The backend computes NSE and MCX open, preopen, and closed states using IST, weekends, holiday sets, and segment-specific hours.
Session state controls whether a quote or execution path should be labeled live, delayed, closed, or fallback.
Estimate margin and risk
Before and after orders, the risk engine estimates notional value, charges, required margin, leverage, concentration, and warnings.
This is why the paper account teaches exposure discipline instead of just calculating raw profit and loss.
Parse workstation commands
Terminal commands such as buy, sell, alert, layout, watch, chart, and goto are parsed into typed actions with sanitized tickers.
The command layer is a productivity feature but also a type-safety boundary for dense trading workflows.
Replay and diagnose decisions
Replay and diagnostics screens let users inspect market movement, provider status, and portfolio behavior after simulated trades.
Sequence diagram
Concept depth
Key concepts
Paper trading lets users practice order placement, risk management, and strategy behavior without risking capital.
In EquityFlow: EquityFlow executes orders against live quotes but updates a virtual portfolio instead of a brokerage account.
Confidence
Implementation evidence
Code highlights
Contract-aware order validation
The execution engine rejects orders that do not satisfy instrument metadata.
The same order ticket means different things for stocks, options, futures, and commodities.
Validation happens before virtual portfolio mutation.
SSE quote stream
The backend sends quote updates as server-sent events for the active watchlist.
SSE is adequate because the client receives market updates and sends orders through normal HTTP.
The interval is tuned for freshness without hammering upstream providers.
Portfolio risk scoring
The risk engine combines leverage, margin usage, and concentration warnings instead of showing only P&L.
Risk is derived from exposure and margin, not only account balance.
The scoring formula is explainable enough for a portfolio interview answer.
Typed terminal command parser
The workstation command bar converts concise text into safe structured actions.
The parser returns a discriminated union, so each command kind can be handled safely.
Ticker cleaning prevents invalid characters from entering trading actions.
Contracts
API design
Base URL: http://localhost:8000/api
/instrumentsLists tradable stocks, F&O contracts, commodities, and metadata.
/market/streamStreams live quote updates for selected symbols through SSE.
/ordersValidates and simulates an order against current market data.
{ "symbol": "RELIANCE", "side": "buy", "quantity": 10, "type": "market" }{ "orderId": "ord_418", "status": "filled", "averagePrice": 1432.6 }/portfolioReturns cash, positions, realized P&L, unrealized P&L, and exposure.
/api/provider/preferenceReturns the active market-data provider preference and fallback status for diagnostics.
/api/provider/preferenceUpdates the runtime market-data provider preference between Groww and Upstox when both are configured.
{ "provider": "upstox" }/api/market/statusReturns NSE or MCX market state computed from IST, weekends, holidays, and segment trading hours.
/api/alertsCreates price, percent move, volume, PCR, IV, or open-interest alerts from parsed workstation commands.
/api/diagnosticsReturns provider health, token availability, CORS config, market session state, and data freshness diagnostics.
State model
Database design
Data relationship diagram
instruments
Tradable metadata including symbol, asset class, lot size, expiry, and tick size.
orders
Virtual order ledger with side, type, status, quantity, and fill price.
positions
Current holdings with cost basis, quantity, and mark-to-market value.
provider_status
Runtime state for the selected provider, token source, freshness, and last successful quote fetch.
risk_snapshot
Derived portfolio risk summary used by the terminal and strategy dashboard.
alerts
User-defined alert rules for price, percent move, volume, PCR, IV, and open-interest changes.
command_history
Optional audit trail of parsed terminal commands and their resulting action kind.
Architecture decisions
Trade-offs
Realtime transport
Server-Sent Events over Polling
SSE keeps quote updates fresh without requiring every card to poll repeatedly. The order path can remain normal HTTP.
Backend language
FastAPI over Express
The data and execution logic is Python-heavy, and FastAPI handles concurrent market data I/O cleanly.
Validation model
Contract-aware rules over Generic buy/sell form
A trading simulator that ignores lot sizes, expiry, and margin teaches the wrong behavior for F&O and commodities.
Data provider strategy
Groww-primary with Upstox fallback over One hard-coded market-data provider
Provider APIs can be unavailable or incomplete for some instruments. A preference and fallback model improves reliability and makes diagnostics explicit.
Power-user workflow
Terminal command parser over Only form-based interactions
Dense trading workstations benefit from keyboard-first actions, but the parser still returns typed actions so validation remains explicit.
Risk model
Approximate margin and concentration warnings over Only virtual cash balance
A simulator that ignores leverage and margin teaches poor trading habits. Approximate rules are better than pretending every product is cash equity.
Market session logic
Backend IST market-hours gates over Frontend-only time labels
The backend owns quote and execution semantics, so it should compute whether a market is open, preopen, or closed.
Lessons learned
Challenges and solutions
Problem
Live provider data can be stale, delayed, or unavailable for specific symbols.
Solution: Add provider preference, freshness checks, and fallback behavior instead of showing stale prices as current.
Lesson: Market UIs need to make data freshness visible, not hide it behind a nice chart.
Problem
Different asset classes make one-size-fits-all order validation unsafe.
Solution: Use instrument metadata to validate each order before execution.
Lesson: Financial correctness belongs in backend rules, not just frontend form constraints.
Problem
Provider tokens can be configured in different formats, including raw tokens and Bearer-prefixed strings.
Solution: Normalize access tokens on startup and log provider readiness clearly without exposing secrets.
Lesson: Integration code should be forgiving about input format while strict about secret handling.
Problem
Market hours differ between NSE equity and MCX commodity sessions.
Solution: Use segment-specific session helpers, Asia/Kolkata time, and holiday override environment variables.
Lesson: Financial UX correctness depends on calendars and clocks, not only quote APIs.
Problem
Command palette actions can become unsafe if they bypass normal form validation.
Solution: Parse commands into typed objects, sanitize tickers, then route them through the same order and alert validation paths.
Lesson: Keyboard speed should not bypass domain rules.
Runbook
Requirements and future work
Requirements
- Node.js and npm for the Next.js frontend.
- Python 3.x with FastAPI for backend APIs.
- Market data provider access or configured fallback quotes.
- Instrument metadata for stocks, F&O, and commodity contracts.
- GROWW_API_KEY/GROWW_API_SECRET or GROWW_ACCESS_TOKEN is required for Groww-backed live endpoints.
- UPSTOX_ACCESS_TOKEN or OAuth credentials are required for Upstox-backed endpoints.
- CORS_ALLOW_ORIGINS or local dev regex must allow the Next.js frontend origin.
- NSE_HOLIDAYS and MCX_HOLIDAYS can override default holiday sets for session accuracy.
- Vitest coverage should be kept for risk, replay, alerts, command parser, and request cache behavior.
Future improvements
- Add strategy backtesting against stored historical data.
- Persist accounts, orders, and positions in a database.
- Add risk controls such as max drawdown, exposure caps, and scenario replay.
- Persist paper accounts, orders, alerts, and command history across devices.
- Add broker-style order states such as pending, rejected, partially filled, modified, and cancelled.
- Add slippage and spread-aware fills using bid/ask depth rather than last-traded price only.
- Add provider data-quality dashboards with latency, freshness, error rate, and fallback counts.
Active recall
Interview Q&A
Why did EquityFlow choose SSE for quotes?
What does contract-aware execution protect against?
How would you make paper trading closer to real execution?
Why does EquityFlow need provider freshness metadata?
How does the risk engine calculate useful portfolio warnings?
Why parse terminal commands into discriminated union objects?
What is different between NSE equity and MCX commodity market-hour logic?
Why should paper trading include charges and margin?
How would you make order fills more realistic?
What diagnostics would you expose for provider problems?
How do request caches help and hurt a trading interface?