Presiona ESC para cerrar

Order Book vs AMM: Microestructura y Arbitraje HFT

Si todavía crees que ejecutar un trade en un exchange es solo darle clic al botón de «Buy» y dejar que la magia suceda, tengo noticias para ti. A nivel de microsegundos y milisegundos, el mercado es una guerra encarnizada donde la liquidez fluye de un lado a otro, y donde la velocidad de ejecución junto con la anatomía del pool determinan quién se lleva el profit y quién termina pagando el costo del deslizamiento (slippage) y el flujo tóxico.

En el trading centralizado (TradFi y CEX), el Order Book es el rey. En DeFi, el estándar dorado pasó a ser el AMM. Pero cuando nos bajamos a la arena del trading de alta frecuencia (HFT), la diferencia entre ambos no es un mero detalle técnico: cambia de raíz la mecánica de formación de precios, el arbitraje y la forma en que se llenan las órdenes.

Vamos a abrir el cofre y ver cómo funciona la liquidez bajo el capó en ambos sistemas, dónde se esconden los costos invisibles y cómo sacarle jugo a esto en la práctica.

1. Anatomía del libro L2/L3: Cómo se ve la liquidez en la vida real

La mayoría de los retail traders solo ven el libro nivel L2: volúmenes agregados en cada nivel de precio. Pero los algoritmos de HFT y los institucionales operan en L3 (Order-by-Order), un feed de datos crudo donde cada evento tiene su propio ID único (order_id), timestamp de alta precisión y su lugar exacto en la cola.

Market Data
 

El principio Price-Time Priority (FIFO)

En un matching engine tradicional, las órdenes se ejecutan a rajatabla según estas prioridades:

  • Precio (el mejor precio pasa primero).
  • Tiempo (a igual precio, se llena primero el que llegó antes a la fila).

Esta cola por tiempo genera dos efectos clave en la microestructura:

Adverse Selection (Selección Adversa): Si tu orden límite de compra se llena de golpe, lo más probable es que un pez gordo haya entrado a vender masivamente (toxic flow), y el precio siga cayendo en picada.

Queue Position Value: Estar al frente de la fila en un nivel de precio vale dinero por sí solo. Los bots de HFT viven cancelando y metiendo órdenes otra vez (técnicas de Spoofing/Layering o gestión adaptativa de liquidez) para no perder la prioridad sin comerse un riesgo de inventario innecesario.

2. AMM: Del clásico Constant Product a la liquidez concentrada

Un AMM juega en otra liga comparado con el order book: aquí no hay filas de espera. El precio lo marca la matemática de una función invariante.

Constant Product (v2): x · y = k

En el Uniswap v2 de toda la vida, la liquidez está distribuida desde cero hasta el infinito.

Cuando metes un trade de volumen Δx, te sacas del pool un monto Δy, calculado descontando el fee γ = (1 - fee):

Δy = (y · Δx · γ) / (x + Δx · γ)

El precio de ejecución no es fijo, se va «deslizando» a lo largo de la curva en pleno execution time.

Concentrated Liquidity (v3 / Basado en Ticks)

Uniswap v3 convirtió los AMM en algo muy parecido a un order book, permitiendo a los proveedores de liquidez (LPs) acotar sus rangos [Pa, Pb].

El precio se divide en ticks, donde cada tick representa un cambio de precio del 0.01% (1 bps):

P(i) = 1.0001i

La liquidez L dentro del rango se comporta como un invariante «virtual», pero cuando el precio cruza la frontera de un tick, la liquidez activa cambia de golpe. Para un arbitrajista de HFT esto es clave: la liquidez en AMM v3 es discreta y su profundidad escala a saltos cada vez que se rompe un tick.

3. Cuadro comparativo: Matriz de Microestructura

ParámetroOrder Book (CEX/TradFi)AMM (Uniswap v2)AMM Concentrado (v3)
Prioridad de ejecuciónPrecio-Tiempo (FIFO) / Pro-RataPrecio del Gas / MEV (Priority Fee)Precio del Gas / MEV (Priority Fee)
Latencia (Latency)Microsegundos / NanosegundosTiempo de bloque (o latencia por slot)Tiempo de bloque / Mempool P2P
Descubrimiento de precioSubasta doble continua (Continuous Double Auction)Dinámico según volumen del trade (x · y = k)Dinámico dentro del tick activo
Costos de liquidezSin pérdida impermanente (pero hay Inventory Risk)Impermanent Loss (IL)Loss-Versus-Rebalancing (LVR)
Transparencia del flujoFeeds de datos L3 (Pitch, ITCH, FIX)Mempool (pre-bloque) / On-chain (post-bloque)Mempool (pre-bloque) / On-chain (post-bloque)

