How to pass the Groww SDE-2 system design interview

Groww's SDE-2 interviews have a reputation for pushing candidates hard on real-time, high-throughput financial systems. SDE-2s at Groww are expected to take ownership of complex microservices, handle extreme concurrency, and design architectures that can survive massive traffic spikes during market open. If you make it to the system design round, you will likely face one of their favorite challenges: designing an intraday risk management and auto-square-off engine. It is a beast of a problem. You have to process millions of market ticks per second, calculate Mark-to-Market (MTM) losses on the fly, and automatically close out user positions before their margin completely evaporates. Let's break down the exact architecture, algorithms, and concurrency trade-offs you will need to nail this interview.
In a retail brokerage like Groww, intraday trading allows users to buy and sell stocks on the same day using margin (leverage) provided by the broker. If a user has ₹20,000, the broker might allow them to take a position worth ₹1,00,000 (5x leverage). The broker is essentially spotting the user ₹80,000. If the stock price drops, the loss is deducted from the user's ₹20,000 margin. If the loss exceeds that margin, the broker starts losing their own money. To prevent this, the broker's system monitors the live price of the stock and automatically sells the user's position (squares off) when the loss hits a specific threshold, usually 80% of the user's margin. Building the system that does this accurately for millions of concurrent users is what this interview is all about.
The Groww SDE-2 Hiring Process
Before diving into the architecture, it helps to understand where the system design round fits into the overall SDE-2 hiring loop. Groww typically evaluates candidates across four distinct technical and behavioral stages. SDE-2s are heavily vetted not just on whether their systems work, but on how they fail, recover, and scale.
| Round | Focus Area | Duration |
|---|---|---|
| 1. Machine Coding | LLD, concurrency, working code | 90 mins |
| 2. DSA & Problem Solving | Medium/Hard LeetCode, Trees, Graphs | 60 mins |
| 3. System Design | HLD, scalability, fintech architecture | 60 mins |
| 4. Hiring Manager | Behavioral, past projects, culture fit | 60 mins |
Core Requirements for the Auto-Square-Off Engine

