← Alle Insights

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.

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:

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.