Avellaneda-Stoikov-Modell: Optimale Market-Making-Quotes.
Wer 2008 ein akademisches Paper über Market-Making veröffentlicht, hofft auf hundert Zitate und einen Lehrstuhl. Marco Avellaneda und Sasha Stoikov bekamen beides — und zusätzlich den inoffiziellen Status, den Goldstandard für quantitative Liquiditätsbereitstellung formuliert zu haben. Was ihr Modell so brauchbar macht, wie Sie es herleiten und wie Sie es in der Praxis einsetzen, zeige ich Ihnen hier.
Worum es geht.
Market-Making bedeutet, gleichzeitig Kauf- und Verkaufsaufträge in ein Orderbuch zu stellen und am Spread zu verdienen. Klingt einfach — wäre es aber nur, wenn der Preis sich nicht bewegen würde und kein anderer Teilnehmer informierter wäre als Sie. In der Realität haben Sie zwei Probleme: Inventarrisiko (Sie sammeln eine Position an, die sich gegen Sie bewegen kann) und adverse Selektion (informierte Trader nehmen genau dann Ihre Quote, wenn sie schon falsch ist).
Avellaneda und Stoikov stellen die Frage: Wenn Sie risikoavers sind und Ihre Position kontrollieren wollen — wo sollten Bid und Ask optimal liegen? Ihre Antwort ist eine geschlossene Lösung, die zwei Größen liefert: einen Reservation-Price (der um Ihre Position vom Mittelkurs verschoben ist) und einen optimalen Spread (der Volatilität, Risikoaversion und verbleibende Zeit kombiniert).
Die Modellannahmen.
Bevor wir rechnen, lohnt es sich, die Annahmen sauber zu verstehen — denn jede Schwäche des Modells in der Praxis lässt sich auf eine dieser Vereinfachungen zurückführen.
- Der Mittelkurs
S_tfolgt einer arithmetischen Brownschen Bewegung mit konstanter Volatilitätσ. - Orders treffen als Poisson-Prozess ein, dessen Intensität exponentiell vom Abstand zum Mittelkurs abhängt:
λ(δ) = A · exp(-k · δ). - Der Market-Maker hat einen Endzeitpunkt
Tund maximiert die exponentielle Nutzenfunktion seines Endvermögens mit Risikoaversionsparameterγ. - Es gibt keine Transaktionskosten, keine Latenz, kein Cancel-Replace-Limit, keine adverse Selektion im engeren Sinn.
Die letzte Annahme ist gleichzeitig die problematischste — und der Grund, warum jede ernsthafte Produktivvariante das Modell um eine Toxizitätskomponente erweitert.
Die Lösung in zwei Formeln.
Avellaneda und Stoikov lösen das stochastische Steuerungsproblem über eine Hamilton-Jacobi-Bellman-Gleichung. Die Herleitung füllt mehrere Seiten, das Ergebnis passt in zwei Zeilen:
Reservation-Price (der Preis, zu dem Sie indifferent gegenüber einem weiteren Trade wären):
r(s, q, t) = s − q · γ · σ² · (T − t)
Optimaler Spread (die Gesamtbreite zwischen Bid und Ask):
δ_bid + δ_ask = γ · σ² · (T − t) + (2 / γ) · ln(1 + γ / k)
Aus diesen beiden Größen ergeben sich die konkreten Quotes als
bid = r − spread/2 und ask = r + spread/2.
Die Eleganz liegt darin, dass beide Größen drei Dinge sauber trennen: Ihre aktuelle Position
q, Ihre Risikoaversion γ, und die Marktvolatilität σ.
Intuition: Was machen die Formeln eigentlich?
Stellen Sie sich vor, Sie haben gerade eine Long-Position von 5 Kontrakten aufgebaut. Der
Reservation-Price r liegt jetzt unter dem Mittelkurs — Sie würden also
lieber verkaufen als kaufen. Das hat zwei Effekte: Ihr Ask wird attraktiver (näher am Markt),
Ihr Bid wird zurückgezogen. Sie quotieren asymmetrisch, um Ihre Position zurück
in Richtung null zu lenken.
Der zweite Term im Spread — (2/γ) · ln(1 + γ/k) — ist der Anteil, der Sie für
das Bereitstellen von Liquidität entlohnen soll. Er hängt von k ab, also wie
schnell die Order-Intensität mit dem Abstand abfällt. Ist k groß
(Liquiditätsnachfrage reagiert sensibel auf Spread), müssen Sie eng quoten. Ist
k klein, können Sie sich Luft lassen.
Der erste Term — γ · σ² · (T − t) — bestraft Sie für Volatilität und
Restlaufzeit. Je länger Sie noch quoten müssen und je wilder der Markt, desto breiter Ihr
Spread. Am Ende des Handelstages konvergiert dieser Term gegen null — Sie können enger
quoten, weil das Inventarrisiko zeitlich begrenzt ist.
Implementierung in Python.
Hier eine minimale, aber lauffähige Version der Quote-Berechnung. Die Funktion bekommt den aktuellen Marktstatus und gibt Bid und Ask zurück:
import numpy as np
def avellaneda_stoikov_quotes(
mid_price: float,
inventory: int,
time_left: float,
sigma: float,
gamma: float = 0.1,
k: float = 1.5,
) -> tuple[float, float]:
"""
Berechnet optimale Bid/Ask-Quotes nach Avellaneda-Stoikov.
mid_price: aktueller Mittelkurs
inventory: aktuelle Position (positiv = long, negativ = short)
time_left: verbleibende Zeit bis Horizont T (in Einheiten von sigma)
sigma: Volatilität pro Zeiteinheit
gamma: Risikoaversion
k: Steilheit der Order-Intensität
"""
# Reservation-Price: vom Mittelkurs in Richtung Null-Inventar verschoben
reservation = mid_price - inventory * gamma * sigma**2 * time_left
# Optimaler Spread aus zwei Komponenten
inventory_term = gamma * sigma**2 * time_left
liquidity_term = (2.0 / gamma) * np.log(1.0 + gamma / k)
spread = inventory_term + liquidity_term
bid = reservation - spread / 2.0
ask = reservation + spread / 2.0
return bid, ask
Das ist die reine Lehre. In der Praxis erweitern Sie diese Funktion um mindestens drei Dinge: Tick-Size-Rounding, Sanity-Checks gegen das aktuelle Orderbuch und einen Killswitch für Extremzustände (Volatilitäts-Spikes, Liquiditätslücken).
Kalibrierung der Parameter.
Die Theorie ist schön, aber jede Formel ist nur so gut wie ihre Inputs. Drei Parameter müssen Sie aus Daten schätzen:
- σ (Volatilität): gleitende Schätzung der Mittelkursvolatilität. Ich nehme typischerweise eine EWMA über 5-Sekunden-Mittelkurse mit Halbwertszeit von 5 Minuten.
- k (Intensitätssteilheit): Regression von Fill-Raten gegen den Abstand zum Mittelkurs. Sie sammeln über Tage Daten, wie oft eine Order in welchem Abstand gefüllt wurde, und fitten
log(Fill-Rate) = log(A) − k · δ. - γ (Risikoaversion): kein datenbasierter Parameter — eine Geschäftsentscheidung. Höhere Werte führen zu kleineren Positionen und breiteren Spreads. Ich kalibriere meist so, dass die durchschnittliche absolute Position einem definierten Anteil des verfügbaren Kapitals entspricht.
Hier ein Beispiel für die k-Schätzung:
import numpy as np
from scipy.stats import linregress
def calibrate_k(fill_data: list[dict]) -> tuple[float, float]:
"""
fill_data: Liste von Dicts mit 'distance' (Abstand zum Mid in Ticks)
und 'fill_rate' (Fills pro Sekunde auf diesem Level).
Gibt (A, k) zurück: lambda(delta) = A * exp(-k * delta)
"""
distances = np.array([f['distance'] for f in fill_data])
rates = np.array([f['fill_rate'] for f in fill_data])
mask = rates > 0
log_rates = np.log(rates[mask])
slope, intercept, r_value, _, _ = linregress(distances[mask], log_rates)
A = np.exp(intercept)
k = -slope
return A, k
Grenzen in der Praxis.
Wer das Modell unverändert in den Live-Betrieb stellt, lernt zwei Lektionen schnell. Erstens:
die Annahme konstanter Volatilität ist falsch. Bei einem Vol-Spike (FOMC-Entscheidung,
Erdbeben in Japan, Tesla-Tweet) ist Ihr Spread plötzlich um eine Größenordnung zu eng.
Lösung: σ als regime-abhängige Größe modellieren, mit harter Untergrenze und
Spike-Detektor.
Zweitens: das Modell kennt keine adverse Selektion. Wenn ein informierter Trader Ihren Bid füllt, weil er weiß, dass der Preis fallen wird, sagt Avellaneda-Stoikov nichts dazu. Hier müssen Sie eine separate Komponente einbauen — Order-Flow-Imbalance, Microprice-Differenz, oder eine probabilistische Toxizitätsschätzung. Den dritten Insight-Artikel dieser Serie widme ich genau dieser Erweiterung.
Drittens: das Modell ist ein Single-Asset-Modell. Multi-Asset-Market-Making mit Korrelationen ist ein deutlich komplexeres Problem, das Cartea und Jaimungal in mehreren Papern weiterentwickelt haben. Wer auf einer Krypto-Börse 30 Pairs gleichzeitig quoten will, braucht eine Erweiterung mit einer Inventar-Korrelationsmatrix.
Warum es trotzdem der richtige Startpunkt ist.
Trotz aller Einschränkungen: Wenn Sie Market-Making lernen wollen, fangen Sie hier an. Das Modell gibt Ihnen einen sauberen mathematischen Rahmen, in dem alle relevanten Größen sichtbar werden — Volatilität, Inventarrisiko, Risikoaversion, Liquiditätspreis. Jede Erweiterung, die Sie später bauen, lässt sich an genau einer dieser Stellschrauben verorten. Das ist die eigentliche Stärke des Papers: Es zwingt Sie, präzise zu denken.
In meinen Mandanten-Projekten ist Avellaneda-Stoikov fast immer der erste Schritt. Wir implementieren die Grundversion, kalibrieren sie auf historischen Daten, und schauen, wo das Modell systematisch verliert. Diese Verlustquellen sind dann die Backlog für die nächsten Iterationen — Toxizitätserkennung, Regime-Switching, Multi-Asset-Inventar. Ohne den Anker des ursprünglichen Modells wären diese Erweiterungen Beliebigkeit.
Sie wollen ein Market-Making-System aufsetzen oder eine bestehende Strategie professionalisieren? Erstgespräch buchen — wir schauen uns Modell, Daten und Infrastruktur gemeinsam an.