Almgren-Chriss sans approximations : l'exécution optimale que vous pouvez implémenter en un après-midi
Almgren et Chriss (2001), « Optimal execution of portfolio transactions » (Journal of Risk 3(2), 5–39), est probablement l'article le plus cité en recherche sur l'exécution et l'un des moins correctement implémentés. La plupart du code « Almgren-Chriss » que l'on trouve dans la nature est en réalité un ordonnanceur TWAP affublé d'un bloc de commentaires. La plupart des articles de blog sur le sujet sautent la dérivation, évoquent vaguement une fonction sinh, et n'abordent jamais la partie qui compte réellement en production : d'où viennent les paramètres.
Cet article traite le sujet dans son intégralité. Les hypothèses du modèle, énoncées honnêtement. La trajectoire sous forme close, dérivée, pas affirmée. La frontière efficiente et comment choisir le paramètre d'aversion au risque. Et la calibration des trois entrées — l'impact temporaire , l'impact permanent , la volatilité — à partir des données de carnet d'ordres et de trades de Binance, avec du Python fonctionnel et une discussion honnête sur le bruit inhérent à cet ajustement. C'est la colonne vertébrale intellectuelle de tout le reste en matière d'exécution : TWAP, VWAP et POV en sont des cas particuliers ou des cousins heuristiques (voir TWAP, VWAP, POV : les algorithmes d'exécution que tout le monde utilise), et les approches modernes de machine learning — ordonnanceurs par apprentissage par renforcement et modèles d'impact neuronaux — sont des tentatives d'assouplir exactement les hypothèses que nous allons poser ci-dessous.
Le cadre : ce que le modèle suppose réellement
Vous détenez unités d'un actif (disons 100 BTC) et devez liquider intégralement d'ici l'instant . Divisez en intervalles de longueur . Votre variable de décision est la trajectoire de détention , avec des trades exécutés dans l'intervalle .
Trois hypothèses portent l'intégralité du modèle :
1. Marche aléatoire arithmétique. Le prix non perturbé suit
où les sont des normales standard i.i.d. et est une volatilité absolue (dollars par unité de temps, pas un pourcentage). Arithmétique, pas géométrique : sur quelques heures, la différence est négligeable et la marche arithmétique garde l'algèbre linéaire-quadratique. Pas de drift : Almgren et Chriss discutent du terme de drift, mais pour une liquidation intrajournalière, votre estimation d'alpha sur 4 heures n'est presque toujours que du bruit, et la fixer à zéro est le choix par défaut honnête.
2. Impact permanent linéaire. : trader au rythme déplace le prix de façon permanente, proportionnelle, et ce déplacement ne se résorbe jamais. Chaque unité vendue pousse le mid vers le bas de pour toujours. Cela paraît grossier, mais il existe une raison profonde de garder cette linéarité : Huberman et Stanzl (2004) ont démontré qu'un impact permanent non linéaire en la taille du trade admet des stratégies aller-retour à profit espéré positif — de la manipulation de prix. L'impact permanent linéaire n'est pas une simplification de commodité ; c'est le seul choix sans arbitrage dans cette classe de modèles.
3. Impact temporaire linéaire. Le prix que vous obtenez réellement dans l'intervalle est
capture la moitié du spread bid-ask plus les frais ; est la pente du coût marginal de la demande de liquidité au rythme . L'impact temporaire n'affecte que votre propre exécution et s'évanouit instantanément — le carnet se reconstitue entièrement avant votre prochain ordre enfant. Chacun des trois mots « linéaire », « instantanément », « entièrement » est faux dans les marchés réels, et la dernière section porte sur l'ampleur de cette erreur. Mais d'abord, le gain que l'on obtient en les acceptant.
Coût et variance d'une trajectoire
Sommez les exécutions, soustrayez du mark initial , et vous obtenez le shortfall d'exécution (implementation shortfall). Son espérance et sa variance sur le bruit sont :
avec (une correction de discrétisation qui s'annule quand ).
Deux observations que la plupart des implémentations manquent :
- Le coût permanent ne dépend pas de la trajectoire. Avec un impact permanent linéaire et non résorbable, vous payez le même péage permanent quel que soit votre ordonnancement. L'optimisation est entièrement un arbitrage entre le terme de coût temporaire (qui veut un trading lent et régulier — il est minimisé par , c'est-à-dire le TWAP) et le terme de variance (qui veut que votre position disparaisse dès hier — il est minimisé par une liquidation immédiate).
- Le terme de variance est pondéré par l'inventaire, pas par le trade. Le risque s'accumule sur ce que vous détenez encore, , pas sur ce que vous tradez. C'est pourquoi l'urgence charge le début du calendrier d'exécution.
La forme close : sinh, cosh et le paramètre d'urgence
Almgren-Chriss minimisent l'objectif moyenne-variance
où est l'aversion au risque, en unités de 1/dollars. Posez pour les points intérieurs. Le terme temporaire contribue des différences secondes de , le terme de variance contribue lui-même, et vous obtenez une équation aux différences finies linéaire du second ordre :
C'est l'analogue discret de , et avec les conditions aux limites , , la solution est hyperbolique :
où résout , ce qui pour petit se réduit simplement à .

Toute la stratégie se résume à un seul nombre :
est l'urgence. Son inverse est le temps caractéristique du trade : l'échelle de temps sur laquelle il vaut la peine de conserver le risque d'inventaire pour économiser du coût d'impact. Notez ce dont ne dépend pas : la taille de l'ordre et l'échéance . Que l'échelle de temps intrinsèque de votre trade soit de 20 minutes ou de 6 heures est déterminé uniquement par l'aversion au risque, la volatilité et la liquidité. Si , votre échéance est sans importance — le modèle liquide selon son propre calendrier et la fin de l'horizon n'est pas utilisée. Si , l'échéance devient contraignante et vous faites en pratique du TWAP.
La limite neutre au risque est le TWAP — voilà pourquoi le TWAP existe
Prenez , donc . Alors et
La trajectoire optimale dégénère en une ligne droite : des quantités égales à intervalles de temps égaux. Le TWAP n'est pas une heuristique qui fonctionne par hasard ; c'est l'optimum exact du modèle d'Almgren-Chriss pour un trader neutre au risque avec impact linéaire. Chaque fois que quelqu'un exécute un TWAP, il affirme implicitement : « je ne me soucie pas de la variance de mon shortfall, seulement de sa moyenne ». C'est une position défendable pour de petits ordres sur des horizons courts. C'est une position étrange pour liquider 5 % du volume quotidien sur 8 heures dans un actif faisant 4 % de vol quotidienne — ce qui est exactement le cas où les gens l'utilisent malgré tout. La limite opposée donne pour tout : tout liquider dans le premier intervalle, quel qu'en soit le coût. Entre ces extrêmes, interpole : est à peine distinguable du TWAP, est agressivement chargé en début de période.
La frontière efficiente de l'exécution
Pour chaque , vous obtenez une trajectoire, un coût espéré et une variance . En balayant , on trace une courbe dans le plan — la frontière efficiente de l'exécution, en analogie directe avec Markowitz. Elle est convexe et décroissante : moins de variance coûte toujours plus de shortfall espéré, avec des rendements marginaux fortement décroissants. Au point de la frontière sélectionné par un donné, l'aversion au risque est la pente (négative) de la tangente : .

La frontière reformule la question « quel est ? » — à laquelle personne ne peut répondre par introspection — en « quel arbitrage coût/risque est-ce que je veux ? », à laquelle un desk peut réellement répondre. Trois manières pratiques de choisir le point :
- Raisonnement en coût marginal. Parcourez la frontière et demandez-vous : « en passant de ce point au suivant, je paie dollars de coût espéré pour retirer dollars d'écart-type de shortfall — est-ce que je prends ce compromis ? » Le coude de la frontière est généralement évident à un facteur 2 près, et la trajectoire est peu sensible à à cette résolution.
- Budget de risque. Fixez un écart-type de shortfall maximal acceptable (par exemple « le 1-sigma à un jour de la position résiduelle doit rester sous 15 points de base du notionnel ») et prenez la trajectoire la moins chère qui le satisfait. C'est un problème contraint dont le multiplicateur de Lagrange est .
- Ciblage du temps caractéristique. Choisissez directement (« cet ordre doit avoir une demi-vie de 90 minutes ») et retrouvez . C'est ce que la plupart des praticiens font implicitement lorsqu'ils règlent un curseur d'« urgence ».
Un exemple chiffré avec des valeurs que nous justifierons dans la section calibration. Vendre BTC à S_0 = \100{,}000T = 4\sigma = $600\sqrt{\text{h}}\eta = 1.0\ $\cdot\text{h}/\text{BTC}\lambda = 10^{-6}\ $^{-1}$. Alors
Le calendrier optimal vend 46,2 BTC dans la première heure (TWAP : 25). Coût temporaire : \eta \int_0^T v(t)^2 dt \approx \3{,}290$2{,}500$53{,}000$69{,}300 pour le TWAP. Donc pour 0,8 point de base de coût espéré supplémentaire sur les \10M de notionnel, vous réduisez le risque de shortfall de 23 %. C'est tout le contenu du modèle en une phrase : il tarife l'assurance, et vous laisse décider si vous l'achetez.
La trajectoire elle-même tient en dix lignes de Python :
import numpy as np
def almgren_chriss(X, T, N, sigma, eta, gamma, lam):
"""Optimal liquidation trajectory (discrete AC 2001)."""
tau = T / N
eta_t = eta - 0.5 * gamma * tau # tilde-eta
kappa_t2 = lam * sigma**2 / eta_t # tilde-kappa^2
kappa = np.arccosh(0.5 * kappa_t2 * tau**2 + 1) / tau
t = np.arange(N + 1) * tau
x = X * np.sinh(kappa * (T - t)) / np.sinh(kappa * T)
n = x[:-1] - x[1:] # child order sizes
E = 0.5 * gamma * X**2 + (eta_t / tau) * np.sum(n**2)
V = sigma**2 * tau * np.sum(x[1:]**2)
return x, n, E, V
x, n, E, V = almgren_chriss(X=100, T=4, N=48, sigma=600,
eta=1.0, gamma=0.3, lam=1e-6)
print(f"first-hour qty: {n[:12].sum():.1f} BTC, "
f"E=${E:,.0f}, std=${np.sqrt(V):,.0f}")
Balayez lam sur np.logspace(-8, -4, 50) et tracez en fonction de — voilà votre frontière, et toute la surface de décision tient sur un seul graphique que vous pouvez présenter à un comité de risque.
Calibration : , , à partir des données Binance
C'est là que 90 % des implémentations meurent silencieusement. La formule de la trajectoire est triviale ; les paramètres ne le sont pas. Trois quantités, trois problèmes d'estimation différents.

: le paramètre facile
Volatilité absolue par racine d'heure, à partir des rendements du mid-price. Utilisez des barres de 1 minute et remettez à l'échelle ; à un échantillonnage plus fin, le bruit de microstructure (bid-ask bounce) biaise la variance réalisée à la hausse. Cette estimation est solide — la vol est le seul paramètre que vous obtiendrez juste.
: l'impact temporaire à partir du carnet et des trades
Deux approches complémentaires. Route A — parcourir le carnet L2. À partir des snapshots de profondeur, calculez le coût d'un balayage marketable hypothétique de taille : le VWAP des niveaux consommés moins le mid. Ajuster donne l'impact instantané par BTC. Pour convertir cela en du modèle, exprimé en taux, il faut supposer un temps de reconstitution du carnet (de l'ordre de 10 à 60 s pour BTCUSDT) : trader au rythme consomme par cycle de rafraîchissement, donc . Cette hypothèse — reconstitution instantanée et complète sur une horloge fixe — est exactement la faille par laquelle Obizhaeva-Wang s'engouffre ; plus de détails plus bas. Route B — régresser le slippage réalisé sur la participation. Regroupez le flux agressif (taker) en bins de 1 minute ; pour chaque bin, régressez le VWAP côté taker moins le mid d'ouverture sur le taux de volume taker. La route B mesure ce que le marché a réellement facturé aux agresseurs ; la route A mesure ce que le carnet résiduel facturerait en ce moment. Quand elles divergent d'un facteur 3, croyez B pour le niveau et A pour la forme intrajournalière.
: l'impact permanent via une régression à la Kyle
Régressez les variations de mid-price sur le flux taker net signé sur des fenêtres de 5 minutes :
Vérifiez ensuite que l'impact ne s'est pas résorbé une fenêtre plus tard — la composante non résorbée est « permanente » à votre échelle de temps de trading. C'est de loin la plus bruitée des trois estimations.
Code fonctionnel, utilisant uniquement les endpoints REST publics de Binance :
import requests, numpy as np, pandas as pd
B = "https://api.binance.com/api/v3"
sym = "BTCUSDT"
kl = requests.get(f"{B}/klines", params=dict(
symbol=sym, interval="1m", limit=1000)).json()
close = np.array([float(k[4]) for k in kl])
sigma = np.diff(close).std() * np.sqrt(60) # $/sqrt(h)
d = requests.get(f"{B}/depth",
params=dict(symbol=sym, limit=5000)).json()
bids = np.array(d["bids"], dtype=float) # [price, qty]
mid = (bids[0, 0] + float(d["asks"][0][0])) / 2
cq = np.cumsum(bids[:, 1]) # cum qty
cn = np.cumsum(bids[:, 0] * bids[:, 1]) # cum notional
sizes = np.linspace(0.5, 50, 40) # BTC probes
cost = [mid - np.interp(q, cq, cn) / q for q in sizes]
eps, eta_inst = np.polyfit(sizes, cost, 1)[::-1] # cost ~ eps + k*q
eta = eta_inst * (30 / 3600) # 30s refresh -> $*h/BTC
tr = requests.get(f"{B}/aggTrades",
params=dict(symbol=sym, limit=1000)).json()
df = pd.DataFrame(dict(
t=[t["T"] for t in tr],
p=[float(t["p"]) for t in tr],
q=[float(t["q"]) * (-1 if t["m"] else 1) for t in tr]))
df["bin"] = df.t // 300_000 # 5-min bins
g = df.groupby("bin").agg(dp=("p", lambda s: s.iloc[-1] - s.iloc[0]),
qn=("q", "sum"))
gamma = np.polyfit(g.qn, g.dp, 1)[0] # $/BTC
print(f"sigma={sigma:.0f} $/sqrt(h) eta={eta:.2f} $*h/BTC "
f"gamma={gamma:.3f} $/BTC")
Pour la production, remplacez la simple page aggTrades par plusieurs jours de dumps historiques et exécutez la régression sur des milliers de bins, pas une poignée.
Pourquoi la calibration crypto est bruitée, et que faire
Exécutez la régression sur des données réelles et vous obtiendrez un de quelques pourcents et un coefficient qui varie d'un facteur 2 à 5 d'un jour à l'autre. Ce n'est pas un bug dans votre code. Les raisons sont structurelles :
- Endogénéité. Le flux répond au prix autant que le prix répond au flux. Les traders momentum achètent parce que le prix a monté ; une régression OLS naïve des rendements sur le flux capte leur réaction et l'attribue à de l'impact. La solution propre consiste à utiliser vos propres exécutions (exogènes par construction) — ce que vous n'avez qu'après avoir tradé un certain temps.
- Concavité. L'impact réel est concave en fonction de la taille — empiriquement proche d'une loi en racine carrée (Almgren, Thum, Hauptmann et Li, 2005, « Direct estimation of equity market impact », trouvent un exposant proche de 0,6 ; la même concavité est robuste en crypto). Ajuster une droite à une fonction concave signifie que vos et dépendent de la plage de tailles présente dans l'échantillon. Calibrez aux taux de participation que vous allez réellement trader.
- Fragmentation et leadership des dérivés. Le BTCUSDT spot sur Binance n'est qu'une venue parmi d'autres, et la découverte de prix se produit fréquemment sur les perpétuels. Un flux que vous ne voyez jamais déplace le prix sur lequel vous régressez, gonflant le terme de bruit.
- Dépendance au régime. Le mesuré pendant la session asiatique ne décrit pas l'ouverture US ; l'impact double à peu près quand la volatilité double. Calibrez par session, et réajustez au moins chaque semaine.
La consolation : la trajectoire est indulgente. , donc une erreur d'un facteur 2 sur ne déplace que d'un facteur , et la fonction de coût est plate près de l'optimum. Obtenir à un facteur 2 près et à un ordre de grandeur près capture déjà l'essentiel de l'amélioration disponible par rapport au TWAP. La précision compte pour les estimations de coût pre-trade ; la robustesse suffit pour l'ordonnancement.
Où le modèle se casse, et les articles qui le réparent
Almgren-Chriss est un échafaudage, et savoir précisément quelle poutre est porteuse indique quelle extension mobiliser.
Impact non linéaire — Almgren (2003). « Optimal execution with nonlinear impact functions and trading-enhanced risk » (Applied Mathematical Finance 10, 1–18) refait le programme avec un impact temporaire en loi de puissance . Pour l'exposant empiriquement privilégié — la loi en racine carrée — les trajectoires optimales changent de caractère : un impact concave pénalise moins les rafales qu'un impact linéaire, donc les calendriers optimaux deviennent plus chargés en début de période pour le même . La structure qualitative (paramètre d'urgence, frontière efficiente) survit ; la formule en sinh, non.
Résilience et carnet d'ordres — Obizhaeva et Wang (2013). « Optimal trading strategy and supply/demand dynamics » (Journal of Financial Markets 16(1), 1–32 ; le working paper a circulé dès 2005) remplace la dichotomie temporaire/permanent par un carnet d'ordres à profondeur finie et un impact à décroissance exponentielle : votre trade consomme le carnet, et le carnet se reconstitue au taux de résilience . L'hypothèse d'Almgren-Chriss selon laquelle « l'impact temporaire s'évanouit instantanément » est la limite . La stratégie optimale change radicalement de forme : un bloc au début, un bloc à la fin, et un taux de trading constant entre les deux — les blocs exploitent la récupération du carnet. Si votre intervalle d'ordre enfant est comparable au temps de reconstitution de la venue (en crypto, de quelques secondes à une minute — c'est souvent le cas), vous êtes en territoire Obizhaeva-Wang, pas Almgren-Chriss, et le bricolage de la calibration ci-dessus est votre signal d'alerte.
Absence d'arbitrage dynamique — Gatheral (2010). « No-dynamic-arbitrage and market impact » (Quantitative Finance 10(7), 749–759) se demande quelles combinaisons de fonction d'impact instantané et de noyau de décroissance sont internement cohérentes, c'est-à-dire n'admettent aucune stratégie aller-retour à coût espéré négatif. Les résultats sont tranchés : la décroissance exponentielle n'est compatible *qu'*avec un impact linéaire — combiner décroissance exponentielle et impact en racine carrée permet de pomper de l'argent au modèle via une séquence de trades oscillante ; un impact non linéaire exige une décroissance en loi de puissance, avec une inégalité reliant les deux exposants (pour un impact et une décroissance , approximativement ). C'est l'article à lire avant de greffer un noyau de décroissance sophistiqué sur votre modèle d'impact : la plupart des combinaisons ad hoc sont secrètement arbitrables, ce qui en pratique signifie que votre optimiseur découvrira l'arbitrage et produira des calendriers oscillants absurdes. Si votre trajectoire « optimale » alterne achats et ventes durant une liquidation pure, vous avez violé Gatheral, pas découvert de l'alpha.
Les suites en machine learning. Deux fils de cette série s'appuient directement sur cet échafaudage. D'abord, l'exécution par apprentissage par renforcement : dès lors qu'on admet que l'impact est non linéaire, dépendant de l'état, et partiellement observable, la forme close disparaît, et le RL (depuis l'article de Q-learning de Nevmyvaka, Feng et Kearns en 2006) est une manière naturelle d'explorer l'espace des trajectoires — mais tout agent RL d'exécution sérieux est benchmarké contre, et souvent initialisé à partir de, la solution AC. Ensuite, les modèles neuronaux d'impact de prix : remplacer par une fonctionnelle apprise de l'état du carnet d'ordres, tout en conservant par-dessus la logique d'ordonnancement moyenne-variance. Aucune de ces deux suites n'a de sens sans savoir exactement ce qu'est la base de référence linéaire-gaussienne et pourquoi elle a cette forme.
Ce qu'il faut retenir
Le modèle tient en trois hypothèses, une équation aux différences, et un nombre. Impact permanent linéaire (imposé par l'absence de manipulation), impact temporaire linéaire (une approximation autour de laquelle on calibre), bruit brownien arithmétique. L'optimum arbitre la variance d'inventaire contre le coût d'impact, toute la stratégie se résume dans l'urgence , et le TWAP en ressort comme le cas dégénéré — ce qui est le fait le plus utile du modèle, car il transforme « devrait-on faire un TWAP ici ? » d'une question d'habitude en une affirmation vérifiable sur l'aversion au risque. La calibration est le vrai travail : est facile, est un jeu à un facteur 2 près, est un projet de recherche, et la trajectoire pardonne les trois. Implémentez-le en un après-midi ; passez le reste du mois sur les diagnostics de régression.
Références
- Almgren, R., Chriss, N. (2001). "Optimal execution of portfolio transactions." Journal of Risk, 3(2), 5–39.
- Almgren, R. (2003). "Optimal execution with nonlinear impact functions and trading-enhanced risk." Applied Mathematical Finance, 10(1), 1–18.
- Almgren, R., Thum, C., Hauptmann, E., Li, H. (2005). "Direct estimation of equity market impact." Risk, 18(7), 58–62.
- Huberman, G., Stanzl, W. (2004). "Price manipulation and quasi-arbitrage." Econometrica, 72(4), 1247–1275.
- Obizhaeva, A., Wang, J. (2013). "Optimal trading strategy and supply/demand dynamics." Journal of Financial Markets, 16(1), 1–32.
- Gatheral, J. (2010). "No-dynamic-arbitrage and market impact." Quantitative Finance, 10(7), 749–759.
- Nevmyvaka, Y., Feng, Y., Kearns, M. (2006). "Reinforcement learning for optimized trade execution." ICML 2006.
Authors
Trading-systems engineer
Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.