Setup
The Execution Problem
A portfolio manager needs to sell shares of a stock over a time horizon . Selling too fast incurs large market impact costs (moving the price against themselves). Selling too slowly leaves the position exposed to price risk for longer. This is the optimal execution problem: find a trading schedule that balances market impact against timing risk.
This is a ubiquitous problem in practice: unwinding a large position post-trade decision, rebalancing a portfolio after a factor model update, or executing a delta hedge for a large options position. The Almgren-Chriss (2001) framework is the standard model for this problem on institutional trading desks.
Conventions and Assumptions
- Initial position: shares to sell, .
- Time grid: discrete times with equal spacing .
- Shares sold in period : (non-negative, selling only).
- Trade rate: (shares per unit time).
- Mid-price dynamics in the absence of trading: where .
- Volatility : annualised. Daily vol is for equities.
- Rates are zero (P&L is measured in dollar terms, no discounting).
Market Impact Model
Permanent and Temporary Impact
Almgren-Chriss decompose market impact into two components:
Permanent impact: trades shift the mid-price permanently. Every share sold at time reduces the mid-price for all future periods. The cumulative permanent impact of selling shares is:
where is the permanent impact function (shares per time → price change). For the linear model: , so selling at rate permanently moves the price by per period.
Temporary impact: the execution price in period differs from the (already impacted) mid by an additional amount due to consuming liquidity immediately. This cost is paid once and does not affect future mid-prices:
where is the mid-price at time (already shifted by permanent impact), and is the temporary impact function. For the linear model: , where is a fixed half-spread cost and is the linear temporary impact.
The Full Price Process
Let be the mid-price after permanent impact. Starting from :
The total proceeds from selling shares:
The shortfall (cost of execution relative to the decision price ):
The first two terms are deterministic costs; the last is random (timing risk from mid-price moves while the position is open).
Theory: Optimal Execution
Objective Function
Almgren-Chriss optimise the mean-variance objective over the implementation shortfall:
where is the risk-aversion parameter (units: inverse variance, or equivalently, the penalty per unit of variance). Large penalises timing risk heavily, favouring fast execution; small accepts more risk in return for lower market impact costs.
Expected shortfall:
using the identity and noting . The first term is a constant (independent of schedule), so minimising expected shortfall alone reduces to minimising , which favours spreading trades as evenly as possible (TWAP).
Variance of shortfall:
where is the remaining inventory after period . This follows because the timing risk is , and the are independent.
Continuous-Time Formulation
In continuous time with selling rate (shares per unit time):
where is the remaining inventory. The objective is:
subject to , , .
Closed-Form Solution via Calculus of Variations
The Euler-Lagrange equation for the functional is:
or equivalently where . This is a linear second-order ODE with solution:
Applying boundary conditions , :
The optimal trading rate:
Special Cases
TWAP (): As risk aversion vanishes, . Using for small :
TWAP is optimal when there is no timing risk penalty: trade at a constant rate, spreading market impact evenly.
Aggressive execution (): As risk aversion dominates, . The solution concentrates at : , for . Extreme risk aversion means: sell everything immediately (market order). The market impact cost is irrelevant relative to the timing risk penalty.
Finite : The optimal trajectory is a hyperbolic sine — front-loaded relative to TWAP but not a single market order. More shares are sold early (when the remaining inventory is large, so the variance penalty is large) and fewer late.
Efficient Frontier
For different values of , the optimal strategy traces out an efficient frontier in the (Expected Shortfall, Variance) plane:
As increases, increases: expected shortfall increases (faster execution is more expensive in impact costs) but variance decreases (less timing risk). Every point on the frontier is optimal for some risk aversion level.
Implementation
import numpy as np
from dataclasses import dataclass
@dataclass
class AlmgrenChrissParams:
X: float # initial position (shares)
T: float # horizon (years)
sigma: float # annualised volatility
eta: float # temporary impact coefficient (price per shares-per-time)
gamma: float # permanent impact coefficient
lam: float # risk-aversion parameter lambda
def kappa(p: AlmgrenChrissParams) -> float:
"""Decay parameter kappa = sqrt(lambda * sigma^2 / (2 * eta))."""
return np.sqrt(p.lam * p.sigma**2 / (2.0 * p.eta))
def optimal_trajectory(p: AlmgrenChrissParams, n_steps: int = 100) -> tuple[np.ndarray, np.ndarray]:
"""
Almgren-Chriss optimal continuous-time trajectory.
Returns:
t: time grid, shape (n_steps+1,)
x: remaining inventory at each time, shape (n_steps+1,)
"""
k = kappa(p)
t = np.linspace(0.0, p.T, n_steps + 1)
# x*(t) = X * sinh(kappa*(T-t)) / sinh(kappa*T)
denom = np.sinh(k * p.T)
if np.abs(denom) < 1e-10:
# TWAP limit
x = p.X * (1.0 - t / p.T)
else:
x = p.X * np.sinh(k * (p.T - t)) / denom
return t, x
def optimal_schedule(p: AlmgrenChrissParams, n_steps: int = 20) -> tuple[np.ndarray, np.ndarray]:
"""
Discrete optimal execution schedule.
Returns:
times: endpoints of trading periods, shape (n_steps+1,)
trades: shares traded in each period, shape (n_steps,)
"""
t, x = optimal_trajectory(p, n_steps)
trades = np.diff(-x) # n_k = x_{k-1} - x_k (positive = selling)
return t, trades
def expected_shortfall(p: AlmgrenChrissParams) -> float:
"""Expected implementation shortfall for optimal strategy (continuous-time)."""
k = kappa(p)
# E[IS] = gamma/2 * X^2 + eta * kappa * X^2 / tanh(kappa*T)
if k < 1e-10:
return p.gamma / 2.0 * p.X**2 + p.eta * p.X**2 / p.T # TWAP limit
return p.gamma / 2.0 * p.X**2 + p.eta * k * p.X**2 / np.tanh(k * p.T)
def variance_shortfall(p: AlmgrenChrissParams) -> float:
"""Variance of implementation shortfall for optimal strategy (continuous-time)."""
k = kappa(p)
if k < 1e-10:
return p.sigma**2 * p.X**2 * p.T / 3.0 # TWAP limit
# Var = sigma^2 * X^2 * (kappa*T - tanh(kappa*T)) / (kappa * T * tanh(kappa*T))
kT = k * p.T
tnh = np.tanh(kT)
return p.sigma**2 * p.X**2 * (kT - tnh) / (kT * tnh)
def efficient_frontier(
p_base: AlmgrenChrissParams,
n_lambda: int = 50
) -> tuple[np.ndarray, np.ndarray]:
"""
Compute the efficient frontier by varying risk-aversion lambda.
Returns:
ev: expected shortfall values (n_lambda,)
var: variance values (n_lambda,)
"""
from copy import replace # Python 3.13+; use dataclasses.replace otherwise
import dataclasses
lambdas = np.logspace(-6, 2, n_lambda)
ev_arr = np.zeros(n_lambda)
var_arr = np.zeros(n_lambda)
for i, lam in enumerate(lambdas):
p = dataclasses.replace(p_base, lam=lam)
ev_arr[i] = expected_shortfall(p)
var_arr[i] = variance_shortfall(p)
return ev_arr, var_arr
Validation
Analytic Checks
import dataclasses
p = AlmgrenChrissParams(X=1e6, T=1.0/252, sigma=0.25, eta=2.5e-7, gamma=2.5e-8, lam=0.0)
# 1. TWAP limit: lambda = 0 gives linear trajectory
t, x = optimal_trajectory(p, n_steps=10)
assert np.allclose(x, p.X * (1.0 - t / p.T), atol=1e-3), "Should be TWAP"
# 2. Constraint: total shares sold = X
_, trades = optimal_schedule(p, n_steps=20)
assert abs(trades.sum() - p.X) < 1.0, "Must liquidate all shares"
# 3. Efficient frontier: expected shortfall increases with lambda
ev, var = efficient_frontier(p, n_lambda=20)
# As lambda increases, kappa increases, faster execution -> higher E[IS]
p_hi_lam = dataclasses.replace(p, lam=1.0)
assert expected_shortfall(p_hi_lam) > expected_shortfall(p), "Higher lambda -> higher E[IS]"
assert variance_shortfall(p_hi_lam) < variance_shortfall(p), "Higher lambda -> lower Var[IS]"
print("All analytic checks passed.")
Limitations
Linear market impact. The Almgren-Chriss model uses linear temporary impact . Empirically, market impact is better described by a square-root law: (see Module 4). The closed-form solution does not extend to power-law impact functions; numerical solutions are required.
Constant volatility. Assuming constant is restrictive. In practice, volatility is time-varying (intraday U-shape, stochastic vol). A more realistic model uses time-dependent , which changes the optimal trading rate — sell faster during low-vol periods, slower during high-vol periods.
No alpha signal. The model assumes zero drift (). If the trader has a short-lived alpha signal predicting price movement, the optimal schedule is modified: sell faster if the signal predicts a price decline, slower if it predicts appreciation. The Almgren (2003) extension incorporates an alpha decay model.
Discrete market. The continuous-time optimal schedule must be rounded to discrete lot sizes and clocked to the exchange's trade frequency. Discretisation introduces approximation error, particularly for very short horizons where only a few trades occur.
Participation rate constraints. In practice, trades are constrained to a maximum participation rate (e.g., 10–20% of average daily volume) to avoid signalling. The Almgren-Chriss model has no such constraint; a constrained optimisation is needed.
No dark pools or alternative venues. The model treats the market as a single venue with homogeneous liquidity. A multi-venue model (primary exchange, dark pool, crossing network) with different impact characteristics per venue is more realistic.
Interview Angle
L1. What is the implementation shortfall? A portfolio manager decides to sell 1 million shares at a mid-price of $50.00. After execution, the average fill price is $49.90. What is the implementation shortfall in dollar terms and in basis points?
Implementation shortfall (IS): the difference between the "paper portfolio" P&L (at the decision price) and the actual execution P&L:
\mathrm{IS} = S_0 X - \mathrm{Proceeds} = 50.00 \times 10^6 - 49.90 \times 10^6 = \100{,}000. $
In basis points: . Components: market impact (prices moved down as shares were sold) plus spread cost (selling below the mid). A 20 bps IS on a $50M trade is $100k in cost — significant relative to the transaction value.
L2. Write down the Almgren-Chriss objective function. Why is TWAP the optimal strategy when ? For , derive the Euler-Lagrange equation and state the closed-form trajectory .
Objective: . At : the objective reduces to — minimising subject to gives constant by Cauchy-Schwarz. This is TWAP.
Euler-Lagrange for : the integrand is with . E-L: gives , i.e., with . Solution: .
L3. Construct the efficient frontier for a sell programme: shares, day, annual, , . What is the minimum-variance strategy and what is its expected shortfall? How would you modify the model to account for an alpha signal predicting a 5 bps decline in the stock over the first 30 minutes?
Minimum variance: achieved as (or ): sell everything immediately. Cost: the immediate temporary impact of selling 10^6 shares at rate is bounded by — extremely high. The efficient frontier makes this tradeoff explicit: immediate execution has near-zero variance but very high expected IS.
Alpha decay modification: Suppose the stock has expected return (falling) for . The modified objective adds a drift term: . The Euler-Lagrange equation becomes . The solution front-loads selling during the period of negative expected return — sell faster while the alpha predicts a price decline to minimise the expected mark-to-market loss on the remaining inventory. After (alpha exhausted), revert to the AC schedule.