Lección 4.5.3 · 70 min

Paper trading, shadow trading y seguimiento del slippage

El paper trading promete lo que el backtest promete: ejecuciones al precio medio, sin horquilla y casi sin latencia. Esta lección compara ejecución a ejecución el backtest, el paper y la cuenta real de un mismo sistema, separa el retraso del deslizamiento, recupera los parámetros de deslizamiento plantados por tipo de orden y momento, y monta el seguimiento que habría avisado en la primera semana.

Fig. — Deslizamiento extra de las órdenes a mercado (sobre la media horquilla) medido en paper y en real, con ±2 errores típicos, frente al valor plantado en los datos
Lecciones del nivel 4
  1. 4.1 · Teoría y optimización de carteras

    1. 4.1.1 Markowitz: frontera eficiente y restricciones reales
    2. 4.1.2 Estimación de covarianzas: shrinkage, modelos factoriales y denoising
    3. 4.1.3 Black-Litterman: del equilibrio del mercado a las visiones
    4. 4.1.4 Risk parity, mínima varianza, HRP y HERC
    5. 4.1.5 Optimización con CVaR, drawdown, rotación y costes
    6. 4.1.6 Modelos factoriales: CAPM, Fama-French, PCA y atribución
    7. 4.1.7 Rebalanceo y carteras de estrategias
    8. 4.1.8 Herramientas de carteras: Riskfolio-Lib, PyPortfolioOpt, skfolio y bt
  2. 4.2 · Gestión del riesgo y tamaño de posición

    1. 4.2.1 Riesgo por operación, stops y riesgo de ruina
    2. 4.2.2 Criterio de Kelly y volatility targeting: cuánto arriesgar
    3. 4.2.3 VaR, Expected Shortfall y backtesting del VaR
    4. 4.2.4 Stress testing y riesgos de correlación, liquidez, gap y contraparte
    5. 4.2.5 Control del drawdown y kill switch
    6. 4.2.6 Riesgo de derivados: griegas de cartera, margen y liquidaciones
  3. 4.3 · Microestructura y ejecución

    1. 4.3.1 Implementation shortfall, VWAP, TWAP y Almgren-Chriss
    2. 4.3.2 Order flow imbalance, señales de microestructura y latencia
  4. 4.4 · Brokers y APIs

    1. 4.4.1 Elegir bróker desde España o la UE: regulación, activos, costes y API
    2. 4.4.2 Interactive Brokers: TWS e IB Gateway, ib_async, contratos, datos y órdenes
    3. 4.4.3 Alpaca, Tradier, MetaTrader 5 con Python y OANDA v20
    4. 4.4.4 APIs de exchanges cripto: ccxt, Binance, Bybit, Kraken y Coinbase
    5. 4.4.5 Credenciales seguras: variables de entorno, gestores de secretos y permisos mínimos
  5. 4.5 · Sistema de trading en vivo

    1. 4.5.1 Arquitectura de un sistema en vivo: de los datos a la reconciliación
    2. 4.5.2 Gestión de órdenes: estados, fills parciales, cancelaciones y reconexiones
    3. 4.5.3 Paper trading, shadow trading y seguimiento del slippage
    4. 4.5.4 Programación de tareas y alertas: cron, APScheduler, Prefect, Telegram, Slack y email
    5. 4.5.5 Tolerancia a fallos: idempotencia, estado persistente y reconciliación al arrancar
    6. 4.5.6 NautilusTrader o LEAN en real: del backtest a producción con el mismo código

Tres precios para la misma orden

El checklist de la lección 2.5.8 terminaba en el paper trading: la estrategia corre en tiempo real con órdenes simuladas durante un periodo fijado de antemano, para comprobar que lo que supone el backtest ocurre. Esta lección lo hace con números. El sistema de los datos del nivel (lecciones 4.5.1 y 4.5.2) operó en una cuenta paper del 2 de septiembre al 10 de octubre de 2025 y en una cuenta real del 13 de octubre al 31 de diciembre, con las mismas reglas y 1.000.000 USD en cada una. Para cada señal hay tres precios:

  • Backtest (vivo4_backtest_fills.csv): lo que supone el backtest. El medio a la hora de la señal (15 minutos antes del cierre) para las órdenes a mercado y límite, el cierre oficial para las de cierre y la apertura de la sesión siguiente para las de los lunes que se ejecutan al abrir. Sin costes.
  • Medio al enviar (precio_medio_envio en vivo4_ordenes.csv): el precio medio del mercado cuando el OMS envía la orden. Es la referencia del deslizamiento.
  • Ejecución: el precio de cada ejecución que devolvió el broker.
