Almgren-Chriss を誤魔化しなしで理解する: 午後のうちに実装できる最適執行
Almgren and Chriss (2001), "Optimal execution of portfolio transactions" (Journal of Risk 3(2), 5–39) は、おそらく執行研究の分野で最も引用される論文であり、同時に最も正しく実装されていない論文の一つでもある。世に出回っている「Almgren-Chriss」コードの大半は、コメントブロックが付いただけの TWAP スケジューラーにすぎない。この論文について書かれたブログ記事の大半は導出を飛ばし、sinh 関数を軽く紹介するだけで、実運用で本当に重要な部分——パラメータがどこから来るのか——には一切触れない。
本稿ではその全体を扱う。誠実に述べられたモデルの前提。主張ではなく導出された閉形式の軌道。効率的フロンティアと、リスク回避パラメータの選び方。そして、三つの入力——一時的インパクト 、恒久的インパクト 、ボラティリティ ——を Binance の板情報と約定データからキャリブレーションする方法を、実働する Python コードと、なぜフィットがノイジーになるのかについての率直な議論とともに示す。これは執行に関するあらゆるものの知的な背骨である。TWAP、VWAP、POV はその特殊ケースあるいはヒューリスティックな親戚であり(詳細はTWAP、VWAP、POV: 誰もが使っている執行アルゴリズムを参照)、現代の機械学習アプローチ——強化学習スケジューラーやニューラルインパクトモデル——は、まさに今から書き下ろす前提を緩和しようとする試みである。
設定: モデルが実際に前提としていること
あなたはあるアセットを 単位(例えば BTC 100 枚)保有しており、時刻 までに全て清算しなければならない。 を長さ の 個の区間に分割する。意思決定変数は保有量の軌道 であり、区間 で執行される取引量は である。
このモデル全体を支える前提は三つある。
1. 算術ランダムウォーク。 擾乱を受けない価格は次に従う。
ここで は独立同分布の標準正規変数、 は絶対ボラティリティ(単位時間あたりのドル、パーセントではない)である。幾何ではなく算術ウォークを用いるのは、数時間程度の時間軸ではその差が無視できるほど小さく、算術ウォークであれば代数計算が線形二次形式のまま保てるからである。ドリフトはなし。Almgren と Chriss はドリフト項についても論じているが、日中の清算においてはあなたの4時間先のアルファ予測はほぼ常にノイズであり、それをゼロと置くのが誠実なデフォルトである。
2. 線形の恒久的インパクト。 : レート で取引すると、価格は恒久的かつ比例的にシフトし、そのシフトは決して減衰しない。あなたが売る単位ごとに、ミッド価格は永遠に だけ押し下げられる。これは粗い仮定に見えるが、これを線形に保つ深い理由がある。Huberman and Stanzl (2004) は、取引サイズに対して非線形な恒久インパクトは、正の期待利益を持つ往復戦略——すなわち価格操作——を許してしまうことを証明した。線形の恒久的インパクトは便宜上の単純化ではなく、このクラスのモデルにおいて裁定機会を生まない唯一の選択肢なのである。
3. 線形の一時的インパクト。 区間 であなたが実際に受け取る価格は
はビッド・アスクスプレッドの半分と手数料を捉え、 はレート で流動性を要求することの限界コストの傾きである。一時的インパクトはあなた自身の約定にのみ影響し、瞬時に消える——次の子注文を出すまでに板は完全に補充される。「線形」「瞬時に」「完全に」という三つの言葉は、いずれも実際の市場では正しくない。最後の節ではその誤りの程度について論じる。だがまずは、それらを受け入れることの見返りを見ていこう。
軌道のコストと分散
約定を合計し、初期の評価額 から差し引くと、インプリメンテーション・ショートフォールが得られる。ノイズ に関するその期待値と分散は次の通りである。
ここで は で消える離散化補正項である。
ほとんどの実装が見落としている二つの観察がある。
- 恒久的コスト は軌道に依存しない。 線形で減衰しない恒久的インパクトのもとでは、どのようにスケジューリングしても同じ恒久的な代償を払うことになる。最適化とは完全に、一時的コスト項(ゆっくりと均等な取引を望む——これは 、すなわち TWAP で最小化される)と分散項(在庫を昨日のうちに手放したいと望む——これは即時清算で最小化される)との間の綱引きである。
- 分散項は取引量ではなく在庫量に重みづけされる。 リスクはまだ保有しているもの に対して発生するのであり、取引したものに対してではない。これが緊急性がスケジュールを前倒しにする理由である。
閉形式: sinh、cosh、そして緊急性パラメータ
Almgren-Chriss は平均分散目的関数
を最小化する。ここで は1/ドル単位のリスク回避度である。内点について とおく。一時的コスト項は の二階差分を、分散項は 自体を寄与し、次の線形二階差分方程式が得られる。
これは の離散版であり、境界条件 、 のもとで解は双曲線型になる。
ここで は を満たし、 が小さい場合これは単に となる。

