Quantitative Finance · Book 11 · Market making

Market Making and High-Frequency Trading

Market Making and High-Frequency Trading · Market making

27Risk 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 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): 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 for the firm and each desk, an order rate, open orders, a loss limit 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.
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, 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 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). A loss limit 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) 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), 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).

controlstops afterlossfires on ordinary days
none (the 45 minutes of 2012)2 700 s$477 million–
a person at 5 minutes300 s$53 million–
order-rate throttle, 500 a secondnever$161 million10.2%
price collar, 5%600 s$106 million0%
capital threshold, $1 billion gross407 s$72 million0%
position limit, $250 million gross102 s$18 million7.6%
loss limit, $2 million, each second12 s$2.1 million0%
all of them35 s$2.1 million10.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.
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, a $1 billion capital threshold, a $250 million position limit and a $2 million loss limit 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 and the capital threshold, the controls the market access rule 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, in twelve seconds. Together they stop it at 35 seconds: the throttle, by slowing the runaway, delays the loss limit, but the loss is the same.

Each threshold is a trade-off (Figure 27.3): a tighter loss limit 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 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 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.
Figure 27.3. 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.

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 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 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 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; 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 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, checked every second, take to fire?

Solution

Solution of Exercise 27.1.

The loss grows at 148 100×1.16=$171 800148\,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

Solution of Exercise 27.2.

250/2.46=102250/2.46=102 seconds and 1 000/2.46=4071\,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

Solution of Exercise 27.3.

42.10/40.00−1=5.25%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

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 alone (12)?

Solution

Solution of Exercise 27.5.

The throttle slows the loss, so the loss limit’s threshold is reached later; the loss at the stop is the same.

Exercise 27.6 ★★

What should a kill switch do first: cancel or flatten? Why?

Solution

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 fires on no more than 1% of ordinary days, and what does it let the runaway lose?

Solution

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 costs us nothing.”

Solution

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 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.

  1. Define a pre-trade risk check and a price collar.
  2. Define a loss limit and a kill switch.
  3. Describe the limits hierarchy and the snapshot’s validation.
  4. How does the snapshot reach the nanosecond gate?

Part III — Measurements.

  1. Give the stopping time and loss under each control.
  2. Which controls fire on ordinary days, and how often?
  3. Describe the loss-limit and position-limit trade-offs.
  4. Why does the loss limit dominate, and what does the position limit add?

Part IV — The verdict.

  1. State the named result: the loss the runaway would have made under each control, and the earliest control that stops it.
  2. Which set of controls would you run, with which thresholds?
  3. Who should be able to pull the kill switch, and how fast?
  4. What must the audit record?
  5. What does a runaway that loses slowly need?
  6. How would you test the controls without a runaway?
  7. What should a firm’s chief executive certify?
  8. In one sentence: what does a risk control buy?
Solution

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; 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 and Definition 27.2.
  6. See Definition 27.3 and Definition 27.5.
  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 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 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, which stops it first, after 12 seconds.
  14. A loss limit 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 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

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

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 at 10:05 on a volatile day and was flattened. The market recovered by 10:30. Was the limit wrong?

Solution

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

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 for a firm connected to 20 venues through 3 gateways. What must happen in the first millisecond?

Solution

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 that minimises the expected cost of false alarms plus the runaway’s expected loss, given a runaway once in NN days.

Solution

Solution of Interview question 27.6.

Expected cost per day c P(D<−L)+1Nℓ τ(L)c\,P(D<-L)+\frac1N\ell\,\tau(L) with τ(L)=L/ℓ\tau(L)=L/\ell, so the second term is L/NL/N; with cc the cost of a false alarm, set c ϕ((L+μ)/σ)/σ=1/Nc\,\phi((L+\mu)/\sigma)/\sigma=1/N and solve for LL.

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

Terms defined in this chapter

See all 2333 terms in the glossary