E
Trading platformactive

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

Aspiring traders practicing without capital risk.Finance students learning order types and portfolio behavior.Developers discussing real-time financial system design.

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

Diagram loads when visible

Trading terminal

Dense market workspace with watchlists, order tickets, positions, trade history, and diagnostics.

Next.jsReactTypeScript

Market data layer

Provider adapters fetch quotes and stream updates to the frontend through server-sent events.

FastAPISSEGrowwUpstox

Execution layer

Validates order type, lot size, expiry, margin, and instrument-specific rules before simulating fills.

PythonContract metadata

Portfolio layer

Maintains virtual cash, positions, mark-to-market P&L, risk, and order history.

FastAPI stateLocal persistence

Provider resilience layer

Groww and Upstox adapters normalize tokens, provider preference, quote freshness, and fallback behavior before the UI sees market data.

Groww APIUpstox APIprovider preference

Risk and strategy layer

Margin estimates, charges, leverage, concentration, warnings, and option strategy payoff tables make paper trading more realistic.

risk-engine.tstrading-charges.tsstrategy builder

Terminal command layer

A command parser turns typed workstation commands into order, alert, layout, watchlist, chart, and navigation actions.

command-parser.tscommand palette

Implementation surface

Tech stack

Next.jsFrontend

Trading workstation UI with SSR-friendly routing and dense data surfaces.

TypeScriptFrontend

Typed order tickets, positions, quote payloads, and UI state.

FastAPIBackend

Async backend for quotes, execution, portfolios, and diagnostics.

Server-Sent EventsBackend

Live price updates without repeated polling.

Groww / Upstox adaptersLibrary

Market data provider integration and fallback strategy.

Python zoneinfoLibrary

IST-aware NSE and MCX market-hours calculations with holiday overrides.

Request cacheLibrary

Client-side request deduplication and freshness control for quote and market pages.

VitestDevops

Unit coverage for risk engine, replay math, alerts, request cache, command parser, and trading logic.

Trading charges moduleLibrary

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.

1

Load instruments

The backend exposes stocks, F&O contracts, and commodities with metadata such as lot size, expiry, and tick size.

2

Stream market prices

The terminal opens an SSE connection so active watchlist prices update as quote events arrive.

3

Validate order ticket

The backend checks order side, quantity, lot size, expiry, margin, and stop-loss rules.

4

Simulate execution

Orders are filled virtually according to type and current quote, then written to the order ledger.

5

Update portfolio

Positions, realized P&L, unrealized P&L, exposure, and cash are recalculated after fills and quote changes.

6

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.

7

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.

8

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.

9

Replay and diagnose decisions

Replay and diagnostics screens let users inspect market movement, provider status, and portfolio behavior after simulated trades.

Sequence diagram

Diagram loads when visible

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.

Code highlight loads when visible

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.

Code highlight loads when visible

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.

Code highlight loads when visible

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.

Code highlight loads when visible

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

GET/instruments

Lists tradable stocks, F&O contracts, commodities, and metadata.

GET/market/stream

Streams live quote updates for selected symbols through SSE.

POST/orders

Validates and simulates an order against current market data.

{ "symbol": "RELIANCE", "side": "buy", "quantity": 10, "type": "market" }
{ "orderId": "ord_418", "status": "filled", "averagePrice": 1432.6 }
GET/portfolio

Returns cash, positions, realized P&L, unrealized P&L, and exposure.

GET/api/provider/preference

Returns the active market-data provider preference and fallback status for diagnostics.

POST/api/provider/preference

Updates the runtime market-data provider preference between Groww and Upstox when both are configured.

{ "provider": "upstox" }
GET/api/market/status

Returns NSE or MCX market state computed from IST, weekends, holidays, and segment trading hours.

POST/api/alerts

Creates price, percent move, volume, PCR, IV, or open-interest alerts from parsed workstation commands.

GET/api/diagnostics

Returns provider health, token availability, CORS config, market session state, and data freshness diagnostics.

State model

Database design

Backend state and local browser persistence

Data relationship diagram

Diagram loads when visible

instruments

Tradable metadata including symbol, asset class, lot size, expiry, and tick size.

symbolasset_classlot_sizeexpirytick_size

orders

Virtual order ledger with side, type, status, quantity, and fill price.

order_idsymbolsidetypequantitystatusaverage_price

positions

Current holdings with cost basis, quantity, and mark-to-market value.

symbolquantityaverage_costlast_priceunrealized_pnl

provider_status

Runtime state for the selected provider, token source, freshness, and last successful quote fetch.

providertoken_sourcelast_success_atfreshness_msfallback_reason

risk_snapshot

Derived portfolio risk summary used by the terminal and strategy dashboard.

account_idgross_exposuremargin_usedmargin_availableleveragerisk_score

alerts

User-defined alert rules for price, percent move, volume, PCR, IV, and open-interest changes.

idtickermetricoperatorvalueenabledtriggered_at

command_history

Optional audit trail of parsed terminal commands and their resulting action kind.

idraw_commandparsed_kindcreated_atstatus

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

TradeoffsMedium

Why did EquityFlow choose SSE for quotes?

02:00
ConceptsEasy

What does contract-aware execution protect against?

02:00
ArchitectureHard

How would you make paper trading closer to real execution?

02:00
ArchitectureMedium

Why does EquityFlow need provider freshness metadata?

02:00
CodeHard

How does the risk engine calculate useful portfolio warnings?

02:00
CodeMedium

Why parse terminal commands into discriminated union objects?

02:00
ConceptsMedium

What is different between NSE equity and MCX commodity market-hour logic?

02:00
TradeoffsMedium

Why should paper trading include charges and margin?

02:00
ArchitectureHard

How would you make order fills more realistic?

02:00
BehavioralMedium

What diagnostics would you expose for provider problems?

02:00
TradeoffsHard

How do request caches help and hurt a trading interface?

02:00