戦略に関するすべてが一つの数値に凝縮されている。
は**緊急性(urgency)**である。その逆数 はその取引の特性時間——インパクトコストを節約するために在庫リスクを抱え続ける価値がある時間スケール——である。 が依存しないものに注目してほしい。それは注文サイズ と締切 である。あなたの取引の本質的な時間スケールが20分なのか6時間なのかは、リスク回避度、ボラティリティ、流動性だけによって決まる。 であれば締切は無関係になる——モデルは自分自身のスケジュールで清算を終え、期限の後半部分は使われない。 であれば締切が制約となり、実質的に TWAP を行っていることになる。
リスク中立の極限は TWAP である——これが TWAP が存在する理由
、すなわち とする。すると となり、
最適軌道は直線に退化する。等しい時間区間に等しい数量、である。TWAP はたまたま機能するヒューリスティックではない。線形インパクトを持つリスク中立トレーダーにとっての Almgren-Chriss モデルの厳密な最適解そのものである。 誰かが TWAP を走らせるとき、そのたびに を暗黙のうちに主張していることになる。「自分のショートフォールの分散は気にしない、平均のみを気にする」ということだ。これは小さな注文や短い時間軸であれば十分に擁護できる立場である。しかし、1日の出来高の5%を、日次ボラティリティ4%のアセットで8時間かけて清算する場合にこの立場を取るのは奇妙である——にもかかわらず、まさにそういう場面で人々は TWAP を走らせている。反対の極限 では、すべての について となる。最初の区間で全てを吐き出し、コストがいくらであろうと支払う。この両極端の間で、 が補間する。 であればほぼ TWAP と見分けがつかず、 であれば積極的に前倒しされたスケジュールとなる。
執行の効率的フロンティア
それぞれの に対して一つの軌道、一つの期待コスト 、一つの分散 が得られる。 を掃引すると、 平面上に曲線が描かれる——これが執行の効率的フロンティアであり、Markowitz のそれと直接的に類似している。このフロンティアは凸で単調減少である。分散を小さくするには常により大きな期待ショートフォールを払う必要があり、その見返りは急激に逓減する。ある によって選ばれるフロンティア上の点において、リスク回避度は接線の(負の)傾きである。。

このフロンティアは「 とは何か」という、誰も内省では答えられない問いを、「自分はどのコスト対リスクのトレードオフを望むのか」という、デスクが実際に答えられる問いへと組み替える。この点を選ぶ実践的な方法は三つある。
- 限界コストによる推論。 フロンティアを辿り、こう問う。「この点から次の点へ移動するとき、ショートフォール標準偏差を ドル削減するために期待コストを ドル多く払う——このトレードを取るか?」フロンティアの膝(knee)は大抵、2倍程度の誤差の範囲内で明白であり、その解像度においては軌道は に対して鈍感である。
- リスク予算。 許容できる最大のショートフォール標準偏差を固定し(例えば「残存ポジションの1日1シグマは想定元本の15bpsを超えてはならない」)、それを満たす最も安価な軌道を採用する。これは制約付き問題であり、そのラグランジュ乗数が そのものである。
- 特性時間ターゲティング。 を直接選び(「この注文は90分の半減期を持つべきだ」)、 を逆算する。これは実務家の多くが「緊急度」スライダーを設定するときに暗黙に行っていることである。
キャリブレーションの節で正当化する数値を用いた実例を示す。S_0 = \100{,}000X = 100T = 4\sigma = $600\sqrt{\text{h}}\eta = 1.0\ $\cdot\text{h}/\text{BTC}\lambda = 10^{-6}\ $^{-1}$。このとき
最適スケジュールは最初の1時間で46.2 BTCを売る(TWAP なら25)。一時的コスト: \eta \int_0^T v(t)^2 dt \approx \3{,}290$2{,}500$53{,}000$69{,}300$。つまり、想定元本1,000万ドルに対してわずか0.8bpsの追加期待コストで、ショートフォールリスクを23%削減できる。これがこのモデルの内容全体を一文で表したものである。保険の価格を提示し、それを買うかどうかをあなたに委ねる。
軌道そのものは10行の 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}")
lam を np.logspace(-8, -4, 50) で掃引し、 を に対してプロットする——それがあなたのフロンティアであり、意思決定サーフェス全体がリスク委員会に渡せる1枚のチャートに収まる。
キャリブレーション: Binance データから 、、 を求める
ここが実装の90%が静かに息絶える場所である。軌道の式は自明だが、パラメータはそうではない。三つの量、三つの異なる推定問題である。

