σμ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 6 · Backtesting y costes de trading›Tema 6.6·~55 minAvanzado

Ejecuciones de órdenes realistas

Posición en la rutaMódulo 6 de 11 · Tema 6 de 6
6.6 Ejecuciones de órdenes realistas
—Puntuación del lab— / 100XP total—Racha—

Una ejecución no es una certeza

Un backtest ingenuo supone que una orden de cualquier tamaño se ejecuta al precio de los datos. Las órdenes reales plantean tres preguntas. Qué profundidad tiene el libro: una orden de mercado toma primero la mejor oferta y luego la siguiente, así que una orden grande paga un precio medio peor. Si el mercado llegó a mi límite: una orden limitada obtiene el precio pedido o mejor, pero solo si la negociación lo alcanza. Y cuánto puedo tomar: una orden grande solo puede ser una fracción del volumen de la barra, así que se ejecuta por partes en el tiempo.

def fill_market_order(book, quantity):
    remaining = quantity
    cost = 0.0
    filled = 0
    for price, size in book:                      # cheapest offer first
        if remaining <= 0:
            break
        take = min(size, remaining)
        cost += take * price
        filled += take
        remaining -= take
    if filled == 0:
        return 0.0, 0
    return cost / filled, filled

book = [(50.00, 300), (50.02, 500), (50.05, 1000)]
print(fill_market_order(book, 200))        # (50.0, 200)           inside the first level
print(fill_market_order(book, 600))        # (50.01, 600)          300 at 50.00 and 300 at 50.02
print(fill_market_order(book, 5000))       # (50.0333, 1800)      the whole book; 3,200 shares stay unfilled
# The average price and the slippage against the best offer grow with the size
def average_price(book, quantity):
    remaining, cost, filled = quantity, 0.0, 0
    for price, size in book:
        take = min(size, remaining)
        cost += take * price
        filled += take
        remaining -= take
    return cost / filled

book = [(50.00, 300), (50.02, 500), (50.05, 1000)]
for quantity in (100, 300, 800, 1800):
    avg = average_price(book, quantity)
    print(quantity, round(avg, 4), round((avg - 50.00) / 50.00 * 10000, 2), "bps above the best offer")

Órdenes limitadas y huecos

Con datos de barras (apertura, mínimo, máximo) no se ve el camino dentro de la barra, solo sus extremos. Una compra limitada en L se ejecuta si el mínimo de la barra llegó a L o menos. El precio es L, salvo que la barra abriera por debajo de L: entonces el mercado saltó tu límite y se ejecuta en la apertura, que es mejor. Una venta limitada es la imagen especular. Una orden limitada solo tocada puede no ejecutarse en la realidad, porque se sirvió antes la cola delante de ti, así que esta es la cota optimista.

def limit_fill(side, limit, bar_open, bar_low, bar_high):
    if side == "buy" and bar_low <= limit:
        return min(bar_open, limit)             # a gap below the limit fills at the better open
    if side == "sell" and bar_high >= limit:
        return max(bar_open, limit)
    return None

print(limit_fill("buy", 49.95, 50.10, 49.90, 50.20))   # 49.95   traded down through the limit
print(limit_fill("buy", 49.95, 49.90, 49.80, 50.20))   # 49.9    opened below: filled at the open
print(limit_fill("buy", 49.95, 50.10, 50.00, 50.20))   # None    never reached
print(limit_fill("sell", 50.15, 50.00, 49.90, 50.20))  # 50.15

Trabajar una orden grande

Muchas mesas de ejecución usan un límite de participación: no tomar más de, digamos, el 10 % del volumen. En una barra con 40 000 acciones negociadas son 4000, redondeado hacia abajo. Una orden de 5000 acciones tarda entonces dos barras, no una. Recorrer las barras es un bucle que lleva la cantidad restante: cada barra ejecuta min(remaining, int(volume * participation)), y las barras posteriores al final de la orden no ejecutan nada.

def partial_fill(quantity, bar_volume, participation):
    return min(quantity, int(bar_volume * participation))

def fill_over_bars(quantity, volumes, participation):
    remaining = quantity
    fills = []
    for volume in volumes:
        filled = partial_fill(remaining, volume, participation)
        fills.append(filled)
        remaining -= filled
    return fills

fills = fill_over_bars(5000, [40000, 30000, 80000, 100000], 0.1)
print(fills, sum(fills))                      # [4000, 1000, 0, 0] 5000
Los modelos de ejecución fijan tu honestidadCada simplificación aquí se inclina hacia el mismo lado: suponer que una orden limitada se ejecuta al tocarse, que nunca mueves el mercado, que el volumen está ahí. Cuanto más depende un resultado de las ejecuciones, más debes probarlo con reglas pesimistas (ejecutar solo si el precio atraviesa el límite, un tope de participación menor) y comprobar que la ventaja sobrevive.
  • Una orden de mercado recorre el libro nivel a nivel; el precio medio se pondera por volumen y empeora con el tamaño, y un libro fino ejecuta solo una parte.
  • Una orden limitada se ejecuta si la barra alcanza el límite, en la apertura si la barra lo saltó; un simple toque puede no ejecutarse en la realidad.
  • Los topes de participación limitan cada barra a int(volume * participation); un bucle lleva la cantidad restante entre barras.

A continuación: CAPM y beta, medir cuánto de un rendimiento viene del mercado.

Lab: qué se califica

  • Recorrer el libro con fill_market_order25 pts
  • Decidir si se alcanza el límite con limit_fill25 pts
  • Respetar el volumen con partial_fill25 pts
  • Trabajar la orden en el tiempo con fill_over_bars25 pts
Explorador · lab-92-1
▾ lab-92-1
…
bash · en el navegador
learner@quantcraft:~/lab-92-1$
Python aún no cargadoPythonLn 1, Col 1Spaces: 4UTF-8

¿Restablecer este tema?

Todo lo que hay en lab-92-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