Precio backtestRetrasoMedio al enviarDeslizamientoEjecución
Fuente Mermaid
flowchart TB
  B[Precio backtest] --> R[Retraso]
  R --> M[Medio al enviar]
  M --> D[Deslizamiento]
  D --> E[Ejecución]

La diferencia entre backtest y ejecución se parte en dos. El retraso es lo que se mueve el mercado entre la hora que supone el backtest y la del envío: si la señal no tiene información de corto plazo, su media es cero, pero su ruido es grande. El deslizamiento es lo que cuesta ejecutar frente al medio en el momento de enviar: media horquilla, impacto, latencia. Es lo que un modelo de costes (lecciones 2.4.7 y 4.3.1) tiene que estimar, y lo que el paper no tiene.

IN [01]python
import numpy as np
import pandas as pd
import statsmodels.formula.api as smf

ordn = pd.read_csv("vivo4_ordenes.csv",
                   parse_dates=["ts_envio", "fecha"])
ev = pd.read_csv("vivo4_eventos_broker.csv")
bt = pd.read_csv("vivo4_backtest_fills.csv")
ej = (ev[ev["evento"].isin(["parcial", "ejecutada"])]
      .drop_duplicates("id_ejecucion"))          # lección 4.5.2
x = (ej[["id_orden_cliente", "id_ejecucion", "cantidad_ultima",
         "precio_ultimo", "comision", "ts_broker"]]
     .merge(ordn, on="id_orden_cliente")
     .merge(bt[["id_senal", "precio_backtest", "supuesto"]],
            on="id_senal"))
x["s"] = np.where(x["lado"] == "compra", 1, -1)
x["efectivo"] = x["cantidad_ultima"] * x["precio_ultimo"]
pb = lambda a, b: x["s"] * (a / b - 1) * 1e4    # + = peor
x["total"] = pb(x["precio_ultimo"], x["precio_backtest"])
x["retraso"] = pb(x["precio_medio_envio"], x["precio_backtest"])
x["desliz"] = pb(x["precio_ultimo"], x["precio_medio_envio"])
print(len(x), "ejecuciones;", x.groupby("modo").size().to_dict())

def resumen(g):
    w = g["efectivo"]
    return pd.Series({c: np.average(g[c], weights=w)
                      for c in ("total", "retraso", "desliz")}
                     | {"efectivo_musd": w.sum() / 1e6,
                        "comisiones": g["comision"].sum()})

x.groupby("modo").apply(resumen, include_groups=False).round(2)
OUT [01]Ejecuciones con sus tres precios
531 ejecuciones; {'paper': 183, 'real': 348}
       total  retraso  desliz  efectivo_musd  comisiones
modo
paper  -0.04     0.27   -0.31           5.21      303.30
real    0.97    -0.77    1.74          11.70      593.71

Ponderadas por efectivo, las ejecuciones de paper salen 0,04 pb mejor que el backtest y las reales 0,97 pb peor. Pero mirar solo esa columna engaña: en la cuenta real el retraso aporta −0,77 pb (el mercado se movió a favor entre la señal y el envío, por azar) y el deslizamiento de ejecución es de 1,74 pb. En paper, el deslizamiento es de −0,31 pb: el broker de paper no cobra nada por ejecutar. Las órdenes al cierre tienen un deslizamiento sin sentido frente al medio al enviar (se ejecutan diez minutos después, en la subasta), así que en adelante el deslizamiento se mide solo con las órdenes a mercado.

Lo que simula un broker de paper

El simulador de paper de los datos llena las órdenes a mercado al precio medio del instante de la ejecución, sin horquilla y sin deslizamiento extra; la cuenta real paga media horquilla más un extra que depende del momento. Es una simplificación, pero no una caricatura: los brokers lo documentan. Alpaca dice que su paper trading no tiene en cuenta el impacto de las órdenes, la filtración de información, el deslizamiento por latencia, la posición en la cola de las límite no ejecutables, la mejora de precio, las tasas regulatorias ni los dividendos, y que la cantidad de la orden no se compara con la del mejor precio1Nota 1 · Alpaca, «Paper Trading» (consultado el 2026-10-22; enlace en los recursos).. Interactive Brokers advierte que las ejecuciones de su cuenta paper pueden caer o no dentro del mercado del momento y que no son indicativas de lo que pasaría en el real2Nota 2 · Interactive Brokers, «I Received an Execution in my Paper Trader Account that Did Not Correspond to the Market at the Time, What Happened?», actualizado el 11 de noviembre de 2024 (consultado el 2026-10-22; enlace en los recursos)..

