σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft Academyロードマップ
Ctrl K
AO
+1.2k 人の学習者
ログイン参加する ↗
ロードマップ
AO
+1.2k 人の学習者
ログイン
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Python ロードマップ›モジュール 11 · 本番システムと最先端モデル›トピック 11.6·~1 時間 30 分エキスパート

マーケットメイク

ロードマップ上の位置モジュール 11/11 · トピック 6/13
11.6 マーケットメイク
—ラボスコア— / 100合計XP—連続日数—

スプレッドを稼ぎ、リスクを抱える

マーケットメイカーはビッドとアスクを出して待ちます。売り手がビッドを叩き、買い手がアスクを取ると、メイカーは安く買って高く売り、スプレッドを得ます。これが収入です。コストは在庫リスクです。2つの取引の間、メイカーは価格とともに価値が動くポジションを持ち、また、情報のない相手より情報を持つ相手に約定させられることが多くなります(逆選択)。良いマーケットメイクとは、頻繁に約定するほど狭く、リスクの対価を得られるほど広い気配を出し、在庫をゼロ近くに保つバランスです。

# The income: buy at the bid, sell at the ask, keep the spread
bid, ask, size = 99.95, 100.05, 100
cash = -bid * size + ask * size
print(round(cash, 2))                                # 10.0    a round trip of 100 shares earned the 0.10 spread

# The risk: between the two trades the price moves against the inventory
inventory, mid_after = 100, 99.80
print(round(inventory * (mid_after - bid), 2))       # -15.0   the position lost more than the spread would have earned

Avellaneda-Stoikov:どこに気配を出すか

Avellaneda-Stoikov モデルは閉じた形の答えを与えます。まず留保価格 r = mid - q * gamma * sigma^2 * tau は、在庫 q を前提にメイカーが喜んで取引する水準です。ロングのメイカー(q > 0)は資産の価値を仲値より低く見て、買い手を引き寄せるために低く気配を出し、ショートなら高く出します。リスク回避度 gamma、ボラティリティ sigma、残り時間 tau が傾きの強さを決めます。次に最適スプレッド gamma * sigma^2 * tau + (2 / gamma) * ln(1 + gamma / k) は2つの部分からなります。期末までポジションを持つリスクへの対価と、注文フローの項です。k は、仲値から遠くに気配を出すほど約定が枯れる速さを表します。気配は r - spread/2 と r + spread/2 です。

# The reservation price leans against inventory: long -> quote lower, short -> quote higher
def reservation_price(mid, inventory, gamma, sigma, tau):
    return mid - inventory * gamma * sigma ** 2 * tau

for inventory in (-50, 0, 50):
    print(inventory, round(reservation_price(100.0, inventory, 0.1, 0.2, 1.0), 4))
# -50 100.2   short: quote higher to buy back
#   0 100.0   flat: centred on the mid
#  50  99.8   long: quote lower to sell
# The optimal spread and the two quotes around the reservation price
import math

def optimal_spread(gamma, sigma, tau, k):
    return gamma * sigma ** 2 * tau + (2 / gamma) * math.log(1 + gamma / k)

def make_quotes(mid, inventory, gamma, sigma, tau, k):
    centre = mid - inventory * gamma * sigma ** 2 * tau
    half = optimal_spread(gamma, sigma, tau, k) / 2
    return centre - half, centre + half

print(round(optimal_spread(0.1, 0.2, 1.0, 1.5), 4))                       # 1.2948
bid, ask = make_quotes(100.0, 0, 0.1, 0.2, 1.0, 1.5)
print(round(bid, 4), round(ask, 4))                  # 99.3526 100.6474   symmetric around the mid when flat
bid, ask = make_quotes(100.0, 50, 0.1, 0.2, 1.0, 1.5)
print(round(bid, 4), round(ask, 4))                  # 99.1526 100.4474   long 50: both quotes move down by 0.2