4. Mecánicas ocultas: MEV, LVR y Toxic Flow

En el order book de un CEX, los operadores de HFT compiten por nanosegundos de latencia física (colocación en el centro de datos del exchange, fibra óptica dedicada, placas FPGA).

En DeFi la noción del tiempo se distorsiona: lo que manda es cómo se arma la estructura del bloque.

MEV (Maximal Extractable Value)

En un AMM, el orden de las transacciones dentro de un bloque lo deciden los Searchers y Builders. Esto da pie a estrategias de HFT bastante avanzadas:

  • Front-running / Back-running: Pasan por delante de tu orden en el mempool ofreciendo una propina más alta (Priority Fee).
  • Ataques Sándwich: Compran justo antes de que entre la orden de un volumen alto para inflarle el precio y le venden inmediatamente después.

LVR (Loss-Versus-Rebalancing)

Casi todos calculan el riesgo de ser LP usando el Impermanent Loss (IL). Pero a nivel microsegundo, la métrica clave es el LVR, un concepto desarrollado por investigadores de Columbia y el equipo de Paradigm.

LVR (Loss-Versus-Rebalancing) — es la pérdida sistemática que sufre un proveedor de liquidez en un AMM comparado con haber tenido ese mismo portafolio rebalanceándose todo el tiempo en un CEX usando precios externos.

El culpable del LVR es el arbitraje de volatilidad. Cuando el precio en los CEX pega un salto, el pool del AMM se queda mostrando un precio desactualizado (stale price). Un arbitrajista de HFT detecta este spread al instante, ejecuta contra la liquidez barata del AMM y se cubre en el CEX. El proveedor de liquidez del AMM termina vendiendo siempre al peor precio posible contra flujo informado (toxic flow).

LVR ≈ (σ² / 8) · ∫0T St · Lt dt

Donde σ es la volatilidad del activo, St es el precio y Lt la liquidez activa. Conclusión: Cuanto más volátil esté el mercado, mayor es el valor extraído por los arbitrajistas de HFT a costa de los LPs.

5. Manos a la obra: Script en Python para cotizar AMM v2 vs Profundidad L2

Pasemos al código. Vamos a armar un script funcional para simular el precio real de ejecución (tomando en cuenta el slippage) de una orden, comparando la profundidad de un libro L2 contra un pool de AMM Constant Product.

El código está escrito en Python puro, sin dependencias externas.

from __future__ import annotations
from dataclasses import dataclass
from enum import Enum
from typing import List
class ModoComision(Enum):
    COTIZADO = "quote"  # La comisión se deduce del USDT entrante
    BASE = "base"        # La comisión se deduction del ETH recibido
@dataclass
class NivelAsk:
    precio: float
    volumen: float