IN [02]python
mk = x[x["tipo"] == "mercado"].copy()
mk["momento"] = np.where(
    mk["motivo"] == "resto_de_limite", "resto_limite",
    np.where(mk["ts_envio"].dt.hour < 17, "apertura", "cierre"))

def media_et(g):
    return pd.Series({"n": len(g), "media": g.mean(),
                      "desv": g.std(),
                      "et": g.std() / np.sqrt(len(g))})

med = (mk.groupby(["modo", "momento"])["desliz"]
       .apply(media_et).unstack())
med.round(2)
OUT [02]Deslizamiento de las órdenes a mercado, por modo y momento
                        n  media  desv    et
modo  momento
paper cierre        108.0   0.02  0.56  0.05
      resto_limite   21.0   0.14  0.43  0.09
real  apertura       31.0   5.22  3.73  0.67
      cierre        141.0   1.49  1.55  0.13
      resto_limite   48.0   2.32  2.40  0.35

En paper, el deslizamiento medio frente al medio al enviar es prácticamente cero (0,02 pb al cierre, 0,14 pb en los restos de las límite): lo único que queda es lo que se mueve el medio en los milisegundos entre el envío y la ejecución. En real hay tres momentos: las órdenes del cierre (10 minutos antes), los restos de las límite que no se llenaron (tres minutos antes del cierre) y las de los lunes que se ejecutan al abrir el martes. Abrir cuesta 5,2 pb, más del triple que cerrar (1,5 pb). Y cada media lleva su error típico: con 31 ejecuciones de apertura, ±0,67 pb; con 141 de cierre, ±0,13 pb.

La latencia es la otra mitad de la promesa del paper. Desde que el OMS envía hasta que recibe la aceptación, y desde la aceptación hasta la primera ejecución en el broker:

IN [03]python
ac = ev[ev["evento"] == "aceptada"].merge(
    ordn[["id_orden_cliente", "ts_envio", "tipo"]])
ac["ms_acuse"] = (pd.to_datetime(ac["ts_recibido"])
                  - ac["ts_envio"]).dt.total_seconds() * 1e3
prim = (ej.groupby("id_orden_cliente")["ts_broker"].min()
        .rename("primera"))
ac = ac.join(prim, on="id_orden_cliente")
ac["ms_ejec"] = (pd.to_datetime(ac["primera"])
                 - pd.to_datetime(ac["ts_broker"])
                 ).dt.total_seconds() * 1e3
q = lambda s: s.quantile([0.1, 0.5, 0.9]).round(1).tolist()
corte = ac["ms_acuse"] > 10_000      # acuse recibido tras un corte
print("acuses tras un corte:", ac[corte].groupby("modo").size()
      .to_dict())
for modo, g in ac[~corte].groupby("modo"):
    print(f"{modo:5s} acuse p10/p50/p90 ms:", q(g["ms_acuse"]),
          "| 1.ª ejecución a mercado:",
          q(g.loc[g["tipo"] == "mercado", "ms_ejec"]))
OUT [03]Latencias del paper y del real
acuses tras un corte: {'real': 42}
paper acuse p10/p50/p90 ms: [24.0, 31.3, 40.7] | 1.ª ejecución a mercado: [2.9, 5.0, 10.2]
real  acuse p10/p50/p90 ms: [69.8, 87.3, 110.0] | 1.ª ejecución a mercado: [19.4, 61.9, 167.9]
Fig. — Latencias del sistema en vivo en paper y en real: del envío al acuse recibido y de la aceptación a la primera ejecución de una orden a mercado (mediana y percentiles 10 a 90, escala logarítmica)

Antes, una exclusión: 42 acuses de la cuenta real llegaron más de 10 segundos después del envío. No es latencia sino los cortes de conexión de la lección 4.5.2: las órdenes enviadas justo antes de un corte reciben su acuse al reconectar, minutos después. Sin ellos, la mediana del acuse es de 31 ms en paper y de 87 ms en real; la primera ejecución de una orden a mercado llega en 5 ms en paper y en 62 ms en real, con un percentil 90 de 168 ms. Para un sistema que opera al cierre, unas decenas de milisegundos no cambian nada; para uno que reacciona a cada cotización, el paper falsea la parte más importante.

Recuperar los parámetros plantados

