---
title: "Risk Controls"
book: "Market Making and High-Frequency Trading"
subject: quant
language: en
chapter: 27
exercises: 8
source: https://one-course.com/books/quant/11/en/chapter/27-risk-controls
---

# Chapter 27 — Risk Controls

On 1 August 2012 a market maker’s routing system sent millions of orders into the market in about forty-five minutes. It obtained over 4 million executions in 154 stocks, for more than 397 million shares, and lost more than $460 million. The regulator’s order afterwards reads as a checklist of the controls it did not have. In this chapter’s reconstruction, a [loss limit](#def-hf-risk-controls-loss) of $2 million checked every second would have stopped the same runaway after twelve seconds and $2.1 million, without firing once on 2 500 ordinary days; an order-rate throttle, the control most often named first, would not have stopped it at all.

## 27.1 Pre-trade limits

A market maker’s orders pass through a pre-trade gate before they reach a venue: a set of checks that refuse any order that breaks a limit. One Quant Book 13, chapter 22 builds the gate that runs these checks in nanoseconds; this chapter sets the policy it enforces.

**Definition 27.1 (Pre-trade risk check).**

A *pre-trade risk check* is a test an order must pass before it is sent to a venue, against limits on its size, value and price and on the positions, open orders and exposures it would create, refusing the order if any limit would be broken.

**Definition 27.2 (Price collar).**

A *price collar* is a pre-trade limit on how far an order’s price may be from a reference price (the last trade, the mid, a fair value), in basis points or ticks, above which a buy or below which a sell is refused as a probable error.

The limits form a hierarchy ([Figure 27.1](#fig-hf-risk-controls-hierarchy)): the firm, its desks, their strategies, the instruments. Each level caps what the levels below it can add up to. The chapter’s schema (`firm.riskctl`) writes it as a snapshot the gate can load: gross exposure and [loss limits](#def-hf-risk-controls-loss) for the firm and each desk, an order rate, open orders, a [loss limit](#def-hf-risk-controls-loss) and a position limit for each strategy, and a collar, a maximum quantity and notional and long and short limits for each instrument. A snapshot is validated before it is used (every desk within the firm’s limits, every strategy on a known desk) and exported with the gate’s section, which Book 13’s gate reads as it stands.

![The limits hierarchy and the three places it acts: the pre-trade gate refuses an order that breaks a limit; the post-trade monitor watches losses, positions and message rates and triggers the kill switch, which cancels open orders, flattens positions and blocks new orders at the level that broke. Source: firm.riskctl; the gate is One Quant Book 13’s firm.riskgate.](https://one-course.com/images/onecourse/chapters/quant-11/hf-risk-controls/fig-60b33e8eeb0e.svg)

***Figure 27.1.** The limits hierarchy and the three places it acts: the pre-trade gate refuses an order that breaks a limit; the post-trade monitor watches losses, positions and message rates and triggers the [kill switch](#def-hf-risk-controls-kill), which cancels open orders, flattens positions and blocks new orders at the level that broke. Source: `firm.riskctl`; the gate is One Quant Book 13’s `firm.riskgate`.*

## 27.2 Position, loss and message limits

**Definition 27.3 (Loss limit).**

A *loss limit* is a threshold on the realised plus marked-to-market loss of a strategy, desk or firm over a period (a day, usually), beyond which the loss triggers a kill action at that level.

Position and [loss limits](#def-hf-risk-controls-loss) are checked after trades as well as before them: the gate can refuse an order that would exceed a position, but only a monitor that marks positions to the market sees a loss build ([Listing 27.1](#lst-hf-risk-controls-monitor)). A [loss limit](#def-hf-risk-controls-loss) is the most direct control of all, since it limits what is being protected, but it acts only after the loss has happened and only as often as positions are marked. Message limits (chapter 10’s throttles and order-to-trade ratios) protect the venue and the firm’s standing with it; the firm’s own limit on messages a second is a monitor on the whole firm, not a strategy.

## 27.3 Price collars and fat-finger checks

Collars and size checks catch the error in a single order: a price far from the market, a quantity or notional far above normal. On 2 May 2022 a bank’s trader who meant to sell a $58 million basket created one of $444 billion; the bank’s controls blocked $255 billion of it but let $189 billion reach a trading algorithm, which sold about $1.4 billion in European markets before it was cancelled. The UK’s conduct regulator, fining the bank £27.8 million in 2024, found that no hard block would have rejected the basket in its entirety, that the trader could close a pop-up alert without reading it, and that real-time monitoring was too slow.

**As of September 2026 — The rules on market access and algorithmic trading.**

The SEC adopted Rule 15c3-5 in November 2010: brokers or dealers with market access must maintain risk management controls reasonably designed to prevent erroneous orders and orders that exceed pre-set credit and capital thresholds, and their chief executive must certify them. Its order of 16 October 2013 fined the market maker of the 2012 runaway $12 million for violating the rule. In the European Union, Commission Delegated Regulation (EU) 2017/589 requires an investment firm to be able to cancel immediately, as an emergency measure, any or all of its unexecuted orders on any or all venues, and to identify the algorithm and trader responsible for each order. The UK’s Financial Conduct Authority fined a bank £27 766 200 on 22 May 2024 over the 2022 basket error, and the Prudential Regulation Authority a further £33 880 000.

**Definition 27.4 (Market access rule).**

The *market access rule* is SEC Rule 15c3-5, which requires a broker-dealer with access to an exchange or alternative trading system, for itself or its customers, to have documented, regularly reviewed pre-trade controls against erroneous orders and orders beyond pre-set credit and capital thresholds, under its direct and exclusive control.

## 27.4 Kill switches: who pulls them and when

**Definition 27.5 (Kill switch).**

A *kill switch* is a control that, when triggered by a person or by a monitor, stops a strategy, desk or the whole firm from trading at once: it cancels its open orders, refuses new ones and, if so configured, flattens its positions, and it records who pulled it and why.

The chapter’s runaway ([Listing 27.2](#lst-hf-risk-controls-runaway)) takes the SEC order’s figures: about 1 480 orders a second of 100 shares for 45 minutes, a loss of $1.16 a share traded, and $2.46 million a second of gross position (the $3.5 billion long and $3.15 billion short it ended with). Stopping it flattens the position at 0.2% of its value. Each control, alone, stops it at a different time ([Figure 27.2](#fig-hf-risk-controls-controls)), and each fires on some share of ordinary days of a legitimate book (peak rates around 300 messages a second, gross positions around $150 million, intraday drawdowns around $150 000, orders within tens of basis points of their references).

| control | stops after | loss | fires on ordinary days |
| --- | --- | --- | --- |
| none (the 45 minutes of 2012) | 2 700 s | $477 million | – |
| a person at 5 minutes | 300 s | $53 million | – |
| order-rate throttle, 500 a second | never | $161 million | 10.2% |
| [price collar](#def-hf-risk-controls-collar), 5% | 600 s | $106 million | 0% |
| capital threshold, $1 billion gross | 407 s | $72 million | 0% |
| position limit, $250 million gross | 102 s | $18 million | 7.6% |
| [loss limit](#def-hf-risk-controls-loss), $2 million, each second | 12 s | $2.1 million | 0% |
| all of them | 35 s | $2.1 million | 10.2% |

![The loss of a runaway shaped on the 2012 incident under each control alone and under all of them together (log scale, $ million): no control (stopped by hand at 45 minutes), a person at 5 minutes, an order-rate throttle of 500 a second, a 5% price collar, a $1 billion capital threshold, a $250 million position limit and a $2 million loss limit marked each second. Data: hf_risk.table.](https://one-course.com/images/onecourse/chapters/quant-11/hf-risk-controls/fig-9d4ddbaf711d.svg)

***Figure 27.2.** The loss of a runaway shaped on the 2012 incident under each control alone and under all of them together (log scale, $ million): no control (stopped by hand at 45 minutes), a person at 5 minutes, an order-rate throttle of 500 a second, a 5% [price collar](#def-hf-risk-controls-collar), a $1 billion capital threshold, a $250 million position limit and a $2 million [loss limit](#def-hf-risk-controls-loss) marked each second. Data: `hf_risk.table`.*

The throttle, often the first control named, does not stop anything: it slows the runaway to a third and the loss follows, $161 million by the end. The [price collar](#def-hf-risk-controls-collar) and the capital threshold, the controls the [market access rule](#def-hf-risk-controls-access) names, stop it after ten and seven minutes at $106 and $72 million. The position limit stops it in under two minutes; the [loss limit](#def-hf-risk-controls-loss), in twelve seconds. Together they stop it at 35 seconds: the throttle, by slowing the runaway, delays the [loss limit](#def-hf-risk-controls-loss), but the loss is the same.

Each threshold is a trade-off ([Figure 27.3](#fig-hf-risk-controls-tradeoff)): a tighter [loss limit](#def-hf-risk-controls-loss) stops the runaway sooner but fires on ordinary days, 2% of them at $1 million, 19% at $500 000; a position limit tight enough to stop it in a minute fires on half of all days. The [loss limit](#def-hf-risk-controls-loss) dominates: for the same false alarms it stops the runaway much sooner, because it measures what matters. The position limit catches what the [loss limit](#def-hf-risk-controls-loss) cannot: a runaway that has not yet lost.

![The trade-off of a threshold: the runaway’s loss under a loss limit ($0.5 to $4 million) and under a gross position limit ($100 to $600 million) against the share of 2 500 ordinary days on which each would have fired. Data: hf_risk.sweep.](https://one-course.com/images/onecourse/chapters/quant-11/hf-risk-controls/fig-58c5e3ed167a.svg)

***Figure 27.3.** The trade-off of a threshold: the runaway’s loss under a [loss limit](#def-hf-risk-controls-loss) ($0.5 to $4 million) and under a gross position limit ($100 to $600 million) against the share of 2 500 ordinary days on which each would have fired. Data: `hf_risk.sweep`.*

Who pulls the switch matters as much as when. A monitor fires in a second; a person takes minutes to see, understand and act, and in 2012 took forty-five. The [kill switch](#def-hf-risk-controls-kill) must be reachable by the monitor and by a person, must cancel before it flattens, must act on every venue at once (as the EU’s rule requires), and must leave an audit trail of who pulled it and why (`firm.riskctl.KillSwitch`).

## 27.5 The regulatory requirements for algorithmic firms

The rules in the dated box converge on the same controls: pre-trade limits on price, size and value; limits on credit and capital; a kill function; knowing which algorithm and trader sent each order; and review of the controls by management. The regulators’ orders read as descriptions of what went wrong when one was missing: in 2012, no control on the aggregate capital the orders committed, and no automated alert that led to action in time; in 2022, a size check that could be overridden and monitoring too slow to act.

## 27.6 Tutorial: forty-five minutes

**Goal.** Write the limits snapshot, export it for the gate, and measure what each control would have saved against a 2012-shaped runaway and what it costs on ordinary days. **End state:** the table and the three figures.

1. **The snapshot** : `firm.riskctl.validate` and `export` ; `riskctl_fixture.py` writes `data/limits.json` , which One Quant Book 13’s `firm.riskgate.from_riskctl` loads.
2. **The monitor**: marks, [loss limits](#def-hf-risk-controls-loss) and kill actions at each level. `def mark (self , t: float , prices: dict ) -> list : self .last.update(prices) out = [] desks: dict = {} for name, s in self .d[" strategies " ].items(): p = self .pnl(name) desks[s[" desk " ]] = desks.get(s[" desk " ], 0.0 ) + p if p < -s[" max_loss_usd " ]: self .sw.kill(t, " strategy " , name, " flatten " , f " loss { p: .0f } " ) out.append((" strategy " , name, " flatten " )) for name, p in desks.items(): if p < -self .d[" desks " ][name][" max_loss_usd " ]: self .sw.kill(t, " desk " , name, " flatten " , f " loss { p: .0f } " ) out.append((" desk " , name, " flatten " )) if sum (desks.values()) < -self .d[" firm " ][" max_loss_usd " ]: self .sw.kill(t, " firm " , " " , " flatten " , " firm loss " ) out.append((" firm " , " " , " flatten " )) return out` **Listing 27.1.** Marks positions to the market, sums strategies into desks and the firm, and kills at the level whose loss limit breaks. code/firm/riskctl/firm_riskctl.py
3. **The runaway** under each control. `r = RUNAWAY | kw rate = min (r[" orders_per_s " ], controls.get(" throttle " , math.inf)) loss_rate = rate * r[" shares " ] * r[" loss_per_share " ] gross_rate = r[" gross_per_s " ] * rate / r[" orders_per_s " ] stops = {" end of the runaway " : float (seconds)} if " position " in controls: stops[" position limit " ] = controls[" position " ] / gross_rate if " capital " in controls: stops[" capital threshold " ] = controls[" capital " ] / gross_rate if " loss " in controls: mark = controls.get(" mark_s " , 1.0 ) stops[" loss limit " ] = math.ceil(controls[" loss " ] / loss_rate / mark) * mark if " collar_bp " in controls: stops[" price collar " ] = controls[" collar_bp " ] / 1e4 / r[" drift_per_min " ] * 60.0 if " human_s " in controls: stops[" kill switch (person) " ] = controls[" human_s " ] who = min (stops, key=stops.get) t = min (stops[who], seconds) loss = loss_rate * t + flatten_cost * gross_rate * t return {" stopped_by " : who, " seconds " : t, " loss " : loss, " gross " : gross_rate * t, " orders " : rate * t}` **Listing 27.2.** Each control’s stopping time; the first one stops the runaway, which is then flattened. code/firm/riskctl/firm_riskctl.py
4. **Ordinary days** and the threshold sweeps ( `hf_risk.table` , `hf_risk.sweep` ).

**What to change next.** Replay the runaway through Book 13’s gate on `firm.exchsim` (its `firm_riskgate_runaway`); add a second runaway that loses slowly and see which control catches it; make the [loss limit](#def-hf-risk-controls-loss) intraday-drawdown based.

## 27.7 Build: the risk controls

**Purpose.** Own the limits policy (hierarchy, schema, validation), the post-trade monitors and the [kill switch](#def-hf-risk-controls-kill); hand the pre-trade gate its snapshot.

**Interface.** `validate(limits)`, `to_riskgate(limits)`, `export(limits)`, `KillSwitch`, `Monitor(limits, switch)` with `on_fill`, `mark`, `on_message`; `runaway(controls)`, `normal_days(controls)`. The schema, version 1, is in the module’s docstring and is the contract with Book 13’s `firm.riskgate`.

**Rules.** Dollars, shares, nanoseconds; a desk within the firm’s limits; kills recorded with their reason; cancel before flatten.

**Acceptance tests.** `code/firm/riskctl/tests/`: validation catches a desk above the firm and an unknown desk; the gate section by hand; the fixture equals the export and Book 13’s gate loads it and refuses an order outside the collar; the monitor kills a strategy beyond its [loss limit](#def-hf-risk-controls-loss) and the firm beyond its message rate, and the audit records kill and unkill; the runaway and ordinary days behave as in the chapter.

**Stretch.** Intraday drawdown limits; per-venue kill; limits changed during the day with versioned snapshots.

Sources and further reading

- US Securities and Exchange Commission, *In the Matter of Knight Capital Americas LLC* , Release No. 34-70694, 16 October 2013.
- Commission Delegated Regulation (EU) 2017/589, Article 12 (kill functionality).
- Financial Conduct Authority, FCA fines CGML £27 766 200 for failures in its trading systems and controls, 22 May 2024.

## 27.8 Exercises

**Exercise 27.1 ★.**

The runaway loses $1.16 a share on 148 100 shares a second. How long does a $2 million [loss limit](#def-hf-risk-controls-loss), checked every second, take to fire?

**Solution of Exercise 27.1.**

The loss grows at $148\,100\times1.16=\$171\,800$ a second: $2 million after 11.6 seconds, so the check at 12 seconds fires.

**Exercise 27.2 ★.**

Gross position grows by $2.46 million a second. When does a $250 million position limit stop it, and a $1 billion capital threshold?

**Solution of Exercise 27.2.**

$250/2.46=102$ seconds and $1\,000/2.46=407$ seconds.

**Exercise 27.3 ★.**

A buy order is priced at $42.10 against a reference of $40.00. Does a 5% collar refuse it?

**Solution of Exercise 27.3.**

$42.10/40.00-1=5.25\%$, beyond the 5% collar: refused.

**Exercise 27.4 ★★.**

Why does the throttle not stop the runaway, and what is it for?

**Solution of Exercise 27.4.**

It limits how fast orders go out, not what they commit: the runaway continues at a third of its speed and loses a third as much. It protects the venues and the firm’s standing with them, and slows any runaway so that other controls have time.

**Exercise 27.5 ★★.**

Why does adding every control stop the runaway later (35 seconds) than the [loss limit](#def-hf-risk-controls-loss) alone (12)?

**Solution of Exercise 27.5.**

The throttle slows the loss, so the [loss limit](#def-hf-risk-controls-loss)’s threshold is reached later; the loss at the stop is the same.

**Exercise 27.6 ★★.**

What should a [kill switch](#def-hf-risk-controls-kill) do first: cancel or flatten? Why?

**Solution of Exercise 27.6.**

Cancel first: open orders can still fill and add to the position while it is being flattened; flattening a position that keeps growing is chasing it.

**Exercise 27.7 ★★★.**

*Coding.* With `hf_risk.sweep`, which [loss limit](#def-hf-risk-controls-loss) fires on no more than 1% of ordinary days, and what does it let the runaway lose?

**Solution of Exercise 27.7.**

$1.5 million fires on no ordinary day of the 2 500 ($1 million fires on 2%); the runaway loses $1.6 million before it.

**Exercise 27.8 ★★★.**

*Find the flaw.* “Our algorithm has never lost more than $500 000 in a day, so a $500 000 [loss limit](#def-hf-risk-controls-loss) costs us nothing.”

**Solution of Exercise 27.8.**

The history is of days the algorithm behaved; a volatile day can exceed it without anything going wrong. In the model a $500 000 limit fires on 19% of ordinary days: its cost is the trading lost on those days and the flattening at bad prices.

## 27.9 Problem: Forty-Five Minutes

**Problem 27.1.**

Weekend problem — forty-five minutes

A market-making firm sets its risk controls after reading the 2012 order.

**Part I — The incident and the rules.**

1. Summarise what happened on 1 August 2012, by the SEC’s order.
2. Define the [market access rule](#def-hf-risk-controls-access) and what it requires.
3. What does the EU’s kill functionality require?
4. What went wrong in the 2022 basket error, by the FCA’s account?

**Part II — The controls.**

5. Define a [pre-trade risk check](#def-hf-risk-controls-pretrade) and a [price collar](#def-hf-risk-controls-collar) .
6. Define a [loss limit](#def-hf-risk-controls-loss) and a [kill switch](#def-hf-risk-controls-kill) .
7. Describe the limits hierarchy and the snapshot’s validation.
8. How does the snapshot reach the nanosecond gate?

**Part III — Measurements.**

9. Give the stopping time and loss under each control.
10. Which controls fire on ordinary days, and how often?
11. Describe the loss-limit and position-limit trade-offs.
12. Why does the [loss limit](#def-hf-risk-controls-loss) dominate, and what does the position limit add?

**Part IV — The verdict.**

13. State the *named result* : the loss the runaway would have made under each control, and the earliest control that stops it.
14. Which set of controls would you run, with which thresholds?
15. Who should be able to pull the [kill switch](#def-hf-risk-controls-kill) , and how fast?
16. What must the audit record?
17. What does a runaway that loses slowly need?
18. How would you test the controls without a runaway?
19. What should a firm’s chief executive certify?
20. In one sentence: what does a risk control buy?

**Solution of Problem 27.1.**

1. Its routing system sent millions of orders in about 45 minutes: over 4 million executions in 154 stocks, 397 million shares, $3.5 billion long and $3.15 billion short, and a loss over $460 million.
2. See [Definition 27.4](#def-hf-risk-controls-access) ; controls against erroneous orders and orders beyond credit and capital thresholds, documented, reviewed, certified.
3. Cancelling immediately any or all unexecuted orders on any or all venues, and knowing which algorithm and trader sent each order.
4. A $58 million basket entered as $444 billion; $189 billion passed controls to an algorithm that sold $1.4 billion; no hard block, an overridable alert, slow monitoring.
5. See [Definition 27.1](#def-hf-risk-controls-pretrade) and [Definition 27.2](#def-hf-risk-controls-collar) .
6. See [Definition 27.3](#def-hf-risk-controls-loss) and [Definition 27.5](#def-hf-risk-controls-kill) .
7. Firm, desks, strategies, instruments; every desk within the firm’s limits, every strategy on a known desk, every limit positive.
8. Exported with a gate section that Book 13’s gate loads with its `from_riskctl` adapter.
9. Throttle never ($161 million); collar 600 s ($106 million); capital 407 s ($72 million); position 102 s ($18 million); [loss limit](#def-hf-risk-controls-loss) 12 s ($2.1 million); a person at 5 minutes $53 million; none $477 million.
10. The throttle on 10.2% and the position limit on 7.6%; the others on none.
11. Tighter thresholds stop the runaway sooner and fire on more ordinary days: [loss limits](#def-hf-risk-controls-loss) 2% at $1 million and 19% at $500 000; position limits half of all days at $150 million.
12. It measures what the controls protect, so for the same false alarms it stops sooner; the position limit catches a runaway that has not yet lost.
13. $477 million with none, $161 million with a throttle, $106 million with a collar, $72 million with a capital threshold, $18 million with a position limit and $2.1 million with a [loss limit](#def-hf-risk-controls-loss) , which stops it first, after 12 seconds.
14. A [loss limit](#def-hf-risk-controls-loss) and a position limit at every level, a collar and size checks on every order, a capital threshold, a throttle for the venues; the [loss limit](#def-hf-risk-controls-loss) at $1.5–2 million for this book.
15. Monitors automatically, and people on the desk and in risk, within seconds, on every venue at once.
16. Who, when, which level, which action, and why.
17. A position or exposure limit and a monitor of positions that do not match the strategy’s normal behaviour.
18. Replay recorded days and planted faults through the gate (Book 13’s runaway on the exchange simulator).
19. That the controls exist, are reasonably designed and are reviewed regularly.
20. A bound on how much can go wrong before anyone understands why.

## 27.10 Interview questions

**Interview question 27.1 ★ risk.**

List the pre-trade checks you would require on every order, in the order you would run them.

**Solution of Interview question 27.1.**

Kill state, stale limits, reference price, collar, quantity, notional, worst-case position, open orders, gross exposure, rate, duplicates: cheapest and most decisive first.

*What the interviewer is looking for: a complete, ordered list.*

**Interview question 27.2 ★★ developer.**

Your gate refuses orders when its limits snapshot is stale. Why fail closed, and what could go wrong?

**Solution of Interview question 27.2.**

Without current limits the gate cannot know an order is safe; refusing is the safe error. The risk is an outage of trading from a lost heartbeat, so the snapshot’s publisher must be monitored and redundant.

*What the interviewer is looking for: fail closed and its cost.*

**Interview question 27.3 ★★ trader.**

Your strategy hit its [loss limit](#def-hf-risk-controls-loss) at 10:05 on a volatile day and was flattened. The market recovered by 10:30. Was the limit wrong?

**Solution of Interview question 27.3.**

Not necessarily: a limit is a bound on what can go wrong, not a forecast. Review whether the loss was the strategy’s normal risk (limit too tight) or a malfunction (limit worked).

*What the interviewer is looking for: limits as bounds, reviewed after firing.*

**Interview question 27.4 ★★ risk.**

How would you set a strategy’s position limit from its history?

**Solution of Interview question 27.4.**

From the distribution of its daily peak positions, set above a high quantile so it rarely fires, and below what the firm can lose at a stressed price move.

*What the interviewer is looking for: history and stress.*

**Interview question 27.5 ★★ developer.**

Design the [kill switch](#def-hf-risk-controls-kill) for a firm connected to 20 venues through 3 gateways. What must happen in the first millisecond?

**Solution of Interview question 27.5.**

Block new orders at every gateway at once, send mass cancels on every session (or rely on cancel-on-disconnect), then flatten; the state must be shared so no gateway sends another order.

*What the interviewer is looking for: block, cancel, then flatten, everywhere.*

**Interview question 27.6 ★★★ researcher.**

With ordinary daily drawdowns normal with mean $\mu$ and standard deviation $\sigma$, and a runaway losing at rate $\ell$ per second, find the [loss limit](#def-hf-risk-controls-loss) that minimises the expected cost of false alarms plus the runaway’s expected loss, given a runaway once in $N$ days.

**Solution of Interview question 27.6.**

Expected cost per day $c\,P(D<-L)+\frac1N\ell\,\tau(L)$ with $\tau(L)=L/\ell$, so the second term is $L/N$; with $c$ the cost of a false alarm, set $c\,\phi((L+\mu)/\sigma)/\sigma=1/N$ and solve for $L$.

*What the interviewer is looking for: marginal false-alarm cost against marginal runaway loss.*
