HFT & Advanced Concepts
Level 3 — Production (from-scratch derivations, code-from-memory, explain-out-loud) Time Limit: 45 minutes Total Marks: 60
Instructions: Show all derivations. Where code is asked, write it from memory (Python-style pseudocode accepted if syntactically coherent). Where "explain out loud" is indicated, write as if teaching a junior trader.
Question 1 — Market Making Economics from Scratch (12 marks)
A market maker quotes a two-sided market on a stock. The bid is and the ask is . Assume the true (mid) fair value is .
(a) Derive the quoted spread, half-spread, and the market maker's theoretical edge per round-trip (buy at bid, sell at ask). State any assumption about fill symmetry. (4)
(b) The maker fills 8,000 shares per side per day. Exchange rebates are \0.0020$0.015$/share. Derive net daily P&L. (4)
(c) Explain out loud: why does inventory risk force the maker to skew quotes, and what happens to the bid/ask when the maker is long 50,000 shares beyond target inventory? (4)
Question 2 — Latency Arbitrage Derivation (10 marks)
Venue A updates its price at time . Venue B reflects the same price after a propagation delay . An HFT sees A, then races an order to B.
(a) Derive the condition (inequality) under which the latency-arb trade is profitable, in terms of the price move , transaction cost per share , and the probability that the order reaches B before the stale quote is pulled. (5)
(b) Given \delta = \0.03c = $0.005$0.010p_{\min}$. (5)
Question 3 — Execution Algorithm: VWAP from Memory (14 marks)
(a) Write, from memory, the mathematical definition of VWAP over trades. (2)
(b) Derive the difference between a TWAP schedule and a VWAP schedule in terms of how they slice a parent order of shares across intervals. Give the shares-per-interval formula for each. (4)
(c) Write pseudocode (from memory) for a POV (Percentage of Volume) algorithm that targets participation rate , given a live feed of interval market volume. Include a guard for the parent order running out. (5)
(d) Compute the achieved VWAP for the following three fills:
| Trade | Price | Qty |
|---|---|---|
| 1 | 50.00 | 300 |
| 2 | 50.10 | 200 |
| 3 | 49.90 | 500 |
(3)
Question 4 — Colocation, DMA & Smart Order Routing (10 marks)
(a) Explain out loud the difference between colocation and Direct Market Access (DMA), and why colocation confers a latency edge measured in microseconds. (4)
(b) A Smart Order Router (SOR) must fill 1,000 shares. Available liquidity: Venue X has 400 shares @ ; Venue Y has 800 shares @ . Taker fee X = \0.003$0.001$/sh. Derive the routing that minimizes total cost and compute the total cost. (6)
Question 5 — Flash Crashes & Circuit Breakers (8 marks)
(a) Define a flash crash and explain the feedback mechanism by which HFT liquidity withdrawal amplifies it. (4)
(b) A single-stock circuit breaker (Limit Up-Limit Down, LULD) uses a band around a 5-minute reference price of \200.00$. Compute the upper and lower price bands, and state what happens if the price hits a band and stays there. (4)
Question 6 — Regulatory View (6 marks)
Explain out loud the regulator's central concern with HFT and give two specific market-structure rules/mechanisms designed to mitigate HFT-related risks. Justify each. (6)
End of paper.
Answer keyMark scheme & solutions
Question 1 (12)
(a) (4)
- Quoted spread = \text{ask} - \text{bid} = 100.02 - 99.98 = \0.04$. (1)
- Half-spread = 0.04/2 = \0.02$. (1)
- Theoretical edge per round-trip ask bid = \0.04$/share (buy at 99.98, sell at 100.02). (1)
- Assumption: symmetric fills — the maker gets filled equally on both sides so inventory returns to target; edge only realized if both legs execute. (1)
(b) (4)
- Spread capture: two-sided round-trip earns full \0.048000 \times 0.04 = $320$. (1)
- Rebates: added on both sides = 16{,}000 \times 0.0020 = \32$. (1)
- Adverse selection: 16{,}000 \times 0.015 = \240$. (1)
- Net P&L = 320 + 32 - 240 = \112$/day. (1)
(c) (4)
- Inventory risk: holding a directional position exposes the maker to price moves unrelated to spread income. (1)
- To reduce it the maker skews quotes: shift both bid and ask to encourage trades that flatten inventory. (1)
- When long 50,000 beyond target the maker wants to sell, so it lowers the ask (more aggressive to sell) and lowers the bid (less eager to buy more). (1)
- Net effect: quotes shifted down / offer improved, discouraging further buys and inviting fills that reduce the long. (1)
Question 2 (10)
(a) (5)
- Gross gain if order arrives in time . (1)
- If order misses (prob ), assume it earns (quote pulled, no fill). (1)
- Expected profit . (1)
- Profitability condition: , i.e. require and . (1)
- For a minimum required edge : . (1)
(b) (5)
- . (2)
- Require . (1)
- . (2)
Question 3 (14)
(a) (2) (1 for numerator being , 1 for denominator .)
(b) (4)
- TWAP slices evenly over time: shares per interval (independent of volume). (2)
- VWAP slices in proportion to expected volume: shares in interval , where is expected volume in interval . (2)
(c) (5)
def pov_algo(parent_qty, rho, volume_feed):
remaining = parent_qty
for interval_volume in volume_feed:
if remaining <= 0: # guard: order complete
break
target = rho * interval_volume
child = min(target, remaining) # guard: don't over-fill
send_order(child)
remaining -= child
return parent_qty - remaining # total executedMarks: loop over volume feed (1), target = ρ·volume (1), child = min(target, remaining) over-fill guard (1), remaining<=0 completion guard (1), decrement/coherent structure (1).
(d) (3)
- Numerator: . (1)
- Denominator: . (1)
- VWAP = 49970/1000 = \49.97$. (1)
Question 4 (10)
(a) (4)
- DMA: client sends orders directly to the exchange matching engine via broker infrastructure, bypassing manual desk handling. (1) Reduces one layer of latency and gives order-type control. (1)
- Colocation: physically placing the firm's servers in the same data center as the exchange's matching engine. (1) Shortens the physical signal path → propagation & handling reduced to microseconds, a decisive edge in racing/latency-sensitive strategies. (1)
(b) (6)
- Cheapest first: Venue X @ 10.00 with 10.003$/sh; take all 400. (1)
- Venue Y @ 10.01 with 10.011$/sh; take remaining 600. (1)
- (Compare effective prices: X 10.003 < Y 10.011, so fill X fully then Y — this ordering is optimal.) (1)
- Cost X: 400 \times 10.003 = \4001.20$. (1)
- Cost Y: 600 \times 10.011 = \6006.60$. (1)
- Total = 4001.20 + 6006.60 = \10{,}007.80$. (1)
Question 5 (8)
(a) (4)
- Flash crash: a very rapid, deep, and short-lived price collapse (and often recovery) over seconds/minutes. (2)
- Feedback: as prices fall, HFT market makers widen/withdraw quotes to avoid adverse selection → liquidity vanishes → same sell flow moves price further → stop-loss and momentum algos add sells → self-reinforcing spiral. (2)
(b) (4)
- Band of 200 = \10$. (1)
- Upper band = 200 + 10 = \210$. (1)
- Lower band = 200 - 10 = \190$. (1)
- If price hits a band and doesn't move back within band within the window, trading pauses (a brief trading halt / limit state) to let liquidity replenish. (1)
Question 6 (6)
- Central concern: HFT can create unfair speed advantages and fragile/illusory liquidity that vanishes under stress, raising systemic and fairness risks. (2)
- Two mitigations (1 for naming + 1 for justification each, up to 4):
- Circuit breakers / LULD: halt or band trading to stop cascade feedback and restore orderly pricing. (2)
- Speed bumps / minimum resting times / order-to-trade ratios / message throttling: neutralize pure latency races and discourage quote-stuffing / spoofing. (2) (Accept alternatives: kill switches, market-maker obligations, tick-size regimes — each requires a justification.)
[
{"claim":"MM net daily P&L = 112", "code":"spread=8000*0.04; rebate=16000*0.0020; adverse=16000*0.015; result=(spread+rebate-adverse==112)"},
{"claim":"Latency arb p_min = 0.4", "code":"delta=Rational(3,100); c=Rational(5,1000); m=Rational(10,1000); pmin=m/(delta-c); result=(pmin==Rational(2,5))"},
{"claim":"VWAP of three fills = 49.97", "code":"num=50.00*300+50.10*200+49.90*500; den=300+200+500; result=(abs(num/den-49.97)<1e-9)"},
{"claim":"SOR total cost = 10007.80", "code":"x=400*10.003; y=600*10.011; result=(abs((x+y)-10007.80)<1e-6)"},
{"claim":"LULD bands 210 and 190", "code":"ref=200; band=0.05*ref; result=(ref+band==210 and ref-band==190)"}
]