Los datos tienen la respuesta conocida: el precio de cada ejecución real a mercado es el medio por 1±(h+ε)/1041 \pm (h + \varepsilon)/10^4, con hh la media horquilla del ETF y ε\varepsilon un extra normal cuya media y desviación dependen del momento (vivo4_deslizamiento_verdad.csv). Lo medido arriba es h+εh + \varepsilon más el movimiento del medio durante la latencia. Para llegar a ε\varepsilon hace falta hh, y los datos no la dan directamente. Se puede estimar con la regla de las órdenes límite del sistema, que se colocan a un cuarto de horquilla del medio (media horquilla = 2 × la distancia del límite al medio):

IN [04]python
lim = ordn[ordn["tipo"] == "limite"]
s_l = np.where(lim["lado"] == "compra", 1, -1)
dist = s_l * (lim["precio_medio_envio"] - lim["precio_limite"]) \
    / lim["precio_medio_envio"] * 1e4
h = (2 * dist).groupby(lim["instrumento"]).agg(["mean", "count"])
print(h.round(2).T.to_string())
mk["h"] = np.where(mk["modo"] == "real",
                   mk["instrumento"].map(h["mean"]), 0.0)
OUT [04]La horquilla, estimada con las órdenes límite
instrumento   ORAU  ORCM  OREM   OREU   ORIG  ORRE   ORSC  ORTL   ORTN   ORUS
mean          0.67  1.59   1.6   0.88   0.36  0.93   0.49  0.72   0.33   0.19
count        13.00  6.00   9.0  12.00  13.00  6.00  17.00  9.00  14.00  12.00

Las medias horquillas estimadas van de 0,2 pb (ORUS, el ETF de la renta variable de EE. UU.) a 1,6 pb (OREM y ORCM, emergentes y materias primas). Son estimaciones ruidosas: el precio límite se redondea al céntimo, y en un ETF de 24 USD un céntimo son 4 pb, diez veces la distancia que se quiere medir; con seis órdenes, el error de ORCM es grande. En un broker real, la horquilla se mide con las cotizaciones (lección 1.1.5); aquí la regla de las límites basta.

IN [05]python
verdad = pd.read_csv("vivo4_deslizamiento_verdad.csv")
mk["extra"] = mk["desliz"] - mk["h"]
est = (mk.groupby(["modo", "momento"])["extra"]
       .apply(media_et).unstack()[["n", "media", "et"]])
comp = est.join(verdad.set_index(["modo", "momento"]))
comp["z"] = (comp["media"] - comp["media_pb"]) / comp["et"]
comp.round(2)
OUT [05]El extra estimado frente a la verdad
                        n  media    et  media_pb  desviacion_pb     z
modo  momento
paper cierre        108.0   0.02  0.05       0.0            0.0  0.31
      resto_limite   21.0   0.14  0.09       0.0            0.0  1.49
real  apertura       31.0   4.44  0.69       3.0            4.0  2.08
      cierre        141.0   0.85  0.13       1.0            1.5 -1.20
      resto_limite   48.0   1.61  0.34       1.5            2.0  0.32

La figura de la cabecera lo resume. Al cierre, el extra medido es de 0,85 ± 0,13 pb frente al 1,0 verdadero; en los restos de las límite, 1,61 ± 0,34 frente a 1,5. Los dos están a menos de 1,2 errores típicos de la verdad. En la apertura, 4,44 ± 0,69 frente a 3,0: a algo más de dos errores típicos, y con 31 ejecuciones de unos pocos lunes; es el tipo de diferencia que en datos reales no se sabría si es azar o un cambio de régimen. El paper da exactamente 0: es su regla. Y la columna de paper deja claro lo que no se puede hacer: calibrar el modelo de costes con el paper.

Las diferencias entre momentos se pueden medir sin conocer la horquilla. Con un efecto fijo por ETF, la horquilla de cada uno queda absorbida y la regresión da cuánto más cuesta la apertura o el resto que el cierre. Las varianzas son distintas por momento (casi 4 pb de desviación en la apertura, 1,5 al cierre), así que los errores tienen que ser robustos:

IN [06]python
real = mk[mk["modo"] == "real"]
fit = smf.ols("desliz ~ C(instrumento) + "
              "C(momento, Treatment('cierre'))", data=real
              ).fit(cov_type="HC1")
fila = fit.params.filter(like="momento")
tabla = pd.DataFrame({"coef": fila,
                      "et": fit.bse.filter(like="momento")})
tabla.index = ["apertura - cierre", "resto - cierre"]
tabla["verdad"] = [3.0 - 1.0, 1.5 - 1.0]
tabla.round(2)
OUT [06]Diferencias entre momentos con efectos fijos
                   coef    et  verdad
