σμ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 AcademyRutas
Ctrl K
AO
+1,2 k estudiantes
Iniciar sesiónUnirse ↗
Rutas
AO
+1,2 k estudiantes
Iniciar sesión
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Ruta de Python›Módulo 11 · Sistemas de producción y modelos de vanguardia›Tema 11.6·~1 h 30 minExperto

Creación de mercado

Posición en la rutaMódulo 11 de 11 · Tema 6 de 13
11.6 Creación de mercado
—Puntuación del lab— / 100XP total—Racha—

Ganar el diferencial, cargar con el riesgo

Un creador de mercado publica un bid y un ask y espera. Cuando un vendedor golpea el bid y un comprador toma el ask, el creador compra barato, vende caro y se queda con el diferencial. Ese es el ingreso. El coste es el riesgo de inventario: entre las dos operaciones el creador mantiene una posición cuyo valor se mueve con el precio, y con más frecuencia lo ejecuta alguien que sabe más (selección adversa) que alguien que no. Crear mercado bien es equilibrar cotizaciones lo bastante ajustadas para ser tocadas a menudo y lo bastante amplias para cobrar por el riesgo, manteniendo el inventario cerca de cero.

# 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: dónde cotizar

El modelo de Avellaneda-Stoikov da una respuesta en forma cerrada. Primero, el precio de reserva r = mid - q * gamma * sigma^2 * tau es donde el creador estaría contento de operar dado el inventario q: un creador largo (q > 0) debe valorar el activo por debajo del mid y cotizar más bajo para atraer compradores, uno corto debe cotizar más alto. La aversión al riesgo gamma, la volatilidad sigma y el tiempo restante tau fijan cuánto inclinarse. Segundo, el diferencial óptimo gamma * sigma^2 * tau + (2 / gamma) * ln(1 + gamma / k) tiene dos partes: un cargo por el riesgo de mantener la posición hasta el horizonte y un término por el flujo de órdenes, donde k dice cuán rápido se agotan las ejecuciones al cotizar más lejos del mid. Las cotizaciones son r - spread/2 y 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

Inventario, ejecuciones y P&L

Sigue el estado con dos números, el inventario y el efectivo. Cuando se toca el bid, compraste: el inventario sube y el efectivo baja price * quantity; cuando se toca el ask, vendiste: al revés. Tu riqueza en cada momento es el efectivo más el inventario valorado al mid, cash + inventory * mid, y su cambio es tu P&L. Ese P&L viene del diferencial capturado y de los movimientos de precio mientras mantienes inventario; cotizar alrededor del precio de reserva devuelve el inventario a cero porque el lado que lo reduce se vuelve más atractivo. Los límites importan en la práctica: un tope duro de inventario, una pausa en mercados rápidos y la comprobación en cada cotización de que el bid esté por debajo del ask.

# 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
Un modelo es un punto de partidaEl modelo supone un precio mid de paseo aleatorio, volatilidad constante y una curva suave exponencial de llegada de órdenes. Los mercados reales tienen colas, tamaños de tick, comisiones y rebajas, saltos y traders informados que se llevan las cotizaciones obsoletas. Trata las fórmulas como una manera de razonar sobre la dirección de cada efecto (inventario largo: cotizar más bajo; más volatilidad: más ancho), luego calibra y prueba con datos grabados en un simulador antes de arriesgar dinero, con límites duros que ningún modelo pueda saltarse.
  • Un creador de mercado gana el diferencial pero carga con riesgo de inventario y selección adversa; el objetivo: lo bastante ajustado para operar, lo bastante amplio para cobrar e inventario cerca de cero.
  • El precio de reserva mid - q * gamma * sigma^2 * tau se inclina contra el inventario; el diferencial gamma * sigma^2 * tau + (2/gamma) ln(1 + gamma/k) crece con la volatilidad ponderada por la aversión al riesgo y el tiempo.
  • Sigue inventario y efectivo, valora al mid, impón límites duros de inventario y prueba la estrategia en un simulador con datos grabados antes de usarla en vivo.

A continuación: el modelo de Heston, una volatilidad que es a su vez aleatoria.

Lab: qué se califica

  • Inclinarse contra el inventario con reservation_price25 pts
  • Fijar el ancho con optimal_spread25 pts
  • Cotizar ambos lados con make_quotes25 pts
  • Registrar una ejecución con apply_fill25 pts
Explorador · lab-135-1
▾ lab-135-1
…
bash · en el navegador
learner@quantcraft:~/lab-135-1$
Python aún no cargadoPythonLn 1, Col 1Spaces: 4UTF-8

¿Restablecer este tema?

Todo lo que hay en lab-135-1 vuelve a los archivos iniciales y se limpia el terminal. Tu solución actual se perderá: no se puede deshacer.

Se restablecerá
  • main.py → código inicial
  • Historial del terminal y salida de pruebas
  • Cambios sin enviar
Se conservará
  • Mejor puntuación del lab
  • Tu XP y tu racha
  • Progreso de la lección y notas

Inicia sesión para ejecutar tu código.

Todas las clases se pueden leer gratis. Crea una cuenta o inicia sesión para ejecutar código, lanzar las pruebas y enviar este lab.

  • IDE en el navegador con terminal bash — sin instalar nada
  • Corrección instantánea, XP y tu lugar en la ruta
Crear una cuentaIniciar sesión
O
Continuar con GitHub