class LibroOrdenesL2:
    """
    Libro de órdenes L2 (Lado Ask / Venta).
    Ejemplo para el par ETH/USDT:
        precio  = USDT por cada 1 ETH
        volumen = Cantidad de ETH
    """
    def __init__(
        self,
        asks: List[tuple[float, float]],
        comision_taker: float = 0.001,
    ) -> None:
        if not (0 <= comision_taker < 1):
            raise ValueError("comision_taker debe estar en el rango [0, 1)")
        self.comision_taker = float(comision_taker)
        self.asks: List[NivelAsk] = []
        for precio, volumen in asks:
            if precio <= 0:
                raise ValueError("El precio debe ser > 0")
            if volumen <= 0:
                raise ValueError("El volumen debe ser > 0")
            self.asks.append(
                NivelAsk(
                    precio=float(precio),
                    volumen=float(volumen),
                )
            )
        self.asks.sort(key=lambda x: x.precio)
    def mejor_ask(self) -> float:
        if not self.asks:
            raise ValueError("El libro de órdenes está vacío")
        return self.asks[0].precio
    def precio_spot(self) -> float:
        return self.mejor_ask()
    def liquidez_total_cotizado(self) -> float:
        return sum(
            nivel.precio * nivel.volumen
            for nivel in self.asks
        )
    def liquidez_total_base(self) -> float:
        return sum(
            nivel.volumen
            for nivel in self.asks
        )
    def simular_compra(
        self,
        monto_en_cotizado: float,
        mutar: bool = True,
        modo_comision: ModoComision = ModoComision.COTIZADO,
    ) -> tuple[float, float]:
        """
        Compra de activo base utilizando monto_en_cotizado.
        Retorna:
            (
                activo_base_recibido,
                precio_promedio_efectivo
            )
        """
        if monto_en_cotizado <= 0:
            raise ValueError("monto_en_cotizado debe ser > 0")
        if modo_comision == ModoComision.COTIZADO:
            cotizado_para_trade = (
                monto_en_cotizado *
                (1.0 - self.comision_taker)
            )
        else:
            cotizado_para_trade = monto_en_cotizado
        cotizado_restante = cotizado_para_trade
        total_base_comprado = 0.0
        nuevos_niveles: List[NivelAsk] = []
        for nivel in self.asks:
            if cotizado_restante <= 0:
                nuevos_niveles.append(nivel)
                continue
            costo_nivel = nivel.precio * nivel.volumen
            if cotizado_restante >= costo_nivel:
                total_base_comprado += nivel.volumen
                cotizado_restante -= costo_nivel
            else:
                base_del_nivel = cotizado_restante / nivel.precio
                total_base_comprado += base_del_nivel
                volumen_restante = nivel.volumen - base_del_nivel
                if volumen_restante > 1e-12:
                    nuevos_niveles.append(
                        NivelAsk(
                            nivel.precio,
                            volumen_restante,
                        )
                    )
                cotizado_restante = 0.0
        if cotizado_restante > 1e-9:
            raise ValueError("Liquidez insuficiente en el libro de órdenes")
        if modo_comision == ModoComision.BASE:
            total_base_comprado *= (1.0 - self.comision_taker)
        if total_base_comprado <= 0:
            raise ValueError("El volumen obtenido es cero")
        precio_promedio = monto_en_cotizado / total_base_comprado
        if mutar:
            self.asks = nuevos_niveles
        return total_base_comprado, precio_promedio
class AMMProductoConstante:
    """
    AMM estilo Uniswap v2
    x = ETH (Activo Base)
    y = USDT (Activo Cotizado)
    precio_spot = y / x
    """
    def __init__(
        self,
        reserva_x: float,
        reserva_y: float,
        comision: float = 0.003,
    ) -> None:
        if reserva_x <= 0:
            raise ValueError("reserva_x debe ser > 0")
        if reserva_y <= 0:
            raise ValueError("reserva_y debe ser > 0")
        if not (0 <= comision < 1):
            raise ValueError("la comision debe estar en el rango [0, 1)")
        self.x = float(reserva_x)
        self.y = float(reserva_y)
        self.comision = float(comision)
    def precio_spot(self) -> float:
        return self.y / self.x
    def invariante(self) -> float:
        return self.x * self.y
    def simular_compra(
        self,
        monto_y_entrada: float,
        mutar: bool = True,
    ) -> tuple[float, float]:
        """
        Compra de ETH a cambio de USDT.
        Retorna:
            (
                ETH_recibido,
                precio_promedio
            )
        """
        if monto_y_entrada <= 0:
            raise ValueError("monto_y_entrada debe ser > 0")
        y_efectivo = monto_y_entrada * (1.0 - self.comision)
        x_salida = (
            self.x * y_efectivo
        ) / (
            self.y + y_efectivo
        )
        if x_salida <= 0:
            raise ValueError("El volumen obtenido es cero")
        if x_salida >= self.x:
            raise ValueError("Liquidez insuficiente en el pool")
        precio_promedio = monto_y_entrada / x_salida
        if mutar:
            self.x -= x_salida
            self.y += monto_y_entrada
        return x_salida, precio_promedio
def imprimir_resultado_trade(
    titulo: str,
    recibido: float,
    precio_promedio: float,
    precio_spot: float,
) -> None:
    deslizamiento = (
        (precio_promedio - precio_spot) / precio_spot
    ) * 100
    print(
        f"{titulo:<12}"
        f" Recibido: {recibido:.6f}"
        f" | Precio prom.: {precio_promedio:,.4f}"
        f" | Deslizamiento: {deslizamiento:.4f}%"
    )