apertura - cierre  3.64  0.70     2.0
resto - cierre     0.87  0.35     0.5

La apertura cuesta unos 3,6 pb más que el cierre según la regresión, frente a 2,0 de verdad: el mismo exceso de las aperturas de la tabla anterior, ahora con un error típico robusto de unos 0,7 pb. El resto cuesta 0,9 pb más que el cierre, frente a 0,5. Con efectos fijos no hay nivel: la regresión no puede decir cuánto cuesta el cierre, solo cuánto más cuesta lo demás. Para el nivel hace falta la horquilla.

Un libro en sombra

Comparar el paper de septiembre con el real de noviembre mezcla dos cosas: la regla de ejecución y el mercado de cada periodo. El shadow trading (operar en sombra) las separa: el mismo sistema lleva, junto al libro real, un libro que aplica otra regla de ejecución a las mismas órdenes, los mismos días. Aquí la sombra es la regla del paper aplicada a las órdenes reales: cada ejecución a mercado al medio del envío, las límite a su límite y las de cierre al cierre. Es lo que habría dicho la cuenta paper si hubiera seguido en paralelo.

SeñalOMSBroker realLibro en sombraBacktestComparar
Fuente Mermaid
flowchart TB
  S[Señal] --> O[OMS]
  O --> BR[Broker real]
  O --> SB[Libro en sombra]
  BT[Backtest] --> C[Comparar]
  BR --> C
  SB --> C

Una variante habitual es la contraria: correr la estrategia nueva en sombra, sin enviar órdenes, junto a la que ya opera, con los mismos datos y el mismo reloj, y comparar sus señales y sus ejecuciones supuestas antes de darle dinero. La arquitectura de la lección 4.5.1 lo permite sin cambios: otra señal y otro OMS suscritos al mismo bus, con un broker simulado.

IN [07]python
r = x[x["modo"] == "real"].copy()
r["px_sombra"] = np.where(r["tipo"] == "mercado",
                          r["precio_medio_envio"], r["precio_ultimo"])
usd = lambda px: r["s"] * r["cantidad_ultima"] * (
    px - r["precio_backtest"])
r["coste_real"] = usd(r["precio_ultimo"]) + r["comision"]
r["coste_sombra"] = usd(r["px_sombra"]) + r["comision"]
tot = r[["coste_real", "coste_sombra"]].sum()
print(tot.round(2).to_dict())
oculto = tot["coste_real"] - tot["coste_sombra"]
efec_mk = r.loc[r["tipo"] == "mercado", "efectivo"].sum()
print(f"Lo que el paper esconde: {oculto:,.2f} USD, "
      f"{oculto / efec_mk * 1e4:.2f} pb de lo ejecutado a mercado")
import exchange_calendars as xcals
dias = len(xcals.get_calendar("XNYS").sessions_in_range(
    "2025-10-13", "2025-12-31"))
print(f"{dias} sesiones; al año, {oculto / dias * 252:,.0f} USD, "
      f"un {oculto / dias * 252 / 1e6:.2%} del capital")
OUT [07]Backtest, sombra y real en la cuenta real
{'coste_real': 1732.02, 'coste_sombra': 27.02}
Lo que el paper esconde: 1,705.00 USD, 2.49 pb de lo ejecutado a mercado
56 sesiones; al año, 7,672 USD, un 0.77% del capital
Fig. — Coste acumulado frente al backtest (precio y comisiones) del sistema en vivo: cuenta paper hasta el 10 de octubre y cuenta real después, con el libro en sombra que aplica la regla del paper a las órdenes reales

En las 56 sesiones de la cuenta real, el libro real cuesta 1.732 USD frente al backtest (deslizamiento y comisiones) y la sombra, 27 USD: las comisiones casi compensadas por el retraso, que esos días jugó a favor. La diferencia, 1.705 USD, es lo que el paper esconde: el deslizamiento de las órdenes a mercado, 2,49 pb de lo que se ejecutó a mercado. Llevado a un año, unos 7.700 USD, un 0,77 % del capital, para una estrategia que espera unos pocos puntos al año. La figura muestra el coste acumulado frente al backtest de los dos periodos. En paper, la curva sube y baja con el retraso (cientos de dólares en un día) y termina en 283 USD, casi solo comisiones. En real, la curva real y la sombra suben y bajan juntas, porque el retraso es el mismo para las dos, pero la distancia entre ellas crece casi sin interrupción: es el deslizamiento, que se paga en cada orden. Ningún mes de paper habría anticipado esa distancia.

Seguimiento del slippage en vivo

