Skip to content

Order Book Impact and Pre-Trade Cost Estimation

The four components of pre-trade cost sit on a spectrum from 'directly computable' to 'model-only guesswork.' Which end of that spectrum dominates your estimate determines how far you should trust it.

9 of 12 ~15 min

You need to buy 100,000 shares. You look at the book: $50.01 offers 5,000 shares, the next level is 8,000 at $50.03, the third is 12,000 at $50.06.

How much will this cost?

The naive answer: 50.01×100,000=50.01 × 100,000 = 5,001,000, plus impact from sweeping the book. The smart answer depends on the model. Pre-trade cost estimation is the craft of guessing that number right before you commit: get it right and the PM approves the order and the TCA report looks clean; get it wrong and either the budget is padded and the trade never happens, or the budget is thin and the trade costs more than promised.

Harris (2003, Ch. 23) locates the difficulty precisely: a cost estimate is a function of three things at once — the current state of the order book, the expected evolution of that state during execution, and the expected response of other market participants to your order. The first is observable, the second half-observable, the third pure model. That slide from “computable” to “guessable” is this article’s through-line: the four cost components line up along exactly that spectrum, and how much you should trust your estimate depends on which end is doing the work.

Four Components, One Spectrum

The standard decomposition splits total cost into four parts. Spread cost: the half-spread you pay to cross, unavoidable for a marketable order. Display impact: the price concession from sweeping displayed levels beyond the best. Hidden impact: the concession from your order being detected — hidden orders triggering, informed traders responding. Timing cost: price drift over the execution window. Written together:

C^=s2⏟spread+∑i(pi−p0)qi⏟display impact+IH(Q,V,σ)⏟hidden impact+σT⏟timing\hat{C} = \underbrace{\frac{s}{2}}_{\text{spread}} + \underbrace{\sum_i (p_i - p_0) q_i}_{\text{display impact}} + \underbrace{I_H(Q, V, \sigma)}_{\text{hidden impact}} + \underbrace{\sigma \sqrt{T}}_{\text{timing}}

where ss is the spread, pip_i and qiq_i are the price and size at level ii, IHI_H is the hidden impact function, QQ is order size, VV is daily volume, σ\sigma is volatility, and TT is the execution horizon.

The ordering isn’t accidental: observability falls off left to right. The spread you read directly, display impact you compute from the book, hidden impact you can only model with calibrated parameters, and timing cost is at bottom a random variable. Take them in that order.

Spread Cost: Read It Off the Screen

The simplest component. A buy order crossing the offer pays the half-spread:

Cspread=Ask−Bid2C_{\text{spread}} = \frac{\text{Ask} - \text{Bid}}{2}

In the opening example the spread is 1 cent, so spread cost is 0.5 cents per share — $500 on the order.

This is the price of immediacy, paid to the market maker who posted the inside quote. It isn’t waste — the market maker earned it by providing liquidity — but it isn’t optional either, if you want to trade now. A patient trader posting a limit order can earn that half-spread instead of paying it, at the price of timing risk and the risk of never filling. That trade-off keeps coming back.

Display Impact: Compute It From the Book

When your order exceeds the displayed size at the best price, you sweep through levels, paying a wider concession at each. For a 100,000-share buy against the opening book: take 5,000 at 50.01,8,000at50.01, 8,000 at 50.03, 12,000 at $50.06, and keep walking. The total concession across $n$ displayed levels:

Cdisplay=∑i=1nqi(pi−p0)C_{\text{display}} = \sum_{i=1}^{n} q_i (p_i - p_0)

where p0p_0 is the inside price — what you’d pay if you could stop at the first level.

Book depth is observable, so no model is needed; you walk the levels:

def display_impact(buy_size, asks):
    """Calculate cost of sweeping through displayed ask levels."""
    remaining = buy_size
    total_cost = 0
    for price, size in asks:
        fill = min(remaining, size)
        total_cost += fill * price
        remaining -= fill
        if remaining <= 0:
            break
    avg_price = total_cost / buy_size
    return avg_price - asks[0][0]

A 100,000-share order sweeps roughly 8-10 levels in a typical liquid name; at reasonable depth the average fill lands near $50.04, about 3 cents per share of display impact over the inside price.

But “observable” is already fraying here: the book you see is a snapshot, and by the time your order lands, some levels are gone. Realistic estimates attach a fill probability to each level — maybe 70% for the full size at level 1, 50% at level 2, 30% at level 3, decaying outward. This is where the spectrum starts tilting toward guesswork.

Hidden Impact: Model-Only Territory

Hidden impact is the price concession that comes from your order being detected and other participants responding. It’s the most uncertain of the four components, and the most model-dependent.