When the interviewer drops the auto-square-off prompt, do not immediately start drawing boxes on a whiteboard. Spend the first 10 minutes clarifying the functional and non-functional requirements. This demonstrates seniority and prevents you from designing a system that solves the wrong problem.
For functional requirements, establish exactly what the system needs to do. It must ingest live market data (ticks) from the National Stock Exchange (NSE) and Bombay Stock Exchange (BSE). It must maintain a real-time ledger of all open intraday positions. It must calculate the MTM loss for every open position every time a relevant price tick arrives. Finally, if the MTM loss breaches the 80% margin threshold, it must immediately trigger a market sell/buy order to close the position.
The non-functional requirements are where the real engineering challenge lies. First is ultra-low latency. The time between a price tick arriving and a square-off order hitting the exchange must be in the low milliseconds. Second is high throughput. The Indian stock market generates millions of ticks per second during volatile periods. Your system must process these without a growing backlog. Third is strict ordering. Price updates for a specific stock must be processed in the exact order they occurred. Finally, you need absolute idempotency. The system cannot accidentally send duplicate square-off orders, which would result in the user taking an unintended short position.
High-Level Architecture Data Flow
A modern trading architecture separates the fast-moving market data from the transactional order management system. Here is the step-by-step data flow you should propose to the interviewer:
1. The Exchange Data Gateway receives multicast UDP packets directly from the exchange leased lines. A low-latency service (often written in C++ or Rust) normalizes these raw binary packets into a standard format (like Protobuf) and publishes them to a message broker. 2. Apache Kafka acts as the central nervous system, buffering the incoming ticks. Topics are partitioned by the stock identifier (scrip_id) to ensure strict ordering. 3. The Risk Engine, built on a stateful stream processing framework like Apache Flink, consumes the Kafka topics. It holds the active user portfolios in its local state. 4. As ticks arrive, the Risk Engine updates the internal state, calculates the new MTM, and checks the margin threshold. 5. If a breach is detected, the Risk Engine fires a 'SQUARE_OFF_COMMAND' to a separate Kafka topic. 6. The Order Management System (OMS) consumes this command, acquires a distributed lock on the user's position, verifies the position is still open in the primary database, and routes the market order to the exchange.
Groww SDE-2 Interview Questions
How do you stream live price ticks and update portfolio state?
Market data gateways pull in ticks directly from the exchange. Because the throughput is absolutely massive—easily hitting millions of events per second across thousands of scrips—you want to ingest these ticks right into a distributed event streaming platform like Apache Kafka. The interviewer will ask how you guarantee that prices are processed in the correct order. The answer is Kafka partitioning. You must partition your topics by scrip_id (for example, all ticks for Reliance go to Partition 1, all ticks for TCS go to Partition 2). Doing this guarantees that every single tick for a specific stock hits the exact same consumer thread in the exact order it was generated. If you process prices out of order, you might calculate a false MTM and trigger an illegal square-off.
When it comes to processing, a framework like Apache Flink works beautifully. Flink consumes the Kafka stream, windows the data if you need to throttle updates, and joins those live prices directly with the user's portfolio state. You obviously cannot query a traditional database like PostgreSQL for every single tick—that would instantly melt your infrastructure with millions of read queries per second. Instead, you need to keep the active intraday portfolio states in memory.
You have two choices here. You can use Flink's native state backend (like RocksDB) to keep the portfolio state directly inside the processing nodes. Alternatively, you can use an external in-memory datastore like Redis Cluster. If you choose Redis, you would structure the data using Redis Hashes. The key would be `portfolio:{user_id}:{scrip_id}`, and the fields would include `quantity`, `average_buy_price`, and `allocated_margin`. When a tick arrives, the system fetches this hash, calculates the difference between the current tick price and the average buy price, multiplies it by the quantity, and checks if the resulting loss exceeds 80% of the allocated margin.
How do you calculate Mark-to-Market (MTM) at scale?
Figuring out MTM for millions of users on every single tick creates a brutal fan-out problem. Just think about it: if one highly traded stock like HDFC Bank updates its price 50 times a second, and 500,000 retail traders hold an active intraday position in HDFC Bank, you suddenly have to perform 25 million calculations per second just for one stock. A standard stateless microservice architecture pulling data from a database simply will not survive this load. The network I/O overhead alone will introduce seconds of latency, which is unacceptable in trading.
To solve this, you need to bring the compute to the data, not the data to the compute. One highly effective architectural pattern for this is the Actor Model, implemented via frameworks like Akka (Scala/Java) or Erlang/Elixir. In this design, you treat each user's intraday portfolio as a lightweight, in-memory actor. When a tick rolls in from Kafka, a publisher broadcasts it to a PubSub channel specific to that stock. All user actors that hold that stock are subscribed to that channel. The actor receives the price locally in memory, updates its internal state, calculates the fresh MTM instantly without any network calls, and checks if it crossed the margin threshold. If it does, the actor itself emits the square-off event.
If you'd rather stick to a Redis-centric architecture instead of introducing Akka, Redis Lua scripts are your best friend. Lua scripts execute atomically inside the Redis server. You can write a script that takes the new stock price as an input, reads the user's buy price and quantity, computes the total loss, and returns a boolean flag if the 80% threshold gets breached. This pushes the calculation down into the data layer, saving you expensive network round trips and avoiding race conditions during the read-calculate-write cycle.
How do you concurrently trigger auto-square-off without race conditions?
Here is the edge case that keeps trading system engineers awake at night: the double-spend or duplicate order race condition. Imagine a scenario where a user sees their position tanking and manually hits the 'Exit Position' button on their Groww app at the exact millisecond the automated Risk Engine triggers an auto-square-off for the same position. Both requests hit the Order Management System (OMS) simultaneously. If the OMS processes both, it will send two sell orders to the exchange. The user originally bought 100 shares. The system just sold 200 shares. The user is now accidentally short 100 shares. In trading systems, that is a catastrophic failure that exposes the broker to massive regulatory fines and financial risk.
To prevent this, your OMS has to enforce bulletproof idempotency and concurrency control. You cannot rely on application-level checks like `if (position.isOpen()) { sell() }` because both threads will read `isOpen() == true` before either has a chance to update the database. You need database-level guarantees.
The most robust approach is using Optimistic Concurrency Control (OCC) right in your primary relational database, usually PostgreSQL. You add a `version` integer column to the `positions` table. When the OMS receives a square-off command, it first reads the current state: `SELECT version, status FROM positions WHERE position_id = 'P123'`. Let's say the version is 5 and status is 'OPEN'. The system then attempts to update the row with a strict WHERE clause: `UPDATE positions SET status = 'SQUARED_OFF', version = 6 WHERE position_id = 'P123' AND version = 5 AND status = 'OPEN'`. If the user's manual exit transaction hit the database a millisecond earlier, it would have already incremented the version to 6. The automated square-off update will affect 0 rows. The application code checks the affected row count, realizes the state changed, and safely aborts the duplicate order.
Another solid approach, especially if you need to lock resources across multiple microservices before hitting the database, is using a distributed lock like Redlock (Redis). When the square-off event arrives, the OMS attempts to acquire a lock on the key `lock:position:P123`. The manual exit API also tries to acquire this exact same lock. Whichever request gets the lock proceeds, while the other waits or fails fast. Once the first request finishes and updates the database, the second request acquires the lock, reads the fresh database state, sees the position is already closed, and drops the operation.
Handling Edge Cases and Exchange Failures
Interviewers at Groww will push you on failure scenarios. The happy path is easy, but what happens when external systems break? One common scenario is when a stock hits its lower circuit limit. In the Indian market, if a stock drops too fast, the exchange halts trading or restricts the price band. If a stock hits the lower circuit, there are literally zero buyers in the market. If your risk engine triggers an auto-square-off market sell order at this exact moment, the exchange will accept the order, but it will sit pending in the order book. It will not execute.
Your system needs a feedback loop from the exchange. The OMS must listen to order execution reports (often via the FIX protocol). If the square-off order remains pending for too long, or is explicitly rejected by the exchange, the system needs a state machine to handle it. It should immediately alert the risk operations team via a dashboard. In some cases, if the broker's risk policy allows, the system might cancel the pending market order and retry with a limit order, or attempt to square off other profitable positions in the user's portfolio to free up margin and cover the liability.
You also need to account for internal infrastructure failures. What if the Kafka cluster goes down? You need a Multi-AZ deployment with In-Sync Replicas (ISR) set to at least 2, ensuring that even if an entire availability zone drops, no market ticks or square-off commands are lost. What if a Risk Engine processing node crashes mid-calculation? If you are using Flink, you rely on its distributed snapshotting mechanism. Flink periodically checkpoints its in-memory state to a durable storage like AWS S3 or HDFS. If a node dies, a new one spins up, loads the last checkpoint, replays the Kafka events from the checkpoint offset, and resumes processing without missing a single margin breach.
Capacity Planning and Infrastructure Sizing
A senior system design interview isn't complete without some back-of-the-envelope math. Let's estimate the load for a platform like Groww. Assume there are 4,000 actively traded scrips on the NSE. During peak market hours (like the first 15 minutes of the trading day), the exchange might emit up to 10,000 ticks per second. If Groww has 1 million active intraday traders, and each trader holds an average of 3 open positions, you have 3 million active intraday positions to track.
If you store these 3 million positions in Redis, and each position hash takes about 200 bytes, the total memory required for the active state is roughly 600 MB. This easily fits into a single Redis node, but you would deploy a Redis Cluster with multiple shards anyway to distribute the read/write CPU load. The real bottleneck is network bandwidth and CPU for the MTM calculations. If a highly volatile stock updates 100 times a second, and 100,000 users hold it, your Risk Engine is doing 10 million calculations per second. This requires a heavily partitioned compute cluster. Assuming a single modern CPU core can handle 50,000 simple arithmetic calculations and threshold checks per second, you would need at least 200 cores dedicated purely to the Risk Engine during peak volatility to maintain sub-millisecond latency.
Frequently asked questions
What is the most important metric for a risk management system?
Latency beats everything else. Your system has to process ticks, calculate MTM, and fire off square-off orders in sub-milliseconds. If it lags during extreme market volatility, the stock price will continue to drop while your system is catching up, and the broker ends up eating the user's financial liability.
Why use Kafka for market data ingestion?
Kafka handles massive throughput and offers great fault tolerance, but its real superpower here is partitioning data by scrip_id. That guarantees all price updates for a given stock get processed sequentially by the exact same consumer, completely eliminating out-of-order price calculations which would corrupt the risk evaluation.
How do you handle database failures during trading hours?
You want to rely heavily on in-memory datastores like Redis for the high-speed real-time operations, backed by persistent storage. For your transactional source of truth, use a highly available relational database like PostgreSQL with synchronous replication. If your primary database suddenly drops during trading hours, an automatic failover (using a tool like Patroni) promotes a hot standby to primary in seconds, keeping the disruption virtually unnoticeable to the trading engine.
What happens if the auto-square-off order is rejected by the exchange?
You need a solid state machine and a robust retry mechanism built in. If an exchange rejects the order—maybe a stock hit its upper or lower circuit limits and trading is halted—the system needs to log that failure immediately. From there, it should alert the risk operations team dashboard and try to square off the position using alternative order types, assuming the broker's compliance rules allow it.
Related comparisons
See AcePrompt in action
Watch how AcePrompt supports a real technical round - structured answers, tuned to your resume, in real time.
Ace your next system design interview with real-time AI guidance.
Get started