Medir el deslizamiento al final del trimestre no basta: hay que saber pronto si el modelo de costes está mal. La herramienta clásica es un CUSUM de Page: acumula las desviaciones del deslizamiento observado frente al que dice el modelo, menos una holgura, y avisa cuando la suma pasa un umbral.

St=max⁡ ⁣(0,  St−1+dt−d^tσ−k),alarma si St>hS_t = \max\!\left(0,\; S_{t-1} + \frac{d_t - \widehat{d}_t}{\sigma} - k\right), \qquad \text{alarma si } S_t > h

con dtd_t el deslizamiento de la ejecución tt, d^t\widehat{d}_t el del modelo, σ\sigma la desviación esperada (1,5 pb al cierre), k=0,5k = 0{,}5 (detecta desvíos de un sigma) y h=5h = 5 (pocas falsas alarmas). Se aplica a las ejecuciones de cierre de la cuenta real, en orden, con tres modelos de coste: el del paper (0), solo la media horquilla y la media horquilla más 1 pb.

IN [08]python
def cusum(d, modelo, sigma=1.5, k=0.5, h=5.0):
    s, camino = 0.0, []
    for v in (d - modelo) / sigma:
        s = max(0.0, s + v - k)
        camino.append(s)
    camino = np.array(camino)
    salta = np.argmax(camino > h) if (camino > h).any() else None
    return camino, salta

cie = mk[(mk["modo"] == "real") & (mk["momento"] == "cierre")] \
    .sort_values("ts_broker")
modelos = {"paper (0)": 0.0, "media horquilla": cie["h"],
           "horquilla + 1 pb": cie["h"] + 1.0}
for nombre, mod in modelos.items():
    camino, i = cusum(cie["desliz"], mod)
    cuando = ("nunca" if i is None else
              f"ejecución {i + 1}, {cie['ts_broker'].iloc[i][:10]}")
    print(f"{nombre:17s} alarma: {cuando}")

ape = mk[(mk["modo"] == "real") & (mk["momento"] == "apertura")] \
    .sort_values("ts_broker")
_, i = cusum(ape["desliz"], ape["h"] + 1.0)
print("aperturas con el modelo del cierre: alarma en la ejecución",
      i + 1, ape["ts_broker"].iloc[i][:10])
OUT [08]CUSUM del deslizamiento al cierre
paper (0)         alarma: ejecución 8, 2025-10-21
media horquilla   alarma: ejecución 9, 2025-10-21
horquilla + 1 pb  alarma: nunca
aperturas con el modelo del cierre: alarma en la ejecución 2 2025-10-14

Con el modelo del paper, la alarma salta en la octava ejecución de cierre, el 21 de octubre: seis sesiones después de empezar en real. Con solo la media horquilla, una ejecución más tarde: el extra de 1 pb es pequeño pero constante. Con horquilla más 1 pb no salta nunca en once semanas: es el modelo bueno. Si se aplicase el modelo del cierre a las aperturas, saltaría en la segunda ejecución: los modelos de coste se calibran y se vigilan por momento y tipo de orden, no en bloque.

nosíEjecuciónDeslizamientoCUSUM por momentoPasa el umbralAlertaRecalibrar modelo
Fuente Mermaid
flowchart TB
  E[Ejecución] --> D[Deslizamiento]
  D --> C[CUSUM por momento]
  C --> A{Pasa el umbral}
  A -- no --> E
  A -- sí --> AL[Alerta]
  AL --> R[Recalibrar modelo]

La alerta no corrige nada sola: dice que el modelo de costes con el que se aprobó la estrategia ya no describe la realidad. Lo siguiente es recalibrarlo con las ejecuciones reales y repetir el backtest con él (lección 2.4.7); si la estrategia ya no compensa sus costes, se reduce o se para (lección 4.2.5). El envío de la alerta es la lección 4.5.4.

Lo que el paper sí comprueba

Nada de lo anterior hace inútil el paper trading. Las seis semanas de paper de los datos sirvieron para comprobar que las señales en vivo coinciden con las del backtest (lección 4.5.1), que la máquina de estados aguanta los mensajes reales del broker y una desconexión (lección 4.5.2), que los rechazos se tratan bien y que el sistema arranca y para cada día sin intervención. Para lo que no sirvieron es para medir costes. La forma práctica de unirlo: paper para la operativa, una cuenta real pequeña para los costes (con la sombra en paralelo), y el tamaño completo solo cuando el CUSUM lleve semanas sin saltar con el modelo con el que se hizo el backtest.

