Position limits, margin, fat-finger bounds and a kill switch have to answer on every order before it leaves the gateway. This is how those checks live inside the order path instead of beside it: what state sits in memory, what is recomputed incrementally, and what happens after a restart. The constraints come first.
An order arrives at the gateway. Before it goes out to the venue, something has to decide whether the account is allowed to send it. That decision runs on every order, including the overwhelming majority that are perfectly fine, so its cost is paid by all normal traffic and not only by the rejects.
That is the constraint to name first. A risk check placed in the order path is a tax on order entry. The engineering question is not how to make the check clever, it is how to make it small enough that traders do not feel it, and honest enough that it still refuses the orders it must refuse.
The hot path answers exactly one question: may this order be sent right now, given what we currently know about this account. Checks that answer that question stay in. Checks that answer a different question move out.
Everything else runs beside the path, on the same state, without holding the order. It informs the limits that the hot path enforces, but it does not sit between the trader and the venue.
The dividing line is a question, not a category. In the path: may this order go out. Beside the path: what should the limits be. Anything that answers the second question and still blocks the order is a design mistake, however important the check is.
The state a pre-trade check needs - current positions, working orders, used and available margin, limit configuration - lives in the memory of the process that makes the decision. Not in a cache in front of a database, not behind a network call. In the process.
The reason is not only speed, though a query is orders of magnitude more expensive than a lookup in a local array. The reason is correctness. A database holds the position as it was written. The risk check needs the position including orders sent a moment ago that have not been filled, acknowledged or persisted yet. If you read from storage, you check against a past that has already been overtaken by your own flow.
Practically, that shapes the process the way any low-latency component gets shaped:
The database is where the position is recorded. It is not where the position is known.
A full recomputation of an account's exposure and margin walks every position and every working order. That cost grows with the size of the book, which means the risk check would get slower for exactly the clients who trade the most. So the hot path does not recompute. It applies a delta.
The account carries running aggregates - net and gross exposure per instrument and per group, used margin, notional in flight. An incoming order produces a small change to those aggregates, the changed values are compared against the limits, and the order is accepted or rejected. The work is proportional to the order, not to the portfolio.
Full recomputation still happens - on a schedule, when margin parameters change, and as a periodic self-check against the incremental result. It runs off the path, on a copy, and its result is either swapped in or raised as a discrepancy. Incremental state that silently drifts from the true state is worse than no check at all, so the comparison is not optional.
Measured on the risk path we build, the pre-trade check itself completes in <1 ms. That figure covers the decision on in-memory state, not the full journey of an order from the client to the venue and back.
A kill switch is used precisely when something is already wrong. That rules out building it on top of the machinery that may itself be the thing that is wrong. It is a separate path, with its own rules.
Stopping new orders is the easy half. The harder half is what the switch does to orders already resting at the venue: pulling quotes and cancelling working orders has to be possible while the sending path is disabled. That cancel path deserves its own testing, because it is exercised on the worst day rather than on a normal one.
In-memory state is a derived view of a durable record. That is what makes a restart survivable. Every event that changes risk state - an order accepted, a reservation released, a fill applied, a limit changed, the switch engaged - is appended to a journal on the local machine before it is acted upon downstream.
Recovery time then depends on journal length and drop copy availability, not on the size of the book, and the failure mode of every unknown is the same: refuse to trade the account.
The honest limits are worth stating plainly, because they decide whether this architecture fits at all:
amBrain builds this kind of pre-trade risk path for brokers and prop firms, with the hot paths written in Rust. The team has worked on trading infrastructure from Yerevan, Armenia since 2019.
Our engineering team specializes in FinTech solutions. Let's discuss how we can bring your project to life.