σμ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 AcademySkills
Ctrl K
AO
+1,2 Tsd. Lernende
AnmeldenBeitreten ↗
Skills
AO
+1,2 Tsd. Lernende
Anmelden
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Python-Skill›Modul 11 · Produktivsysteme und Spitzenmodelle›Thema 11.6·~1 Std. 30 Min.Experte

Market Making

Position in der SkillModul 11 von 11 · Thema 6 von 13
11.6 Market Making
—Lab-Punkte— / 100XP gesamt—Serie—

Den Spread verdienen, das Risiko tragen

Ein Market Maker stellt Bid und Ask ein und wartet. Trifft ein Verkäufer den Bid und nimmt ein Käufer den Ask, kauft der Maker billig, verkauft teuer und behält den Spread. Das ist das Einkommen. Die Kosten sind das Bestandsrisiko: Zwischen den beiden Trades hält der Maker eine Position, deren Wert sich mit dem Preis bewegt, und er wird öfter von jemandem ausgeführt, der mehr weiß (Adverse Selection), als von jemandem, der nichts weiß. Gutes Market Making balanciert Quotes, die eng genug sind, um oft getroffen zu werden, und weit genug, um das Risiko zu vergüten, während der Bestand nahe null bleibt.

# 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: wo man quotiert

Das Avellaneda-Stoikov-Modell liefert eine geschlossene Antwort. Erstens ist der Reservierungspreis r = mid - q * gamma * sigma^2 * tau der Punkt, an dem der Maker bei Bestand q gern handeln würde: Ein Long-Maker (q > 0) sollte den Wert unter dem Mid ansetzen und tiefer quotieren, um Käufer anzulocken, ein Short-Maker höher. Risikoaversion gamma, Volatilität sigma und Restzeit tau bestimmen, wie stark er sich neigt. Zweitens hat der optimale Spread gamma * sigma^2 * tau + (2 / gamma) * ln(1 + gamma / k) zwei Teile: eine Gebühr für das Risiko, die Position bis zum Horizont zu halten, und einen Term für den Orderfluss, wobei k angibt, wie schnell Ausführungen versiegen, je weiter man vom Mid quotiert. Die Quotes sind r - spread/2 und 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

Bestand, Fills und P&L

Verfolgen Sie den Zustand mit zwei Zahlen, Bestand und Cash. Wird der Bid getroffen, haben Sie gekauft: Der Bestand steigt, das Cash sinkt um price * quantity; wird der Ask getroffen, haben Sie verkauft: umgekehrt. Ihr Vermögen ist jederzeit Cash plus zum Mid bewerteter Bestand, cash + inventory * mid, und seine Änderung ist Ihr P&L. Dieses P&L stammt aus dem vereinnahmten Spread und den Preisbewegungen während des Haltens; Quoten um den Reservierungspreis ziehen den Bestand zurück auf null, weil die Seite, die ihn abbaut, attraktiver wird. Limits zählen in der Praxis: eine harte Bestandsobergrenze, eine Pause in schnellen Märkten und bei jeder Quote die Prüfung, dass der Bid unter dem Ask liegt.

# 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
Ein Modell ist ein AusgangspunktDas Modell unterstellt einen Random-Walk-Mid-Preis, konstante Volatilität und eine glatte exponentielle Order-Ankunftskurve. Echte Märkte haben Warteschlangen, Tickgrößen, Gebühren und Rabatte, Sprünge und informierte Trader, die veraltete Quotes abgreifen. Betrachten Sie die Formeln als Weg, über die Richtung jedes Effekts nachzudenken (Long-Bestand: tiefer quotieren; mehr Volatilität: weiter), dann kalibrieren und testen Sie auf aufgezeichneten Daten in einem Simulator, bevor Sie Geld riskieren, mit harten Limits, die kein Modell aushebeln kann.
  • Ein Market Maker verdient den Spread, trägt aber Bestandsrisiko und Adverse Selection; das Ziel: eng genug zum Handeln, weit genug zur Vergütung, Bestand nahe null.
  • Der Reservierungspreis mid - q * gamma * sigma^2 * tau neigt sich gegen den Bestand; der Spread gamma * sigma^2 * tau + (2/gamma) ln(1 + gamma/k) wächst mit der risikoaversionsgewichteten Volatilität und der Zeit.
  • Verfolgen Sie Bestand und Cash, bewerten Sie zum Mid, erzwingen Sie harte Bestandslimits und testen Sie die Strategie in einem Simulator auf aufgezeichneten Daten, bevor Sie sie live nutzen.

Als Nächstes: das Heston-Modell, eine Volatilität, die selbst zufällig ist.

Lab: Was bewertet wird

  • Mit reservation_price gegen den Bestand lehnen25 Pkt.
  • Die Breite mit optimal_spread festlegen25 Pkt.
  • Mit make_quotes beide Seiten quotieren25 Pkt.
  • Mit apply_fill einen Fill verbuchen25 Pkt.
Explorer · lab-135-1
▾ lab-135-1
…
bash · im Browser
learner@quantcraft:~/lab-135-1$
Python noch nicht geladenPythonLn 1, Col 1Spaces: 4UTF-8

Dieses Thema zurücksetzen?

Alles in lab-135-1 wird auf die Startdateien zurückgesetzt und das Terminal geleert. Ihre aktuelle Lösung geht verloren – das lässt sich nicht rückgängig machen.

Wird zurückgesetzt
  • main.py → Startcode
  • Terminal-Verlauf und Testausgabe
  • Nicht eingereichte Änderungen
Bleibt erhalten
  • Beste Lab-Punktzahl
  • Ihre XP und Ihre Serie
  • Vorlesungsfortschritt und Notizen

Melde dich an, um deinen Code auszuführen.

Alle Lektionen kannst du kostenlos lesen. Erstelle ein Konto oder melde dich an, um Code auszuführen, Tests zu starten und dieses Lab abzugeben.

  • IDE im Browser mit Bash-Terminal — nichts zu installieren
  • Sofortige Bewertung, XP und dein Platz auf der Skill
Konto erstellenAnmelden
ODER
Weiter mit GitHub