Ejercicios

  1. Repite la descomposición del primer apartado solo con las órdenes a mercado del cierre. ¿Cuánto del 1,74 pb de deslizamiento real explica la media horquilla estimada?
Solución
IN [09]python
c = mk[mk["momento"] == "cierre"]
for modo, g in c.groupby("modo"):
    w = g["efectivo"]
    print(modo, "deslizamiento", round(np.average(g["desliz"],
                                                  weights=w), 2),
          "| media horquilla", round(np.average(g["h"], weights=w), 2),
          "| retraso", round(np.average(g["retraso"], weights=w), 2))
OUT [09]Solo órdenes a mercado del cierre
paper deslizamiento 0.03 | media horquilla 0.0 | retraso 1.67
real deslizamiento 1.4 | media horquilla 0.55 | retraso -0.43

Al cierre, la cuenta real paga 1,4 pb ponderado por efectivo, de los que la media horquilla estimada explica 0,55: el resto es el extra. En paper, 0,03. El retraso, en cambio, cambia de signo entre periodos (+1,67 pb en paper, −0,43 en real): es el ruido del mercado en cinco minutos, no un coste, y cuatro meses no bastan para que su media se acerque a cero.

  1. ¿Depende el deslizamiento real a mercado del ETF? Compara el deslizamiento medio por ETF con su media horquilla estimada.
Solución
IN [10]python
por = (mk[mk["modo"] == "real"].groupby("instrumento")
       .agg(n=("desliz", "size"), desliz=("desliz", "mean"),
            h=("h", "first")))
por["desliz - h"] = por["desliz"] - por["h"]
print(por.round(2).sort_values("h").to_string())
print("correlación desliz-h:", round(por["desliz"].corr(por["h"]), 2))
OUT [10]Deslizamiento y horquilla por ETF
              n  desliz     h  desliz - h
instrumento
ORUS         20    1.12  0.19        0.92
ORTN         25    2.85  0.33        2.53
ORIG         34    1.79  0.36        1.43
ORSC         28    2.10  0.49        1.61
ORAU         22    2.22  0.67        1.55
ORTL         27    1.36  0.72        0.64
OREU         19    3.58  0.88        2.70
ORRE         18    2.26  0.93        1.32
ORCM          9    3.04  1.59        1.45
OREM         18    2.68  1.60        1.08
correlación desliz-h: 0.53

Los ETF con más horquilla deslizan algo más (correlación de 0,53 entre las diez medias), pero lo que queda tras restar la media horquilla va de 0,6 a 2,7 pb. Con unas 20 ejecuciones por ETF, mezclando momentos (cada ETF tiene una proporción distinta de aperturas, que cuestan el triple) y horquillas estimadas con pocas órdenes, cada media tiene un error de medio punto o más: los datos no permiten distinguir un extra por ETF, y en la verdad plantada no lo hay, solo depende del momento. En datos reales, el extra también depende del tamaño de la orden frente a la liquidez (impacto, lección 4.3.1); aquí las órdenes son pequeñas frente al volumen de los ETF y ese efecto no está.

  1. Una estrategia espera 3 pb de beneficio bruto por operación y opera al cierre con órdenes a mercado. Con lo medido en la cuenta real, ¿cuánto queda? ¿Y si la mitad de las operaciones se hicieran en la apertura?
Solución

Al cierre, el deslizamiento real medio es de 1,5 pb por ejecución y las comisiones añaden algo más (0,0035 USD por acción: 0,35 pb en una acción de 100 USD): quedan unos 1,1 pb, poco más de un tercio de lo esperado. Si la mitad se ejecuta en la apertura (5,2 pb), el deslizamiento medio sube a unos 3,4 pb y la estrategia pierde dinero antes de comisiones. El paper habría dicho 3 pb limpios en los dos casos.

Footnotes

  1. Alpaca, «Paper Trading» (consultado el 2026-10-22; enlace en los recursos). ↩

  2. Interactive Brokers, «I Received an Execution in my Paper Trader Account that Did Not Correspond to the Market at the Time, What Happened?», actualizado el 11 de noviembre de 2024 (consultado el 2026-10-22; enlace en los recursos). ↩

Respuesta plegada en cada pregunta