def main() -> None:
    asks = [
        (3000.0, 1.5),
        (3001.0, 2.0),
        (3002.5, 5.0),
        (3005.0, 10.0),
        (3010.0, 25.0),
    ]
    libro_ordenes = LibroOrdenesL2(
        asks=asks,
        comision_taker=0.001,
    )
    amm = AMMProductoConstante(
        reserva_x=1000.0,
        reserva_y=3_000_000.0,
        comision=0.003,
    )
    tamanio_trade = 15_000.0
    spot_libro = libro_ordenes.precio_spot()
    spot_amm = amm.precio_spot()
    recibido_libro, prom_libro = libro_ordenes.simular_compra(
        monto_en_cotizado=tamanio_trade,
        mutar=True,
        modo_comision=ModoComision.COTIZADO,
    )
    recibido_amm, prom_amm = amm.simular_compra(
        monto_y_entrada=tamanio_trade,
        mutar=True,
    )
    print(
        f"\n=== Comparación de ejecución de orden "
        f"por {tamanio_trade:,.2f} USDT ===\n"
    )
    imprimir_resultado_trade(
        "ORDERBOOK",
        recibido_libro,
        prom_libro,
        spot_libro,
    )
    imprimir_resultado_trade(
        "AMM V2",
        recibido_amm,
        prom_amm,
        spot_amm,
    )
    print("\n=== Estado después de la transacción ===\n")
    if libro_ordenes.asks:
        print(
            f"Mejor Ask: "
            f"{libro_ordenes.mejor_ask():,.4f}"
        )
    else:
        print("El libro de órdenes se ha vaciado por completo")
    print(
        f"AMM Spot: "
        f"{amm.precio_spot():,.4f}"
    )
    print(
        f"Reservas AMM: "
        f"{amm.x:.6f} ETH | "
        f"{amm.y:.2f} USDT"
    )
if __name__ == "__main__":
    main()

Cómo leer estos números

En pools de AMM profundos, las órdenes pequeñas pasan con soltura y con un deslizamiento mínimo, pero a medida que incrementas el volumen, la curva convexa eleva el precio rápidamente. En un libro de órdenes, en cambio, la ejecución depende directamente de los muros de liquidez existentes (liquidity walls). Si el libro carece de suficiente profundidad, la orden consumirá múltiples niveles de precio, lo que resulta en un precio promedio significativamente peor que en el AMM.

6. Modelos Híbridos: Cómo los DEX adoptan el Order Book y por qué los CEX le echan el ojo a los AMM

La frontera entre los libros de órdenes y los AMM se está borrando cada vez más. Los traders de alta frecuencia (HFT) y los institucionales chocaron de frente contra el techo de cristal de Uniswap v2: su baja eficiencia de capital y la imposibilidad de meter órdenes límite complejas (Stop-loss, Take-profit, Iceberg) hacían que los DEX fueran súper incómodos para un market making activo.

Esto provocó un salto evolutivo clave: el nacimiento de las arquitecturas híbridas.

1. Order Books On-Chain y en L2 (dYdX, Hyperliquid, Vertex)

Con el boom de las redes L1/L2 de alto rendimiento (Aptos, Sui, Arbitrum) y las AppChains especializadas, por fin fue posible correr libros de órdenes completos directamente sobre la blockchain.

Off-chain matching + On-chain settlement: Los motores de matcheo de órdenes corren off-chain en engines ultra rápidos (para meter latencias de < 10 ms), mientras que la ejecución final y las exigencias de margen se liquidan seguro en smart contracts.

Fully On-chain (Hyperliquid, Serum/Ellipsis): El order book vive 100% en el consenso de la red. El verdadero dolor de cabeza aquí es bancarse un volumen absurdo de operaciones: en HFT, el flujo de reemplazo y cancelación de órdenes (Cancel/Replace) representa hasta el 95–98% de todas las transacciones entrantes.

2. Arquitectura basada en Intents y RFQ (Request for Quote)

El modelo de "Intents" (Uniswap X, 1inch Fusion, CoW Protocol) básicamente trae de vuelta el enfoque institucional de ejecución.

