Lesson 5.4: Market making and optimal execution
Learn how market makers earn the spread and handle inventory and adverse selection, Avellaneda-Stoikov quotes, and how execution algorithms and benchmarks work.
By the end of this lesson you will be able to explain how a market maker earns the spread and what takes the profit away, work out the break-even spread against informed traders, compute inventory-adjusted quotes with the Avellaneda–Stoikov rule, show why skewing quotes against inventory cuts risk, and describe how execution algorithms and benchmarks such as arrival price, TWAP and VWAP work. You will show that a market maker facing 10 per cent informed traders who move the price by 0.50 needs a half-spread of 0.05, that holding five shares of inventory moves the quotes from 99.34 and 100.66 to 99.22 and 100.53 in the lesson's example, that in a toy simulation a small inventory skew cuts the standard deviation of profit from 36.3 to 3.1 for almost no loss of average profit while too large a skew turns the profit negative, and that a buyer who matches the market's volume pattern gets the VWAP of 500.29 and still pays 5.8 basis points over the price at the start. You should have read Lessons 1.1, 1.4 and 4.4. The mathematics is percentages, averages and one logarithm. This course is education about how markets and research work, not investment advice.
Every strategy in this module has a counterparty. When a trend follower buys, someone sells, and often that someone is a market maker: a trader who stands ready to buy and sell at all times, quoting a price at which they will buy, the bid, and a price at which they will sell, the ask, and living on the gap. Lesson 1.1 described the order book and Lesson 1.4 the cost of crossing the spread. This lesson takes the point of view of the person on the other side, and then of the person on this side who must buy or sell a large amount without moving the market against themselves.
What a market maker does
A market maker continually places a buy order slightly below the current price and a sell order slightly above it. If both are hit, the market maker earns the difference, the spread, with no view on the market's direction. Over a day a good market maker does this thousands of times, in many instruments. The business sounds like free money, and the competition for it is fierce: other market makers quote too, so the spread is driven down, and the winners are those with the fastest systems, the lowest fees and the best risk control.
Where does the profit go? Three things eat the spread.
1. Adverse selection. Some of the traders who hit your quote know something you do not. If you buy from a trader who knows the price is about to fall, you lose. Informed traders are, by definition, the ones who trade right before a move, so the trades a market maker gets are not a random sample: the ones that go against it are over-represented.
2. Inventory risk. Each trade changes your position. Buy more than you sell, and you hold shares whose price might fall before you can sell them. The market maker is not a speculator, but inventory exposes them to the market anyway.
3. Costs and competition. Fees, technology, capital and the need to out-quote rivals.
Adverse selection: the spread as an insurance premium
The first economic model of this, by Lawrence Glosten and Paul Milgrom in 1985, says that the spread exists because some traders are informed. Think of a simple case. A fraction π of the traders who might hit your quote are informed: they know the price is about to move by an amount J. The rest are uninformed, trading for reasons unrelated to the price, such as raising cash.
Suppose you quote a half-spread of h on each side. Against an uninformed trader you earn h. Against an informed trader you lose, because the price moves by J against you after the trade, and you gained h from the quote: net J − h lost. To break even,
(1 − π) × h = π × (J − h), which gives h = π × J.
Worked example 1. If 10 per cent of the flow is informed and informed traders know the price will move by 0.50, then the break-even half-spread is 0.10 × 0.50 = 0.05, and the full spread is 0.10. If the informed share rises to 20 per cent, the spread must double to 0.20 just to avoid losing. This is why spreads widen before earnings announcements, in thinly traded stocks and in fast markets: the chance of facing an informed trader is higher, and the market maker raises the price of insurance. It is the same logic as Lesson 1.4's point that the spread is not a fee: it is the price of the risk of trading with someone better informed.
Inventory risk and the Avellaneda–Stoikov quotes
Suppose the market maker has bought more than sold, and now holds q shares. They would like to sell some. How should they change their quotes? Marco Avellaneda and Sasha Stoikov answered this in 2008 with a model in which the market maker is averse to risk, with a risk-aversion parameter γ. In their solution, the market maker centres their quotes on a reservation price that is lower than the market's mid price when they hold inventory, and higher when they are short:
reservation price = s − q × γ × σ² × (T − t)
where s is the mid price, q is the inventory (negative when short), σ is the price volatility and T − t is the time left until the end of the trading period. The quotes are placed symmetrically around the reservation price, with a total spread of
spread = γ × σ² × (T − t) + (2 ÷ γ) × ln(1 + γ ÷ k)
where k describes how fast the arrival of orders falls as the quote moves away from the mid price. The first term of the spread compensates for risk: it grows with volatility and with risk aversion. The second compensates for the lower chance of being hit when quoting wider.
Worked example 2. Take a mid price of 100, an inventory of five shares, γ = 0.1, σ = 0.5, T − t = 1 and k = 1.5. The reservation price is 100 − 5 × 0.1 × 0.25 × 1 = 99.875. The spread is 0.1 × 0.25 × 1 + (2 ÷ 0.1) × ln(1 + 0.1 ÷ 1.5) = 0.025 + 20 × 0.0645 = 1.316. The quotes are 99.875 ± 0.658, a bid of 99.217 and an ask of 100.533. With no inventory the quotes would be centred on 100, at 99.342 and 100.658. Holding five shares moves both quotes down by 0.125. The bid is now less attractive, so you are less likely to buy more, and the ask is closer to the market, so you are more likely to sell. The inventory tends to correct itself, without a trade in the market at a bad price. That is the idea: let your quotes, not your orders, manage your inventory.
A toy market maker
To see the effect, we built a simple simulation. The mid price takes small random steps. The market maker quotes a bid and an ask, each 0.05 away from a reservation price that is shifted by the inventory times a skew parameter. Orders arrive at the quotes with a probability that falls the further the quote is from the mid price. In addition, in 2 per cent of the steps an informed trader hits the stale quote just before the price jumps by 0.3 against the market maker. We ran 2,000 steps for each of 200 simulated days, and compared three skews: none, a small one (0.02 per share of inventory) and a large one (0.10 per share).
Skew per share of inventory · Mean profit per day · Standard deviation of profit · Standard deviation of inventory · Largest inventory heldNone · 23.6 · 36.3 · 10.0 · 32.9
Small (0.02) · 22.8 · 3.1 · 1.1 · 3.7
Large (0.10) · −7.2 · 2.7 · 0.7 · 2.3
The profit is in currency units for one-share trades, so only the comparison matters. With no skew, the market maker makes money on average but carries an inventory that wanders as far as 33 shares, and the profit has a huge standard deviation of 36.3, larger than the mean. A small skew cuts the standard deviation of profit by a factor of twelve, to 3.1, and the inventory to about a tenth, at a cost of less than 1 unit of the average profit. Skewing is the cheapest risk control a market maker has. A large skew goes too far: the quotes chase the inventory so aggressively that the market maker sells at prices below the mid and buys above it, giving away the spread, and the average profit is negative.
What is hard in real market making
The toy leaves out most of what makes the business difficult.
Speed. Quotes must be updated as the market moves. A quote that is stale for a few milliseconds is an invitation to a faster trader.
Queue position. In an order book that matches by price and time, being first at a price matters. A passive order near the back of the queue fills only when the price is about to move through it, which is exactly when you do not want to be filled.
Predicting short-term price moves. Good market makers estimate which way the price is about to move, from the order book and from related instruments, and quote accordingly.
Fees and rebates. Exchanges charge or pay for adding and taking liquidity, and these can be as large as the spread.
Risk limits and capital. Limits on inventory, on loss per day and on exposure per instrument, and a kill switch that stops the system if something is wrong.
Hedging. In options, the market maker hedges the exposure to the underlying price continuously, which links to the volatility lesson of Module 6.
Regulation and market structure. Rules on quoting obligations, order-to-trade ratios and tick sizes differ across exchanges, so check the rules of the market you trade.
Market making is not a retail strategy. It is an industrial one, where the edge is in technology, risk control and exchange relationships. But its logic explains so much of how prices behave that a quant needs to understand it: spreads, depth, the footprint of informed trading and the cost of liquidity all come from the market maker's problem.
Execution: the other side of the problem
A fund that wants to buy ₹10 crore of a share cannot simply send one order. A large market order would walk through the order book, pay the spread and move the price, as Lesson 4.4 showed. Execution is the craft of getting a large order done at a good average price, and it is where much of the real cost of trading is decided. The main tools:
TWAP (time-weighted average price) splits the order evenly across a period, for example the same amount every five minutes.
VWAP (volume-weighted average price) splits the order in proportion to the market's expected volume pattern, trading more when the market is busy, which is typically near the open and the close.
POV (percentage of volume) trades a fixed share of whatever the market volume is, such as 10 per cent, finishing whenever the volume allows.
Implementation shortfall or arrival price strategies try to minimise the gap between the price when the decision was made and the average price paid, trading faster when the price is moving away and slower when it is not.
Passive and aggressive orders. A limit order that waits at the bid earns the spread but might not fill, or fill only when the price moves against you. A market order fills at once but crosses the spread. Algorithms mix both.
Auctions and other venues. Some orders are placed in the opening or closing auction, where there is large natural volume.
The tension: impact against timing risk
Trading slowly lowers market impact, since each slice is small. But it leaves the unexecuted part of the order exposed to the market for longer. The price may move against you while you wait, which is timing risk. If you trade at a steady pace over a period T, the standard deviation of the price move over the period, for the average unexecuted position, is roughly σ × √(T ÷ 3), which grows with the time taken. Robert Almgren and Neil Chriss formalised the trade-off in 2000: the best schedule balances the cost of impact against the risk of delay, and depends on how risk-averse the trader is and how urgent the order is.
Benchmarks: measuring execution honestly
How do you tell whether an execution was good? Compare the average price with a benchmark, and be aware of what each benchmark hides.
Worked example 3. You decide to buy at a price of ₹500.00. You buy 30,000 shares over five intervals, taking 20 per cent of the market volume in each. The average prices of the intervals are ₹500.10, ₹500.25, ₹500.40, ₹500.20 and ₹500.55, and the market volumes are 40,000, 25,000, 20,000, 30,000 and 35,000 shares. Your fills are 8,000, 5,000, 4,000, 6,000 and 7,000 shares, and your average price is ₹500.29.
Against VWAP. The market's volume-weighted price over the same intervals is also ₹500.29, so you matched it exactly, 0.0 basis points. This is no surprise: trading in proportion to market volume gives the VWAP by construction.
Against TWAP. The simple average of the interval prices is ₹500.30, so you beat it by 0.2 basis points.
Against arrival price. The price when you decided was ₹500.00, so you paid 0.29 more, 5.8 basis points, or ₹8,700 on 30,000 shares.
A benchmark of VWAP says you did "perfectly", and the arrival price says the order cost ₹8,700. The difference is the drift of the price while you were buying, which a VWAP benchmark cannot see. This is why many institutions measure implementation shortfall, which includes the delay, and why a VWAP algorithm is a good tool for a patient order and a poor one for an urgent one.
The practice of execution rests on measurement. Record the arrival price for every order, the fills and the benchmarks, and study the results by size, by stock and by algorithm. The costs you measure should feed back into the cost model of your backtest.
The code below computes the Avellaneda–Stoikov quotes, the break-even spread, the toy market maker with three skews, and the execution benchmarks.
python
import numpy as np
from math import exp, log
1. Avellaneda-Stoikov quotes
mid, inventory, gamma, sigma, horizon, k = 100.0, 5, 0.1, 0.5, 1.0, 1.5
reservation = mid - inventory gamma sigma 2 horizon
spread = gamma sigma 2 horizon + (2 / gamma) log(1 + gamma / k)
print("reservation price", round(reservation, 3), "| spread", round(spread, 3),
"| bid", round(reservation - spread / 2, 3), "ask", round(reservation + spread / 2, 3))
print("with no inventory: bid", round(mid - spread / 2, 3), "ask", round(mid + spread / 2, 3))
2. break-even half-spread against informed traders: (1 - p) h = p (J - h) -> h = p J
pinformed, jump = 0.10, 0.50
print("break-even half-spread", pinformed jump, "-> spread", 2 pinformed jump)
3. a toy market maker
def runday(seed, skew, steps=2000, sigma=0.02, half=0.05, A=0.5, kk=20.0):
rng = np.random.defaultrng(seed)
mid, q, cash, inventorypath = 100.0, 0, 0.0, []
for in range(steps):
step = rng.normal(0, sigma)
reservation = mid - skew q # quotes move against the inventory
bid, ask = reservation - half, reservation + half
pbid = min(A exp(-kk max(mid - bid, 0)) if mid - bid > 0 else A, 1)
pask = min(A exp(-kk max(ask - mid, 0)) if ask - mid > 0 else A, 1)
u1, u2 = rng.random(), rng.random()
jump = 0.0
if rng.random() < 0.02: # an informed trader hits the stale quote, then the price jumps
jump = 0.3 (1 if rng.random() < 0.5 else -1)
if jump > 0:
q -= 1; cash += ask
else:
q += 1; cash -= bid
if u1 < pbid:
q += 1; cash -= bid
if u2 < pask:
q -= 1; cash += ask
mid += step + jump
inventorypath.append(q)
return cash + q mid, np.std(inventorypath), np.abs(inventorypath).max()
for skew in (0.0, 0.02, 0.1):
res = np.array([runday(seed, skew) for seed in range(200)])
print(f"skew {skew}: mean P&L {res[:, 0].mean():.2f} | sd of P&L {res[:, 0].std():.2f}"
f" | inventory sd {res[:, 1].mean():.2f} | largest inventory {res[:, 2].mean():.1f}")
4. execution benchmarks
prices = np.array([500.10, 500.25, 500.40, 500.20, 500.55])
volume = np.array([40, 25, 20, 30, 35]) 1000.0
ours = 0.20 volume # participate at 20% of each interval's volume
arrival = 500.00
ouravg = (prices ours).sum() / ours.sum()
vwap = (prices volume).sum() / volume.sum()
print("shares bought", ours.sum(), "| our average", round(ouravg, 2), "| market VWAP", round(vwap, 2), "| TWAP", round(prices.mean(), 2))
print("shortfall against arrival", round((ouravg - arrival) / arrival 1e4, 1), "bp, Rs", round((ouravg - arrival) ours.sum()),
"| against VWAP", round((ouravg - vwap) / vwap 1e4, 1), "bp")
5. timing risk of a slow execution: order of 5% of daily volume at 10% participation, volatility 2% a day
size, rate, volbp = 0.05, 0.10, 200
duration = size / rate
print("duration (fraction of a day)", duration, "| timing risk", round(volbp (duration / 3) 0.5, 1), "bp",
"| impact", round(volbp size 0.5, 1), "bp")
Common mistakes
Treating the spread as free money. It is payment for adverse selection and inventory risk, and a market maker who ignores them goes broke.
Quoting symmetrically around the mid price with a large inventory. Skew the quotes against the position.
Skewing too hard. Chasing the inventory gives away the spread, as the large-skew row showed.
Ignoring stale quotes. A quote that is a few milliseconds late is a gift to the informed.
Executing a large order as one market order. The impact is larger and the price you pay is worse.
Judging execution only against VWAP. It hides the drift of the price during the order, so also measure against the arrival price.
Trading too slowly for an urgent signal. Timing risk and the decay of the signal can cost more than the impact you saved.
Not feeding measured costs back. Backtests need the real shortfall of your orders, not a generic number.
Assuming a market maker's edge is a retail one. It depends on speed, fees and risk systems.
Key takeaways
A market maker posts a bid and an ask and earns the spread, which pays for adverse selection, inventory risk and costs. Competition keeps the spread near the cost of doing business.
With a fraction π of informed flow and a price move J, the break-even half-spread is π × J: with 10 per cent informed and J = 0.50 it is 0.05, and it doubles if the informed share doubles.
Avellaneda–Stoikov quotes centre on a reservation price s − qγσ²(T − t), with a spread of γσ²(T − t) + (2 ÷ γ) ln(1 + γ ÷ k). In the example, five shares of inventory move the quotes from 99.342 and 100.658 to 99.217 and 100.533.
In a toy simulation a small inventory skew cut the standard deviation of profit from 36.3 to 3.1 and of inventory from 10.0 to 1.1, for almost no loss of the average profit. A large skew made the profit negative.
Execution algorithms split a large order: TWAP by time, VWAP by volume, POV by a share of volume, and implementation-shortfall algorithms by the arrival price.
Trading slowly lowers impact and raises timing risk, about σ × √(T ÷ 3). Faster execution costs more impact and less risk.
A buyer who matches market volume gets the VWAP by construction: ₹500.29 against ₹500.00 at arrival, a shortfall of 5.8 basis points or ₹8,700. Measure against the arrival price as well as VWAP.
Check yourself
1. 5 per cent of the flow in a share is informed, and informed traders know the price will move by 2.0. What is the break-even full spread?
Half-spread = 0.05 × 2.0 = 0.10, so the full spread is 0.20.
2. A market maker holds an inventory of −10 shares (short) with γ = 0.1, σ = 0.4 and T − t = 1. Where is the reservation price when the mid is 50?
Reservation price = 50 − (−10) × 0.1 × 0.16 × 1 = 50 + 0.16 = 50.16. A short position moves the quotes up, to encourage buying back.
3. Why does a market maker's profit fall when the quotes are skewed too aggressively against inventory?
The quotes move so far from the mid price that the market maker sells below it and buys above it, giving up the spread and sometimes paying it, in order to cut inventory.
4. An order of 8 per cent of daily volume is traded at 16 per cent of market volume in a stock with 1.5 per cent daily volatility. What is the duration and the timing risk?
Duration = 8 ÷ 16 = 0.5 of a day. Timing risk = 150 × √(0.5 ÷ 3) = 150 × 0.408 = 61 basis points.
5. You buy at an average of ₹250.40. The arrival price was ₹250.00 and the day's VWAP was ₹250.38. How do you judge the execution?
The shortfall against arrival is 0.40 ÷ 250 = 16 basis points. Against VWAP you paid 0.02, 0.8 basis points more. Against VWAP it looks fine, but the arrival price shows that most of the cost came from the price drifting up while you bought.
Try this
Set aside forty-five minutes. You need Python and the code in this lesson.
1. Run the code. Check the Avellaneda–Stoikov quotes, the three rows of the market-maker table and the execution benchmarks.
2. Change the informed trader probability in the simulation from 2 per cent to 5 per cent and then to 0.5 per cent. How does the average profit change for each skew?
3. Search for the skew that gives the highest average profit per unit of standard deviation, trying values between 0.005 and 0.06.
4. Change the participation in the execution example from 20 per cent to 40 per cent, keeping the order size at 30,000 shares if you can, and note how the number of intervals and the shortfall change.
5. Use the adverse-selection simulator to find the informed share at which the break-even spread on a ₹100 share reaches 20 basis points.
6. Use the execution simulator to find the participation rate at which timing risk equals impact for your own order and volatility.
7. Write a short note: what a market maker needs to earn the spread, how a buyer of a large order should choose an algorithm, and which benchmark you would use and why.
A good result is a table of market-maker profit and risk against skew, a note on the best skew in your simulation and a comparison of an execution against VWAP and arrival price. This completes the module on strategy families. The next module turns to derivatives and volatility: option payoffs, put-call parity and the pricing models that a quant uses every day.
Read more
Lawrence Glosten and Paul Milgrom's 1985 paper "Bid, Ask and Transaction Prices in a Specialist Market with Heterogeneously Informed Traders" in the Journal of Financial Economics is the classic model of adverse selection. Marco Avellaneda and Sasha Stoikov's 2008 paper "High-Frequency Trading in a Limit Order Book" in Quantitative Finance is the source of the quotes used here. Robert Almgren and Neil Chriss's 2000 paper "Optimal Execution of Portfolio Transactions" in the Journal of Risk is the standard account of the impact-risk trade-off. Larry Harris's Trading and Exchanges: Market Microstructure for Practitioners explains market making and order types, and Robert Kissell's The Science of Algorithmic Trading and Portfolio Management covers execution benchmarks and algorithms.
Tags: Quant Trader Market making Execution Adverse selection VWAP