Autoevaluación

  1. ¿Por qué las ejecuciones a mercado de la cuenta paper de los datos salen a 0,02 pb del medio y las de la cuenta real a 1,49 pb?

    • APorque el broker de paper llena al precio medio, sin horquilla ni deslizamiento; la cuenta real paga media horquilla más un extra
    • BPorque en paper el sistema operó mejor
    • CPorque la cuenta real tenía más capital
    • DPor azar: con más datos serían iguales
    Ver respuesta

    Respuesta A. Porque el broker de paper llena al precio medio, sin horquilla ni deslizamiento; la cuenta real paga media horquilla más un extra

    Es la regla del simulador de paper de los datos, y la de muchos brokers en alguna medida: Alpaca, por ejemplo, documenta que su paper no tiene en cuenta el impacto, el deslizamiento por latencia ni la posición en la cola. El 0,02 que queda en paper es el movimiento del medio en los milisegundos de latencia.

  2. La cuenta real ejecuta 0,97 pb peor que el backtest. ¿Por qué no basta esa cifra para calibrar el modelo de costes?

    • APorque está en puntos básicos
    • BPorque el backtest no tiene comisiones
    • CSí basta
    • DPorque mezcla el retraso (el medio se mueve 5 minutos entre la señal y el envío, con media cero pero mucho ruido) con el deslizamiento de ejecución
    Ver respuesta

    Respuesta D. Porque mezcla el retraso (el medio se mueve 5 minutos entre la señal y el envío, con media cero pero mucho ruido) con el deslizamiento de ejecución

    Frente al medio al enviar, la cuenta real paga 1,74 pb; frente al backtest, 0,97 pb, porque el retraso aporta −0,77 pb de puro ruido en estos cuatro meses. El coste de ejecución se mide frente al medio en el momento de enviar; el retraso, aparte.

  3. ¿Qué recupera la regresión del deslizamiento sobre efectos fijos de ETF y del momento, sin conocer las horquillas?

    • ALas horquillas
    • BLas diferencias de deslizamiento entre momentos (apertura frente a cierre), no su nivel
    • CEl deslizamiento total
    • DNada
    Ver respuesta

    Respuesta B. Las diferencias de deslizamiento entre momentos (apertura frente a cierre), no su nivel

    Con un efecto fijo por ETF, la horquilla de cada ETF y el nivel común se confunden: solo se identifican las diferencias. Para el nivel hace falta la horquilla, que en la lección se estima con las órdenes límite.

  4. Un CUSUM vigila el deslizamiento al cierre frente a un modelo calibrado con el paper (coste esperado 0). ¿Cuándo salta?

    • ANunca
    • BAl final de diciembre
    • CEn la octava ejecución al cierre de la cuenta real, el 21 de octubre, a la semana de empezar
    • DAntes de empezar
    Ver respuesta

    Respuesta C. En la octava ejecución al cierre de la cuenta real, el 21 de octubre, a la semana de empezar

    El coste real al cierre es de 1,5 pb por ejecución y el modelo dice 0: la suma acumulada pasa el umbral en ocho ejecuciones. Con un modelo de horquilla más 1 pb no salta nunca: está bien calibrado.

  5. ¿Qué aporta un libro en sombra frente a comparar el paper de septiembre con el real de noviembre?

    • ANada
    • BMás rentabilidad
    • CEvita pagar comisiones
    • DCompara las mismas órdenes, los mismos días y los mismos precios con dos reglas de ejecución: la diferencia es solo la regla, no el mercado
    Ver respuesta

    Respuesta D. Compara las mismas órdenes, los mismos días y los mismos precios con dos reglas de ejecución: la diferencia es solo la regla, no el mercado

    Paper y real en periodos distintos mezclan la regla de ejecución con el mercado de cada periodo. La sombra aplica la regla del paper a las órdenes reales: en la lección, la diferencia son 1.705 USD en once semanas, 2,49 pb sobre lo ejecutado a mercado.

Ideas clave

  • El paper trading comprueba que el sistema funciona (señales, órdenes, estados, reconexiones); no mide costes. Su broker suele llenar al medio, sin cola ni impacto.
  • La diferencia entre backtest y real se separa en retraso (ruido de media cero si la señal no tiene información de corto plazo) y deslizamiento de ejecución (el coste que se puede modelar).
  • El deslizamiento depende del momento: en los datos, abrir a mercado el lunes cuesta unas tres veces más que ejecutar al cierre. Un modelo único se equivoca en los dos.
  • Cada media lleva su error típico: con 31 ejecuciones, el deslizamiento de apertura se mide con ±0,7 pb; con 141, el de cierre con ±0,13.
  • Un libro en sombra aplica otra regla de ejecución a las mismas órdenes y aísla lo que cuesta la regla.
  • El seguimiento en vivo es un contraste secuencial (CUSUM) del deslizamiento frente al modelo, por momento: salta en días si el modelo es el del paper.

Recursos