Optimal Execution
Garleanu-Pedersen and Almgren-Chriss models for minimizing execution costs
Large orders cost more than their headline price. Temporary impact pushes the price against you; permanent impact shifts it for all subsequent trades. Optimal execution models split a large order into a trajectory of smaller trades that minimize total cost.
API
Garleanu-Pedersen (GP)
Optimal for portfolio transitions where you have a decaying alpha signal. The model balances trading into the target quickly (to capture alpha before it decays) against the cost of trading too aggressively (market impact).
trajectory = hz.gp_optimal_trajectory(
current_pos=0, # current position (shares or contracts)
target_pos=1000, # desired position
alpha_decay=0.1, # alpha half-life parameter (higher = faster decay)
temp_impact=1e-4, # temporary impact coefficient
perm_impact=1e-5, # permanent impact coefficient
n_steps=20, # number of time steps to execute over
)
# Returns: list of floats -- position at each step
# How much to trade each step:
for i in range(1, len(trajectory)):
trade = trajectory[i] - trajectory[i - 1]
print(f"Step {i}: trade {trade:.0f} shares")
Almgren-Chriss (AC)
Optimal for liquidating a position with no alpha signal. The tradeoff is between market impact (trading too fast) and price risk (holding the position too long while the market moves against you).
trajectory = hz.ac_liquidator(
initial_pos=10000, # position to liquidate
risk_aversion=1e-6, # higher = more urgent liquidation
temp_impact=1e-4, # temporary impact coefficient
perm_impact=1e-5, # permanent impact coefficient
n_steps=50, # number of time steps
)
# Returns: list of floats -- remaining position at each step
GP vs AC: which to use
| Scenario | Model | Why |
|---|---|---|
| Entering a new position based on a signal | GP | Your alpha decays — trade into it before the edge disappears |
| Liquidating a position (stop loss, risk reduction) | AC | No alpha signal, pure cost minimization under uncertainty |
| Rebalancing a portfolio | GP | The “alpha” is the distance from optimal weights, which decays as markets move |
| Unwinding after a strategy is turned off | AC | No remaining edge, just exit at minimum cost |
Calibrating impact parameters
The impact coefficients temp_impact and perm_impact are market-specific. Rough calibration from microstructure invariance:
activity = hz.trading_activity(daily_volume, daily_vol, daily_trades)
natural_bet = hz.invariant_bet_size(activity)
# Temporary impact: price moves ~sqrt(shares/natural_bet) * daily_vol
temp_impact = daily_vol / (natural_bet ** 0.5)
# Permanent impact: typically 10-30% of temporary impact
perm_impact = 0.2 * temp_impact
Example: large prediction market order
# Buy 5000 contracts where daily volume is ~20000 (25% of daily volume)
trajectory = hz.gp_optimal_trajectory(
current_pos=0,
target_pos=5000,
alpha_decay=0.05, # edge decays slowly (event is days away)
temp_impact=0.002, # each 1000-lot moves price ~6 cents
perm_impact=0.0005,
n_steps=10,
)
# Front-loaded because alpha is decaying, but not VWAP-flat
When to use
- Large orders: any order >5% of daily volume benefits from trajectory optimization.
- Alpha strategies: GP captures decaying edge without paying excessive impact.
- Risk reduction: AC provides the cost-optimal schedule for unwinding under uncertainty.
- Prediction markets: thin order books make impact significant even for moderate sizes.
For small orders relative to daily volume (under 1%), impact is negligible and you can submit the full order at once.