This article details the architecture of a high-performance pre-trade risk check system crucial for financial trading. It emphasizes the critical distinction between in-path (hot path) and off-path checks, focusing on techniques for achieving sub-millisecond latency for real-time order validation. Key architectural decisions include in-memory state management, single-writer sharding, incremental recalculation, and a robust kill switch mechanism.
Read original on Dev.to #architecturePlacing risk checks directly in the order path (the "hot path") introduces a latency tax on every order. The primary engineering goal is to minimize this overhead while ensuring the checks are robust and accurate. This involves carefully segmenting checks into those that *must* happen synchronously (e.g., position limits, margin, fat-finger bounds) and those that can run asynchronously or inform limits without blocking the order flow (e.g., portfolio analytics, reporting). The core question for in-path checks is: "May this order be sent right now?" Anything else is a design mistake if it blocks the order.
To meet stringent latency requirements, the risk check system maintains all necessary state (positions, orders, margin, limits) directly in the memory of the processing service. This avoids network calls and database queries, which are orders of magnitude slower. The rationale isn't just speed but also correctness; a database represents past state, whereas the hot path needs the absolute current view, including unacknowledged orders.
Database vs. In-Memory State
The database serves as the persistent record of position, but the *known* position for real-time checks resides in memory. This distinction is crucial for both performance and accuracy in high-frequency trading systems.
Full recalculation of an account's exposure and margin on every order would be prohibitively expensive, especially for active traders. The hot path employs incremental recalculation, where incoming orders apply a delta to running aggregates (net/gross exposure, used margin). This ensures the work is proportional to the order, not the portfolio size.
A kill switch is implemented as a separate, atomic path, independent of the main risk machinery to ensure it functions even if the primary system is compromised. It fails closed, stopping new orders if state validity cannot be established, and supports granular scope (firm, desk, account). For state recovery, all risk-altering events are journaled locally. On restart, the journal is replayed to rebuild aggregates, followed by reconciliation against external sources (venue drop copy) before trading resumes for an account. Mismatches lead to alerts, not silent resolution.
Architectural Trade-offs
This architecture makes specific trade-offs: reliance on fill feeds for correctness, potential conservatism for non-additive portfolio margin models, co-dependency of risk engine and order gateway (shared fate), and increased operational overhead compared to database-backed checks. It's best suited for latency-sensitive environments where these trade-offs are acceptable.