Aquí el trader no firma una transacción para interactuar con un pool específico, sino que firma una intención (por ejemplo: «Quiero cambiar 100 ETH por no menos de 300,000 USDC»). A partir de ahí, una red de ejecutores terceros (Fillers / Solvers) se pelea por ver quién llena la orden usando la fuente de liquidez que se le da la gana: CEX, inventario privado de market makers o DEX.

Architecture
 

Para el trader de a pie, esto se traduce en slippage cero y protección total contra ataques sandwich de MEV: todo el riesgo de deslizamiento y ejecución se lo traga el Solver, que busca sacarle jugo al arbitraje entre activos.

7. Manos a la obra: Script avanzado de arbitraje entre un Order Book L2 de CEX y un AMM v2

En la cancha, los bots de HFT viven cazando desbalances de precio entre CEX y AMM. Si en un CEX el precio de un token se dispara por un market buy agresivo, el pool del AMM se queda "desactualizado" (stale) por unos momentos. El arbitrajista aprovecha para comprar en el AMM, empujando su precio hasta igualar al CEX, y descarga de una el volumen comprado en el CEX.

Acá tenés un script en Python 100% funcional que calcula en tiempo real el tamaño óptimo de la jugada de arbitraje (dx), contemplando los fees del AMM, la profundidad del libro del CEX y las comisiones de maker/taker.

from __future__ import annotations
from dataclasses import dataclass
from typing import List, Dict, Any
@dataclass
class BidLevel:
    price: float
    volume: float
class OrderBookSide:
    """
    Lado Bid del order book.
    price  = precio de compra
    volume = volumen del activo base
    """
    def __init__(self, bids: List[tuple[float, float]]):
        self.bids: List[BidLevel] = []
        for price, volume in bids:
            if price <= 0:
                raise ValueError("El precio debe ser > 0")
            if volume <= 0:
                raise ValueError("El volumen debe ser > 0")
            self.bids.append(
                BidLevel(
                    float(price),
                    float(volume)
                )
            )
        self.bids.sort(
            key=lambda x: x.price,
            reverse=True
        )
    def is_empty(self) -> bool:
        return len(self.bids) == 0
    def best_bid(self) -> float:
        if self.is_empty():
            raise ValueError("El order book está vacío")
        return self.bids[0].price
    def cumulative_levels(self) -> List[tuple[float, float]]:
        """
        Devuelve los puntos de quiebre de liquidez.
        [
            (2 ETH, VWAP hasta 2 ETH),
            (7 ETH, VWAP hasta 7 ETH),
            ...
        ]
        """
        result = []
        cumulative_x = 0.0
        cumulative_y = 0.0
        for level in self.bids:
            cumulative_x += level.volume
            cumulative_y += level.volume * level.price
            result.append(
                (
                    cumulative_x,
                    cumulative_y
                )
            )
        return result
    def execute_sell(
        self,
        amount_x: float
    ) -> tuple[float, float]:
        """
        Vende amount_x contra el order book.
        Devuelve:
        (
            USDT_recibido,
            VWAP
        )
        """
        if amount_x <= 0:
            raise ValueError(
                "amount_x debe ser > 0"
            )
        remaining_x = amount_x
        received_y = 0.0
        for level in self.bids:
            if remaining_x <= 0:
                break
            executed = min(
                remaining_x,
                level.volume
            )
            received_y += (
                executed *
                level.price
            )
            remaining_x -= executed
        if remaining_x > 1e-9:
            raise ValueError(
                "Sin liquidez suficiente en el order book"
            )
        vwap = received_y / amount_x
        return received_y, vwap
