Strategy Capacity and Scalability
Strategy capacity is the AUM at which a strategy's own trading destroys the edge it exploits. Every alpha has a finite ceiling because market impact — the price you move against yourself by demanding liquidity — grows with size while the gross edge per trade stays roughly fixed. Capacity is where the two cross. This article develops the square-root impact model rigorously, derives how capacity scales with edge, turnover, and liquidity, connects it to the cost-aware optimization that should shape the portfolio in the first place, and is honest about the estimation uncertainty that makes any single capacity number a range, not a point.
Impact as the binding cost
When you buy you consume resting liquidity and push the price up; the reverse when you sell. Unlike commissions, impact is endogenous — it scales with your size relative to available volume — and it is the cost that ultimately caps a strategy. The key empirical fact is that impact is concave in size: the first shares are cheap, each additional block costs more on the margin, but total cost still rises faster than the alpha you are chasing. At some AUM the marginal dollar earns less in alpha than it pays in impact, and that is your capacity.
The square-root impact model
Decades of execution data across venues and asset classes support a square-root law: the price impact of trading quantity Q is proportional to volatility times the square root of participation (the fraction of average daily volume, ADV, you consume):
impact_bps ≈ Y * sigma * sqrt(Q / V)
where sigma is daily volatility, V is ADV, Q is order size, and Y is a dimensionless constant of order one (often 0.5–1.0, estimated per market). The concavity is the headline feature, and it has a counterintuitive aggregate consequence.
| Participation (Q/V) | Per-unit impact (sqrt(Q/V)) | Total impact cost (∝ Q * sqrt(Q/V)) |
|---|---|---|
| 1% | 0.10 | 0.10x |
| 5% | 0.22 | 1.1x |
| 10% | 0.32 | 3.2x |
| 25% | 0.50 | 12.5x |
| 100% | 1.00 | 100x |
Going from 1% to 25% of ADV multiplies per-unit impact by only ~5x, but because you trade 25x more shares, total impact cost rises by ~125x. Trading a large fraction of ADV is brutally expensive in aggregate even though the marginal cost grows slowly — which is why optimal execution schedules and TWAP/VWAP algorithms exist to spread orders over time and keep participation low.
Deriving the capacity scaling
Set the round-trip impact cost per unit of capital equal to the gross edge per trade and solve. With the square-root model, the participation rate at which impact consumes the edge is p* = (edge / (2·Y·sigma))², and the AUM that this supports scales as:
capacity ∝ (edge / (Y * sigma))² * V / turnover
Two relationships dominate everything: capacity is quadratic in edge (doubling the gross edge quadruples capacity) and inverse in turnover (doubling turnover halves capacity). The turnover term is why fast strategies — HFT, short-horizon mean reversion — are structurally low-capacity: they pay impact over and over on the same capital. Slow strategies (value, long-horizon trend) re-trade rarely and are high-capacity.
Estimating capacity in Python
import numpy as np
def impact_bps(participation, sigma_daily=0.02, Y=0.8):
"""Square-root impact in bps for participation rate Q/V."""
return 1e4 * Y * sigma_daily * np.sqrt(participation)
def capacity(edge_bps, adv_usd, turnover_annual,
max_participation=0.10, sigma_daily=0.02, Y=0.8,
edge_haircut=0.5):
"""Largest AUM where round-trip impact stays below a fraction of the edge."""
usable_edge = edge_bps * edge_haircut # leave room; don't spend it all
# solve usable_edge = 2 * impact_bps(p) for p (round trip = 2x)
p_breakeven = (usable_edge / (2 * 1e4 * Y * sigma_daily)) ** 2
p = min(p_breakeven, max_participation)
daily_trade = p * adv_usd
aum = daily_trade * 252 / turnover_annual
return aum, p
for tcell in (4, 12, 50):
aum, p = capacity(edge_bps=20, adv_usd=50e6, turnover_annual=tcell)
print(f"turnover {tcell}x -> capacity ~${aum/1e6:.0f}M at {p:.1%} of ADV")
Sweeping edgebps and turnoverannual shows the quadratic and inverse relationships directly, and usually delivers a sober reality check on ambitious AUM targets. The edge_haircut matters: setting impact equal to the full edge means you earn nothing net, so capacity should be defined at a fraction of the edge, leaving margin for the part you actually keep.
Capacity feeds back into construction
Capacity is not just a post-hoc number; it should shape the portfolio. The cost-aware optimization used in portfolio optimization and factor construction is precisely where you respect it — by penalizing turnover and capping per-name participation, the optimizer naturally avoids deploying more into a name than its liquidity can absorb:
import cvxpy as cp
def capacity_aware_weights(signal, cov, adv_usd, aum, gamma=10.0,
tc=0.0010, max_part=0.05):
n = len(signal); w = cp.Variable(n)
# cap each position so its implied daily trade stays under max_part * ADV
pos_cap = (max_part * adv_usd) / aum
obj = cp.Maximize(signal @ w
- gamma * cp.quad_form(w, cp.psd_wrap(cov))
- tc * 1e4 * cp.norm1(w))
cons = [cp.sum(w) == 0, cp.abs(w) <= pos_cap, cp.norm1(w) <= 2.0]
cp.Problem(obj, cons).solve()
return w.value
As AUM rises, pos_cap tightens, the optimizer is forced out of the illiquid names that drove the backtest, and realized edge falls — which is capacity decay made mechanical and visible before you trade, not discovered afterward in the P&L.
Temporary vs permanent impact and the execution schedule
The square-root law captures average impact, but for scheduling you need the split between temporary impact (the part that reverts after you stop pushing) and permanent impact (the part that stays, reflecting information your trading revealed). The Almgren-Chriss framework formalizes the tradeoff: trade fast and you minimize exposure to price drift but pay large temporary impact; trade slow and you cut impact but bear more timing risk. The optimal schedule balances temporary impact against the variance of the unexecuted position.
import numpy as np
def almgren_chriss_schedule(shares, n_steps, risk_aversion=1e-6,
temp_impact=2e-6, volatility=0.02):
"""Optimal trade trajectory: remaining shares at each step."""
kappa = np.sqrt(risk_aversion * volatility**2 / temp_impact)
t = np.linspace(0, 1, n_steps + 1)
remaining = shares * np.sinh(kappa * (1 - t)) / np.sinh(kappa)
return remaining
Higher risk aversion or volatility steepens the trajectory toward faster execution; lower impact flattens it toward a patient, near-linear schedule. The point for capacity is that how you trade changes the effective impact constant Y you face, so a fund with superior execution genuinely has higher capacity for the same signal than one that trades naively.
Empirical impact and signal decay
Two refinements separate a textbook capacity estimate from a usable one. First, the impact constant Y should be measured from your own fills via transaction cost analysis, not assumed — it varies by asset, venue, and regime, and a wrong Y propagates squared into the capacity number. Second, capacity interacts with signal decay: a fast signal whose edge decays within hours forces you to trade quickly (high impact, low capacity), while a slow signal lets you work orders patiently over days. The capacity number is therefore inseparable from the alpha's half-life, and quoting one without the other is meaningless.
Why retail edges die at scale
Many strategies that work for a retail trader are structurally uncapacitated: they trade small, illiquid names where modest size is a large fraction of ADV; they are high-turnover, so impact is paid repeatedly; and their edge is thin (a few bps), leaving no room to absorb impact once size grows. A profitable personal book is often genuinely unsellable to a fund — not because the alpha is fake, but because it evaporates the moment you add zeros. This is also why small inefficiencies persist: they are too small for large players to bother with. Capacity analysis tells you which side of that line you live on, and it feeds directly into transaction cost analysis and realistic expected-return modeling.
Honest limits
The square-root model is a robust stylized fact, not a law. Its constant Y is estimated with wide error and varies by venue, time of day, and regime; impact rises in stressed, illiquid markets exactly when you most want to trade. The model also ignores temporary vs permanent impact — part of your impact reverts after you stop trading and part is permanent information leakage — and the split matters for how you schedule orders. It says nothing about adverse selection, where informed counterparties make your fills systematically worse, or about the signaling risk of predictable execution. And capacity is dynamic: liquidity and volatility shift, competitors crowd the same signal, and a capacity estimate made today can be wrong within a quarter.
The constructive summary: capacity scales like edge-squared times ADV divided by turnover, so the levers are a bigger edge, more liquid instruments, and lower turnover. Estimate it explicitly at a fraction of the gross edge, cap participation well below the point where impact and leakage spike (typically 5–10% of ADV), bake the participation cap into the optimizer so construction respects it, and recompute as conditions evolve. Capacity is what separates a backtest from a business — raising more than your capacity does not grow returns, it dilutes them, turning a great strategy into a mediocre fund. Push the ceiling higher with optimal execution, but never pretend the ceiling is not there.