The standard model is Almgren-Chriss-style square-root impact:

IH=ησQVI_H = \eta \sigma \sqrt{\frac{Q}{V}}

The intuition: impact grows with order size QQ, shrinks with daily volume VV, grows with volatility σ\sigma; the square root means doubling the order raises impact by only 2\sqrt{2}. Plugging in the opening example — Q=100,000Q = 100{,}000, V=5,000,000V = 5{,}000{,}000 (5M shares ADV), σ=2%\sigma = 2\% daily, η=0.142\eta = 0.142 (a typical calibration):

IH=0.142×0.02×100,0005,000,000=0.142×0.02×0.141=0.0004=4 bpsI_H = 0.142 \times 0.02 \times \sqrt{\frac{100{,}000}{5{,}000{,}000}} = 0.142 \times 0.02 \times 0.141 = 0.0004 = 4 \text{ bps}

On a $50 stock, 4 bps is 2 cents per share — $2,000 on the full order. A sane magnitude for a 2%-of-ADV order in a liquid name.

The square-root form is an empirical observation, usually motivated theoretically by information leakage: the more you trade the more you leak, but each additional share leaks less at the margin. Alternatives have been tested extensively — linear impact (IH=ηQ/VI_H = \eta Q / V) is simpler but fails at large sizes; power-law impact (IH=η(Q/V)αI_H = \eta (Q/V)^\alpha) is more flexible, with α≈0.6\alpha \approx 0.6 fitting some datasets; Kyle’s lambda gives a market-specific price impact per unit of order flow. The practical verdict: square-root works over Q/V∈[0.001,0.1]Q/V \in [0.001, 0.1] — 0.1% to 10% of ADV — and outside that range you need something else.

Timing Cost: Even the Model Only Gives You a Distribution

The last component isn’t a number; it’s a random variable. Work an order over 30 minutes in a stock with 2% daily volatility, and the standard deviation of the price move over that window (zero drift, pure diffusion) is:

σT=σT=0.02×30390≈0.0055=55 bps\sigma_T = \sigma \sqrt{T} = 0.02 \times \sqrt{\frac{30}{390}} \approx 0.0055 = 55 \text{ bps}

The expected absolute move is the mean absolute deviation:

E[∣r∣]=σT2π≈44 bpsE[|r|] = \sigma \sqrt{T} \sqrt{\frac{2}{\pi}} \approx 44 \text{ bps}

So over 30 minutes, expect typical price movement of around 44 bps. The expected timing cost is zero — up and down are equally likely — but the swing you’re exposed to is a very real 44 bps. Stock trends up while you buy: positive timing cost. Trends down: negative. This isn’t a cost in the impact sense; it’s a risk.

A risk-averse trader compresses this variance by trading fast; a risk-neutral one accepts the variance in exchange for lower impact. The Almgren-Chriss optimal trajectory — coming shortly — is precisely the balance between those two.

Putting It Together: One Number, and Its Temperament

Summing the four parts for the opening example (100,000 shares, 30-minute horizon):

ComponentCalculationCost (cents/share)
Spread0.5 cents0.5
Display impactSweep 8 levels3.0
Hidden impact4 bps × 50.002.0
Timing costExpected0 (zero-mean)
TotalSum5.5 cents/share

About 11 bps of expected cost; on a $5M order, $5,500.

Know this number’s temperament: it’s an expectation, not a realization. Actual cost comes in far lower sometimes (the stock drifts down while you buy) and far higher others (it gaps up). Treating the expectation as a forecast is the most common misuse of pre-trade estimation — the correct use is at the end of this article.

Calibration: Making the Model Answer to Your Data

The parameters in the square-root model (η\eta and friends) can’t be borrowed from industry averages; they have to be calibrated to your own trading. The standard method regresses realized impact against predicted impact on your historical fills:

Irealized=α+β⋅Imodel+ϵI_{\text{realized}} = \alpha + \beta \cdot I_{\text{model}} + \epsilon

β≈1\beta \approx 1 with α≈0\alpha \approx 0: well calibrated. β>1\beta > 1: the model systematically under-predicts. β<1\beta < 1: over-predicts. The pattern most shops find is under-prediction in less liquid names and over-prediction in liquid ones — fixed by bucketing stocks on ADV (or market cap, or spread) and calibrating each bucket separately.

def calibrate_impact(trades):
    """Fit square-root impact model to historical trades."""
    realized = []
    predicted = []
    for trade in trades:
        realized.append(trade.slippage_bps)
        predicted.append(
            trade.volatility * (trade.size / trade.adv) ** 0.5 * 10000
        )
    # OLS regression: realized = alpha + beta * predicted
    beta = covariance(realized, predicted) / variance(predicted)
    alpha = mean(realized) - beta * mean(predicted)
    return alpha, beta