class AMMPool:
    """
    Constant Product AMM
    x = ETH
    y = USDT
    """
    def __init__(
        self,
        reserve_x: float,
        reserve_y: float,
        fee: float = 0.003
    ):
        if reserve_x <= 0:
            raise ValueError(
                "reserve_x debe ser > 0"
            )
        if reserve_y <= 0:
            raise ValueError(
                "reserve_y debe ser > 0"
            )
        if not (0 <= fee < 1):
            raise ValueError(
                "fee debe estar en el rango [0,1)"
            )
        self.x = float(reserve_x)
        self.y = float(reserve_y)
        self.fee = float(fee)
        
    def spot_price(self) -> float:
        return self.y / self.x
        
    def calculate_out_x(
        self,
        amount_y_in: float
    ) -> float:
        if amount_y_in <= 0:
            raise ValueError(
                "amount_y_in debe ser > 0"
            )
        y_effective = (
            amount_y_in *
            (1.0 - self.fee)
        )
        x_out = (
            self.x *
            y_effective
        ) / (
            self.y +
            y_effective
        )
        return x_out
        
    def calculate_required_y_for_x(
        self,
        target_x_out: float
    ) -> float:
        """
        Inversa de la fórmula del AMM.
        Cuánto USDT hay que ingresar
        para sacar target_x_out.
        """
        if target_x_out <= 0:
            raise ValueError(
                "target_x_out debe ser > 0"
            )
        if target_x_out >= self.x:
            raise ValueError(
                "No podés drenar toda la reserva"
            )
        y_effective = (
            target_x_out *
            self.y
        ) / (
            self.x -
            target_x_out
        )
        amount_y_in = (
            y_effective /
            (1.0 - self.fee)
        )
        return amount_y_in
def find_optimal_arbitrage(
    amm: AMMPool,
    cex_bids: OrderBookSide,
    cex_fee: float = 0.001
) -> Dict[str, Any]:
    if not (0 <= cex_fee < 1):
        raise ValueError(
            "cex_fee debe estar en el rango [0,1)"
        )
    if cex_bids.is_empty():
        return {
            "opportunity": False,
            "reason": "Order book del CEX vacío"
        }
    best_bid = cex_bids.best_bid()
    if (
        best_bid *
        (1.0 - cex_fee)
        <=
        amm.spot_price()
    ):
        return {
            "opportunity": False,
            "reason": "Sin spread aprovechable"
        }
    best_result = None
    best_profit = float("-inf")
    cumulative = cex_bids.cumulative_levels()
    for cumulative_x, cumulative_y in cumulative:
        try:
            required_usdt = (
                amm.calculate_required_y_for_x(
                    cumulative_x
                )
            )
            gross_usdt = cumulative_y
            net_usdt = (
                gross_usdt *
                (1.0 - cex_fee)
            )
            profit = (
                net_usdt -
                required_usdt
            )
            if profit > best_profit:
                avg_buy_price = (
                    required_usdt /
                    cumulative_x
                )
                avg_sell_price = (
                    gross_usdt /
                    cumulative_x
                )
                amm_spot = (
                    amm.spot_price()
                )
                impact_pct = (
                    (
                        avg_buy_price -
                        amm_spot
                    )
                    /
                    amm_spot
                ) * 100
                roi_pct = (
                    profit /
                    required_usdt
                ) * 100
                best_profit = profit
                best_result = {
                    "opportunity": True,
                    "input_usdt_amm": required_usdt,
                    "bought_x": cumulative_x,
                    "gross_usdt_cex": gross_usdt,
                    "net_usdt_cex": net_usdt,
                    "net_profit_usdt": profit,
                    "roi_pct": roi_pct,
                    "amm_spot_price": amm_spot,
                    "amm_avg_buy_price": avg_buy_price,
                    "amm_price_impact_pct": impact_pct,
                    "cex_vwap": avg_sell_price,
                }
        except ValueError:
            continue
    if best_result is None:
        return {
            "opportunity": False,
            "reason": "Liquidez insuficiente"
        }
    if best_result["net_profit_usdt"] <= 0:
        return {
            "opportunity": False,
            "reason": "El slippage liquida el profit"
        }
    return best_result
