σμ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 9 · Datos de mercado y microestructura›Tema 9.2·~50 minAvanzado

Desequilibrio del flujo de órdenes

Posición en la rutaMódulo 9 de 11 · Tema 2 de 5
9.2 Desequilibrio del flujo de órdenes
—Puntuación del lab— / 100XP total—Racha—

Presión antes de que el precio se mueva

Un precio rara vez se mueve solo; se mueve porque llegan órdenes y retiran liquidez. Mirar solo las operaciones deja fuera gran parte de la historia, pues casi toda la acción son órdenes colocadas y canceladas en la cima del libro. El desequilibrio del flujo de órdenes (OFI) resume cada actualización del mejor bid y ask en un número con signo: positivo cuando los compradores añaden o los vendedores se retiran, negativo en el caso contrario. En horizontes cortos predice notablemente bien los siguientes cambios de precio.

def book_imbalance(bid_size, ask_size):
    total = bid_size + ask_size
    if total == 0:
        return 0.0
    return (bid_size - ask_size) / total

print(book_imbalance(450, 200))        # 0.3846  more size on the bid: upward pressure
print(book_imbalance(100, 400))        # -0.6    sellers dominate
print(book_imbalance(0, 0))            # 0.0     an empty top does not divide by zero

Una actualización, un número

Compara dos cotizaciones sucesivas. En el bid: si el precio del bid sube o se mantiene, se suma su nuevo tamaño; si baja o se mantiene, se resta su tamaño anterior (con precio sin cambios se aplican ambos, así que cuenta la variación de tamaño). En el ask los signos se invierten: un ask menor o igual añade presión vendedora (- nuevo tamaño ask), uno mayor o igual retira la anterior (+ tamaño anterior ask). Los cuatro términos son (b >= pb) * bs - (b <= pb) * pbs - (a <= pa) * as + (a >= pa) * pas, donde cada comparación vale 1 o 0.

# The order-flow imbalance of one quote update, tried on four changes of the top of the book
def ofi_event(prev, cur):
    pb, pbs, pa, pas_ = prev
    b, bs, a, as_ = cur
    return (b >= pb) * bs - (b <= pb) * pbs - (a <= pa) * as_ + (a >= pa) * pas_

q0 = (99.5, 300, 100.0, 200)
print(ofi_event(q0, (99.5, 450, 100.0, 200)))     # 150   more size on the same bid
print(ofi_event(q0, (99.6, 100, 100.0, 200)))     # 100   a higher bid: the whole new size counts
print(ofi_event(q0, (99.4, 300, 100.0, 200)))     # -300  the bid price fell: the old size is gone
print(ofi_event(q0, (99.5, 300, 100.1, 200)))     # 200   the ask retreated: less selling pressure

Una serie y lo que explica

Aplicar la regla a cada par de cotizaciones sucesivas da una serie de OFI. En una ventana corta, como un segundo, suma los eventos y compáralos con el cambio del precio medio: la relación es casi lineal, d_mid = slope * OFI. La pendiente dice cuánto mueve el precio cada unidad de flujo, y se reduce cuando el libro es profundo. Se ajusta como una recta de mínimos cuadrados por el origen: sum(ofi * dmid) / sum(ofi ** 2).

# A series of events from consecutive quotes, set beside the change of the mid price
import numpy as np

def ofi_event(prev, cur):
    pb, pbs, pa, pas_ = prev
    b, bs, a, as_ = cur
    return (b >= pb) * bs - (b <= pb) * pbs - (a <= pa) * as_ + (a >= pa) * pas_

quotes = [(99.5, 300, 100.0, 200), (99.5, 450, 100.0, 200), (99.6, 100, 100.0, 150), (99.6, 100, 100.1, 400)]
events = np.array([ofi_event(prev, cur) for prev, cur in zip(quotes, quotes[1:])], dtype=float)
print(events)                                                       # [150. 150. 150.]

mid = np.array([(q[0] + q[2]) / 2 for q in quotes])
dmid = np.diff(mid)
print(np.round(dmid, 3))                                            # the mid moved in the direction of the flow
# Recover the price impact of the flow with a slope through the origin
import numpy as np

def impact_slope(ofi, dmid):
    return float(np.sum(ofi * dmid) / np.sum(ofi ** 2))

rng = np.random.default_rng(1)
flow = rng.normal(0, 200, size=500)                                  # order-flow imbalance per second
price_change = 0.00005 * flow + rng.normal(0, 0.004, size=500)       # the mid moves with the flow, plus noise
print(round(impact_slope(flow, price_change), 6))                    # 5e-05, the true impact per unit of flow
Predictivo, pero no dinero gratisEl OFI predice movimientos menores que el diferencial, sobre los que los participantes rápidos ya operan antes de costes. Su valor para la mayoría está en la ejecución: dice si conviene ser paciente con una orden de compra porque el libro se inclina a tu favor, o darse prisa porque el precio va a escaparse. También depende del mercado: la pendiente difiere entre acciones y horas del día.
  • El desequilibrio del libro (bid - ask) / (bid + ask) está entre -1 y +1; proteja el caso vacío.
  • OFI de una actualización: (b >= pb) * bs - (b <= pb) * pbs - (a <= pa) * as + (a >= pa) * pas; una serie lo aplica a cada par consecutivo.
  • Los cambios del precio medio son casi lineales en el OFI: slope = sum(ofi * dmid) / sum(ofi**2); es una señal de corto horizonte, útil sobre todo para la ejecución.

A continuación: el código asíncrono con asyncio, manejar muchos flujos de datos sin esperar a cada uno.

Lab: qué se califica

  • Comparar los dos lados con book_imbalance25 pts
  • Puntuar una actualización con ofi_event25 pts
  • Seguir la presión continuamente con ofi_series25 pts
  • Poner precio al flujo con impact_slope25 pts
Explorador · lab-113-1
▾ lab-113-1
…
bash · en el navegador
learner@quantcraft:~/lab-113-1$
Python aún no cargadoPythonLn 1, Col 1Spaces: 4UTF-8

¿Restablecer este tema?

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