That’s a toy. Production systems use weighted regression (recent trades count more), bucketed models, and Bayesian shrinkage (extreme buckets pulled toward the mean). And calibration is perishable — markets change, parameters drift; quarterly re-fits are a common rhythm.

Where the Models Go Wrong: An Honest List

However well calibrated, pre-trade models still miss, because the inputs are noise. Worth naming each source.

The book state is a snapshot — levels come and go before your order lands, and fill probability at each level depends on a queue position you don’t exactly know. Other participants respond — your order changes the book, and their reactions depend on their models, inventory, and information, none of which you can model precisely. Information events void everything — the estimate assumes no news during execution, and one headline makes it irrelevant. The volatility input is historical — forward vol can be a different animal, and earnings days, FOMC meetings, and scheduled releases all move it. Liquidity has an intraday rhythm — the book is deeper at 10:30 than at 12:00, invisible to a single-snapshot estimate. And there’s self-impact: your earlier orders have already moved the price, and the model doesn’t know you’re working the same name all day.

Most pre-trade models handle a few of these. None handles all. The honest read: a pre-trade estimate is a budgeting tool and a baseline, not a precise forecast.

Almgren-Chriss: From Costs to a Trajectory

With the cost structure in hand, the next question follows: given these costs, what’s the optimal execution schedule? Almgren and Chriss (2000) answer it in closed form under specific assumptions: linear temporary impact (h(v)=η∣v∣h(v) = \eta |v|), linear permanent impact (g(v)=γvg(v) = \gamma v), an arithmetic random walk for the price with zero drift, and a quadratic penalty on cost variance. The optimal trajectory from initial position X0X_0 to zero over horizon TT:

x∗(t)=X0⋅sinh⁡(κ(T−t))sinh⁡(κT)x^*(t) = X_0 \cdot \frac{\sinh(\kappa(T-t))}{\sinh(\kappa T)}

where κ=λσ2/η\kappa = \sqrt{\lambda \sigma^2 / \eta} and λ\lambda is the risk-aversion parameter.

High λ\lambda (risk-averse): large κ\kappa, front-loaded trajectory — trade fast, kill the timing risk. Low λ\lambda (near risk-neutral): small κ\kappa, near-linear trajectory — trade at a constant rate, balancing impact against timing. The trajectory isn’t unique; it’s parameterized by risk aversion, and the trader picks λ\lambda to taste. This is the mathematical spine of execution algorithms.

For the lineage: Bertsimas and Lo (1998) first framed optimal execution as a dynamic program, showing the optimal strategy depends on the trader’s beliefs about price dynamics, the impact function, and risk aversion — and is generally nonlinear in time. Almgren-Chriss bought a closed-form solution with the quadratic variance penalty, and became the standard reference for algo design. Later work pushed toward multiple assets (basket trading), discrete time and volume, stochastic volatility, and information effects (impact from your own order revealing your information) — each extension trading tractability for realism. In practice, a well-calibrated plain Almgren-Chriss is usually enough.

Queue Position: What the Book Doesn’t Tell You

The displayed book gives you price and size per level. It doesn’t give you your order’s queue position within a level.

Post a 5,000-share limit buy at $50.00 where 10,000 shares already rest, and you’re behind all of them — displayed size shows your 5,000, but 15,000 shares stand between the market and your fill. Whether you fill depends on whether enough volume trades to chew through the queue ahead of you. Market orders crossing the book don’t care about any of this; for passive limit orders, queue position is everything — front of queue fills with high probability, back of queue rarely.

Retail traders mostly ignore queue position because knowing it exactly is nearly impossible. Sophisticated execution algos estimate it, inferring fill probability from queue position, time of day, and recent trade flow. The practical bind it creates: posting too much size at the touch reveals your intent, posting too little doesn’t fill. Optimal posting size balances fill probability against information leakage, and most liquidity-seeking algos have that balance built in.

Volatility: The Model’s Operating Range

Impact’s dependence on volatility is written into the square-root model:

IH=ησQ/VI_H = \eta \sigma \sqrt{Q/V}

Double the volatility, double the impact. The intuition holds up: when prices move fast, your order is more visible and the market reacts harder. Quiet days: small impact, quick reversion. News days: large impact, maybe no reversion.

But the linearity has an operating range. In extreme volatility — a flash crash, say — market makers withdraw, depth evaporates, and even small orders move prices far beyond what the linear scaling predicts. A pre-trade model assuming normal volatility will dramatically under-predict cost in those conditions. The practical correction: scale estimates by forward volatility, not trailing history alone. Earnings day, Fed day — forward vol sits above the trailing average; use it.