: 簡単な方
ミッド価格リターンからの、ルート時間あたりの絶対ボラティリティ。1分足を使いスケーリングする。より細かいサンプリングでは、マイクロストラクチャーノイズ(ビッド・アスクのバウンス)が実現分散を上振れさせる。この推定は堅実であり、ボラティリティはあなたが正しく求められる唯一のパラメータである。
: 板情報と約定からの一時的インパクト
相補的な二つの経路がある。経路A——L2 板を辿る。 深度スナップショットから、サイズ の仮想的なマーケット・スイープのコストを計算する。消費された板レベルの VWAP からミッドを引いたものだ。 をフィットすると、BTCあたりの瞬間インパクトが得られる。これをモデルのレートベースの に変換するには、板の補充時間 (BTCUSDT ではおよそ10〜60秒)を仮定する必要がある。レート で取引すると1補充サイクルあたり を消費するので、 となる。この仮定——固定されたクロック上での瞬時かつ完全な補充——こそが、まさに Obizhaeva-Wang が入り込んでくる隙間である。詳細は後述する。経路B——参加率に対して実現スリッページを回帰する。 アグレッシブな(テイカー)フローを1分ビンに分ける。各ビンについて、テイカー側の VWAP からオープン時のミッドを引いたものを、テイカー出来高レートに対して回帰する。経路Bは市場がアグレッサーに実際に課したものを測定し、経路Aは現時点でレスティングブックが課すであろうものを測定する。両者が3倍もの差で食い違う場合は、水準についてはBを、日中の形状についてはAを信じるとよい。
: Kyle 型回帰による恒久的インパクト
ミッド価格の変化を、5分ウィンドウにおける符号付きネットテイカーフローに対して回帰する。
そして、そのインパクトが1ウィンドウ後に反転していないことを確認する。反転しない成分こそが、あなたの取引時間スケールにおける「恒久的」な部分である。これは三つの中で群を抜いてノイジーである。
公開の Binance REST エンドポイントのみを使った実働コードを以下に示す。
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")
本番環境では、単一ページの aggTrades を過去データのダンプ数日分に置き換え、 の回帰を一握りではなく数千ビンで実行すべきである。
暗号資産のキャリブレーションがなぜノイジーなのか、そしてどう対処するか
実データで の回帰を実行すると、 は数パーセント程度で、係数は日によって2〜5倍も変動するだろう。これはあなたのコードのバグではない。理由は構造的なものである。
- 内生性。 フローは価格に反応するのと同じくらい、価格に影響を与える。モメンタムトレーダーは価格が上がったから買うのであり、リターンをフローに単純にOLS回帰すると彼らの反応を拾ってしまい、それをインパクトに帰属させてしまう。クリーンな解決策は、あなた自身の約定(構造的に外生的)を使うことである——ただしこれは、しばらく取引した後にしか手に入らない。
- 凹性。 実際のインパクトはサイズに対して凹であり、経験的には平方根に近い(Almgren, Thum, Hauptmann and Li, 2005, "Direct estimation of equity market impact" は0.6に近い指数を発見しており、同様の凹性は暗号資産においても頑健に見られる)。凹関数に直線をフィットさせると、 と はサンプル中のサイズ範囲に依存することになる。実際に取引する参加率でキャリブレーションすること。
- フラグメンテーションとデリバティブの主導性。 Binance の BTCUSDT スポットは数ある取引所の一つに過ぎず、プライスディスカバリーはしばしば無期限先物で起きている。あなたが見ていないフローが、あなたが回帰している価格を動かし、ノイズ項を膨らませる。
- レジーム依存性。 アジアセッションで測定した は米国オープンを説明しない。ボラティリティが2倍になれば、インパクトもおおよそ2倍になる。セッションごとにキャリブレーションし、少なくとも週次で再フィットすること。
救いとなるのは、軌道が寛容だということである。 なので、 の2倍の誤差は を 倍しか動かさず、コスト関数は最適点付近で平坦である。 を2倍以内の精度で、 を1桁以内の精度で得られれば、TWAP に対する利用可能な改善のほとんどをすでに捉えている。精度が重要になるのはプレトレード・コスト推定においてであり、スケジューリングには頑健性で十分である。
モデルが壊れる場所と、それを修正する論文たち
Almgren-Chriss は足場であり、どの梁が荷重を支えているかを正確に知ることが、どの拡張に手を伸ばすべきかを教えてくれる。
非線形インパクト——Almgren (2003)。 "Optimal execution with nonlinear impact functions and trading-enhanced risk" (Applied Mathematical Finance 10, 1–18) は、べき乗則の一時的インパクト を用いてこのプログラムをやり直す。経験的に支持される ——平方根則——では、最適軌道の性質が変わる。凹的なインパクトは線形インパクトほどにはバーストを罰しないため、同じ でも最適スケジュールはより前倒しになる。定性的な構造(緊急性パラメータ、効率的フロンティア)は生き残るが、sinh の式は生き残らない。
レジリエンスと LOB——Obizhaeva and Wang (2013)。 "Optimal trading strategy and supply/demand dynamics" (Journal of Financial Markets 16(1), 1–32; ワーキングペーパーは2005年から流通)は、一時的・恒久的の二分法を、有限の深さと指数的に減衰するインパクトを持つ指値注文板に置き換える。あなたの取引は板を食い、板はレジリエンス率 で補充される。AC の「一時的インパクトは瞬時に消える」という仮定は の極限である。最適戦略の形は劇的に変わる。開始時のブロック取引、終了時のブロック取引、そしてその間は一定の取引レート——これらのブロックは板の回復を利用するものである。子注文の間隔が取引所の補充時間と同程度であれば(暗号資産では数秒〜1分程度であり、実際にしばしばそうなる)、あなたは Almgren-Chriss の領域ではなく Obizhaeva-Wang の領域にいることになり、上記のキャリブレーションにおける の帳尻合わせが、その警告サインである。
ノー・ダイナミック・アービトラージ——Gatheral (2010)。 "No-dynamic-arbitrage and market impact" (Quantitative Finance 10(7), 749–759) は、瞬間インパクト関数 と減衰カーネル のどの組み合わせが内部整合的か、すなわち負の期待コストを持つ往復戦略を許さないか、を問う。結果は明快である。指数的減衰は線形インパクトとのみ両立する——指数的減衰を平方根インパクトと組み合わせると、振動する取引系列によってモデルから金を汲み出せてしまう。非線形インパクトはべき乗則の減衰を要求し、二つの指数の間には不等式が成り立つ(インパクトが 、減衰が のとき、おおよそ )。これは、インパクトモデルに凝った減衰カーネルをボルトで取り付ける前に読むべき論文である。アドホックな組み合わせの大半はひそかに裁定可能であり、実務上それはあなたのオプティマイザが裁定機会を発見し、不合理な振動スケジュールを生成することを意味する。もしあなたの「最適」軌道が、純粋な清算の最中に買いと売りを交互に行うのであれば、それは Gatheral に違反しているのであって、アルファを発見したのではない。
機械学習の続編。 この一連の記事の中で二つのスレッドがこの足場の上に直接構築されている。第一に、強化学習による執行。インパクトが非線形で、状態依存で、部分観測可能であることを認めた瞬間、閉形式は失われる。RL(Nevmyvaka, Feng and Kearns の2006年の Q学習論文から始まる)は軌道空間を探索する自然な方法である——だが、真剣な RL 執行エージェントはすべて AC の解に対してベンチマークされ、しばしばそこから初期化される。第二に、ニューラル価格インパクトモデル。 を、板の状態の学習された関数に置き換えつつ、平均分散スケジューリングのロジックはその上に維持する。どちらの続編も、線形ガウシアンのベースラインが正確に何であり、なぜその形をしているのかを知らなければ意味をなさない。
まとめ
このモデルは、三つの前提、一つの差分方程式、そして一つの数値である。線形の恒久的インパクト(操作不能性によって強制される)、線形の一時的インパクト(あなたがその周りでキャリブレーションする近似)、算術ブラウン運動ノイズ。最適解は在庫の分散とインパクトコストをトレードオフし、戦略全体は緊急性 に凝縮され、TWAP は の退化ケースとして自然に導かれる——これはこのモデルの中で最も有用な事実である。なぜなら、「これは TWAP で執行すべきか?」という問いを、習慣の問題からリスク回避度についての検証可能な主張へと変えるからだ。本当の作業はキャリブレーションにある。 は簡単で、 は2倍程度のゲームであり、 は研究プロジェクトであり、そして軌道はこの三つすべてを寛容に許してくれる。実装は午後のうちに終わらせ、残りの月は回帰診断に費やすとよい。
参考文献
- 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.