def main():
    amm = AMMPool(
        reserve_x=1000.0,
        reserve_y=3_000_000.0,
        fee=0.003
    )
    cex = OrderBookSide([
        (3050.0, 2.0),
        (3048.0, 5.0),
        (3045.0, 10.0),
        (3040.0, 20.0),
        (3030.0, 50.0),
    ])
    result = find_optimal_arbitrage(
        amm,
        cex,
        cex_fee=0.0005
    )
    print(
        "\n=== Resultado de búsqueda de arbitraje ===\n"
    )
    if not result["opportunity"]:
        print(
            f"Estado: CANCELADO\n"
            f"Razón: {result['reason']}"
        )
        return
    print("Estado: OPORTUNIDAD ENCONTRADA")
    print()
    print(
        f"Inyección en AMM: "
        f"${result['input_usdt_amm']:,.2f}"
    )
    print(
        f"ETH comprado: "
        f"{result['bought_x']:.6f}"
    )
    print(
        f"Retorno bruto CEX: "
        f"${result['gross_usdt_cex']:,.2f}"
    )
    print(
        f"Retorno neto CEX: "
        f"${result['net_usdt_cex']:,.2f}"
    )
    print(
        f"Profit neto: "
        f"${result['net_profit_usdt']:,.2f}"
    )
    print(
        f"ROI: "
        f"{result['roi_pct']:.4f}%"
    )
    print(
        f"AMM Spot: "
        f"{result['amm_spot_price']:.4f}"
    )
    print(
        f"AMM Precio promedio compra: "
        f"{result['amm_avg_buy_price']:.4f}"
    )
    print(
        f"AMM Price Impact: "
        f"{result['amm_price_impact_pct']:.4f}%"
    )
    print(
        f"CEX VWAP: "
        f"{result['cex_vwap']:.4f}"
    )
if __name__ == "__main__":
    main()

8. Conclusiones clave para el trader: Cómo no regalar plata por puro desconocimiento

Entender la microestructura de mercado no es teoría académica para guardarla en un cajón. Es la herramienta principal para evitar que tu capital se vaya desangrando en fugas invisibles.

  • Asegurate de usar el tipo de orden correcto según el estado del mercado: En un CEX, tirar una orden a mercado (Market Order) pesada barre varios niveles del libro sin piedad, comiéndote con un slippage brutal. Si necesitás salir o entrar ya mismo, usá órdenes IOC (Immediate-or-Cancel) o FOK (Fill-or-Kill) marcando el peor precio que estás dispuesto a aceptar.
  • Medí la profundidad real, no solo el spread: Un spread finito en L2 ($0.01) suele ser un espejismo. Si en el mejor Bid/Ask solo hay $100 de liquidez, tu orden de $50,000 va a atravesar el libro hasta zonas con precios astronómicos.
  • Ojo con el flujo tóxico en los AMM: Si aportás liquidez en Uniswap v3 en un rango ajustado justo cuando sale una noticia jodida o la volatilidad se dispara, sos carne de cañón para los bots de HFT. La métrica LVR se va a tragar todas tus ganancias por fees en cuestión de minutos.
  • Cubrite del MEV en los DEX: Cuando metas trades en AMMs, clavale siempre un límite al Slippage Tolerance (idealmente entre 0.1 y 0.3%) o salí usando endpoints RPC privados (como Flashbots Protect / MEV-Blocker) para que tu transacción no quede expuesta en el mempool público a la caza de un sandwich attack.

¡Contanos en los comentarios con cuánto deslizamiento te solés cruzar cuando metés órdenes pesadas y qué modelo (Order Book en CEX o AMM en DEX) elegís para tu operatoria del día a día!


FAQ

El Order Book empareja órdenes límite y de mercado mediante una subasta continua basada en la prioridad de precio y tiempo (FIFO), mientras que los Automated Market Makers (AMMs) ejecutan operaciones algorítmicamente contra pools de liquidez a través de invariantes matemáticas como X x Y = k.

La pérdida impermanente mide la depreciación relativa del portafolio frente al HODL debido al cambio absoluto de precio, mientras que el Loss-Versus-Rebalancing (LVR) cuantifica el costo sistémico de selección adversa pagado a los arbitrajistas de alta frecuencia (HFT) que explotan precios desactualizados en los pools AMM frente a los exchanges centralizados.

Los bots MEV monitorean transacciones pendientes en el mempool público, insertando una orden frontal (front-running) con alta comisión de prioridad para inflar artificialmente el precio del token antes de la orden objetivo, y ejecutan una orden posterior (back-running) en el mismo bloque para extraer ganancias libres de riesgo.
Martyn Borkowski

I am a crypto trader specializing in digital assets and blockchain markets.

My focus is on identifying opportunities, managing risk, and optimizing strategies to achieve consistent growth in the fast-evolving world of cryptocurrency.

Verification & Professional Profiles: X Profile

...

Escribe una opinión

Tu correo electrónico no será publicado. Los campos obligatorios están marcados *