在庫、約定、損益

状態は在庫と現金の2つの数で追跡します。ビッドが約定したら買ったことになり、在庫が増え、現金が price * quantity だけ減ります。アスクが約定したら売ったことになり、その逆です。ある時点の資産は現金に、仲値で評価した在庫を足したもの cash + inventory * mid で、その変化が損益です。損益は、獲得したスプレッドと、在庫を持っている間の価格変動から生じます。留保価格の周りに気配を出すと、在庫を減らす側が魅力的になるため、在庫がゼロに戻ります。実務では制限が重要です。在庫の厳格な上限、急変する市場での一時停止、そして気配のたびにビッドがアスクより低いことの確認です。

# Booking fills and marking the book to market
def apply_fill(state, side, price, quantity):
    inventory, cash = state
    if side == "bid":
        return inventory + quantity, cash - price * quantity
    return inventory - quantity, cash + price * quantity

state = (0, 0.0)
state = apply_fill(state, "bid", 99.95, 100)         # our bid is hit: we buy 100
print(state)                                         # (100, -9995.0)
state = apply_fill(state, "ask", 100.05, 100)        # our ask is hit: we sell 100
print(state)                                         # (0, 10.0)   flat again, and the spread is the profit
inventory, cash = apply_fill(state, "bid", 99.9, 50)
print(round(cash + inventory * 99.9, 2))             # 10.0   marked at the price we just paid, the equity is unchanged
モデルは出発点にすぎないこのモデルは、ランダムウォークの仲値、一定のボラティリティ、滑らかな指数型の注文到着曲線を仮定します。実際の市場には、待ち行列、呼値の単位、手数料とリベート、ジャンプ、古い気配を拾う情報トレーダーがいます。公式は、各効果の向き(ロング在庫なら低く、ボラティリティが高ければ広く)を考える手段として使い、資金を投じる前に、記録データを使ったシミュレータで較正とテストを行い、どのモデルも覆せない厳格な制限を設けます。
  • マーケットメイカーはスプレッドを稼ぐが、在庫リスクと逆選択を負う。取引できるほど狭く、対価を得られるほど広く、在庫はゼロ近くに
  • 留保価格 mid - q * gamma * sigma^2 * tau は在庫に逆らって傾き、スプレッド gamma * sigma^2 * tau + (2/gamma) ln(1 + gamma/k) はリスク回避度で重み付けしたボラティリティと時間とともに広がる
  • 在庫と現金を追跡し、仲値で評価し、在庫に厳格な上限を設け、実運用の前に記録データを使ったシミュレータで戦略をテストする

次は Heston モデルです。それ自体が確率的に変動するボラティリティを扱います。

ラボ:採点される内容

  • reservation_price で在庫に逆らって傾ける25点
  • optimal_spread でスプレッドの幅を決める25点
  • make_quotes で両サイドに気配を出す25点
  • apply_fill で約定を記帳する25点
エクスプローラー · lab-135-1
▾ lab-135-1
…
bash · ブラウザ内
learner@quantcraft:~/lab-135-1$
Pythonは未読み込みPythonLn 1, Col 1Spaces: 4UTF-8

このトピックをリセットしますか?

lab-135-1 の内容はすべてスターターファイルに戻り、ターミナルも消去されます。現在の解答は失われ、元に戻せません。

リセットされるもの
  • main.py → スターターコード
  • ターミナル履歴とテスト出力
  • 未提出の変更
保持されるもの
  • ラボの最高スコア
  • XPと連続日数
  • 講義の進捗とメモ

コードを実行するにはログインしてください。

レクチャーはすべて無料で読めます。コードの実行、テスト、ラボの提出にはアカウントの作成かログインが必要です。

  • ブラウザ内IDEとbashターミナル。インストール不要
  • 即時採点、XP、ロードマップでの現在地
アカウントを作成ログイン
または
GitHubで続ける