Self-Impact: The Model Doesn’t Know About You

When you work multiple orders in the same stock across a day, each order’s impact is partly your own earlier orders coming back to bill you.

Buy 50,000 XYZ in the morning; the price rises 5 cents. Sell 30,000 in the afternoon and you face a thinner book — thinner because your morning order moved it. The afternoon estimate knows nothing of the morning: it prices off the current state, which already embeds the morning’s impact, so the true combined impact of both orders gets under-predicted.

The fix is to track your own trades and adjust: if you’ve already moved the stock 5 cents today, the next order’s expected impact is higher than the model says. This is one corner of the broader “inventory” problem — your net position in a name affects execution cost; long inventory makes sells easier and buys harder, short inventory the reverse. Pre-trade models that ignore inventory produce biased estimates.

The Close: A Different Pricing Mechanism Entirely

Orders worked into the closing auction need a different estimator altogether, because the closing auction is a special market with its own price discovery, and the clearing price isn’t known until 16:00. An estimate benchmarked to the last continuous trade can be wildly wrong when the auction prints far from it.

For an order aimed at the close, the components get re-booked: estimate the closing price from the imbalance, the bid-ask spread, and recent trade flow; book spread cost at zero (auction fills pay no spread); book impact at zero or near it (closing auctions are low-impact); book timing cost over the holding period. But the auction carries its own risk list — the imbalance can flip in the final 30 seconds, the clearing price can land far from expectations, and a large order can move the clearing price by itself — so the confidence interval belongs wider than usual.

Multi-Day Execution: Two New Line Items

Above roughly 10% of ADV, one day isn’t enough and the order spans several. The estimate gains two components: overnight gap risk and impact persistence across days.

Overnight gap risk is characterized by overnight volatility. One rough modeling choice scales daily volatility by a factor:

σovernight=σdaily⋅ρ\sigma_{\text{overnight}} = \sigma_{\text{daily}} \cdot \rho

Values like 1.5 to 2.0 for ρ\rho show up in models, but the factor varies a lot by name and sample — calibrate it yourself rather than reciting a constant. Over a three-day program, the accumulated overnight risk is no longer ignorable.

Impact persistence is subtler. The square-root model assumes impact decays within the day; across days it accumulates instead. The empirical evidence says a substantial fraction of today’s impact — on the order of tens of percent, varying with market and sample — is still there tomorrow. So a multi-day estimate should include the sum of daily impact estimates, cumulative overnight gap risk, an adjustment for persistence, and a penalty for the strategy being detectable across days. All told, multi-day estimates typically come out several tens of percent to double the single-day estimate for the same total size.

Where the Estimate Actually Lives: The Trader’s Workflow

Finally, put the estimate back in its real habitat. A buy-side trader’s typical pre-trade flow:

  1. Receive the order from the PM (via OMS).
  2. Check the stock’s current state: book, volume, volatility, recent news.
  3. Pull the pre-trade estimate from the TCA system (or compute it by hand).
  4. Compare against the PM’s budget; flag if over.
  5. Choose the execution strategy: VWAP, POV, IS, liquidity-seeking.
  6. Set parameters: participation rate, max impact, deadline.
  7. Send to the broker or execute directly.
  8. Track against the benchmark in real time.
  9. Adjust if real-time cost runs well past the estimate.
  10. Document at completion for post-trade TCA.

The estimate is one input among many, and the trader’s experience and judgment usually matter more. But the estimate is the discipline: it’s the number the PM will hold you to, and the baseline for judging whether execution went well. So use it properly — never show a bare point estimate, show a range (5th to 95th percentile; ±30% is normal in volatile names, and the PM should know it); re-calibrate quarterly; pick the benchmark for the job (VWAP for schedule algos, arrival price for liquidity-seeking, implementation shortfall for attribution); and adjust for the day’s events — earnings, FOMC, scheduled data. A pre-trade estimate being imprecise is not its failure. Treating it as precise is yours.

References

  • Harris, L. (2003). Trading and Exchanges: Market Microstructure for Practitioners. Oxford University Press. Ch. 19, 23. ISBN: 978-0-19-514470-3.
  • Almgren, R., & Chriss, N. (2000). “Optimal Execution of Portfolio Transactions.” Journal of Risk, 3(2), 5-39.
  • Bertsimas, D., & Lo, A. W. (1998). “Optimal Control of Execution Costs.” Journal of Financial Markets, 1(1), 1-50.
  • Perold, A. F. (1988). “The Implementation Shortfall: Paper Versus Reality.” Journal of Portfolio Management, 14(3), 4-9.