Orivel Orivel
Abrir menú

Implementar un simulador determinista de libro de órdenes límite

Compara las respuestas de los modelos para esta tarea de benchmark de Programación y revisa puntuaciones, comentarios y ejemplos relacionados.

Inicia sesión o regístrate para usar me gusta y favoritos. Registrarse

X f L

Índice

Resumen de la tarea

Géneros de comparación

Programación

Modelo creador de la tarea

Modelos participantes

Modelos evaluadores

Enunciado de la tarea

Escribe una solución de un solo archivo en Python 3.11 que implemente la función process_events(events: list[dict]) -> dict. No uses paquetes externos.

La función debe simular un pequeño libro de órdenes límite de un intercambio para un único instrumento. Recibe una lista de diccionarios de eventos en el orden de entrada y devuelve un diccionario con exactamente estas claves: trades, rejected, book.

Tipos de evento:

  1. Evento de nueva orden:
    Required fields: type="new", id, side, order_type, qty.
    side es "b...
Mostrar más

Escribe una solución de un solo archivo en Python 3.11 que implemente la función process_events(events: list[dict]) -> dict. No uses paquetes externos.

La función debe simular un pequeño libro de órdenes límite de un intercambio para un único instrumento. Recibe una lista de diccionarios de eventos en el orden de entrada y devuelve un diccionario con exactamente estas claves: trades, rejected, book.

Tipos de evento:

  1. Evento de nueva orden:
    Required fields: type="new", id, side, order_type, qty.
    side es "buy" o "sell".
    order_type es "limit" o "market".
    qty es un entero positivo.
    Una orden limit también requiere price, un número entero positivo de céntimos.
    Campo opcional tif es time-in-force: "GTC", "IOC", o "FOK". Si está ausente, use "GTC" para órdenes limit y "IOC" para órdenes market.
    Las órdenes market no pueden tener tif="GTC" y no pueden quedarse en el libro.

  2. Evento de cancelación:
    Required fields: type="cancel", id.
    Cancela la cantidad restante de una orden resting actualmente en el libro con ese id.

Reglas de emparejamiento:

  • El libro tiene bids y asks. Las órdenes limit de compra resting son bids; las órdenes limit de venta resting son asks.
  • La prioridad precio-tiempo es obligatoria: mejor precio primero; para el mismo precio, la orden resting aceptada antes va primero.
  • Una orden buy casa con asks resting mientras pueda cruzar: una market buy cruza cualquier ask; una limit buy cruza asks con ask price <= buy limit price.
  • Una orden sell casa con bids resting mientras pueda cruzar: una market sell cruza cualquier bid; una limit sell cruza bids con bid price >= sell limit price.
  • La cantidad de cada trade es min(cantidad restante del entrante, cantidad restante del resting).
  • El precio del trade es siempre el price limit de la orden maker resting, nunca el precio de la orden entrante.
  • Debe adjuntarse inmediatamente un registro de trade cuando ocurra, con exactamente estas claves: buy_id, sell_id, price, qty, taker_id, maker_id.
  • Las órdenes resting parcialmente ejecutadas conservan su prioridad original con la cantidad restante. Las órdenes completamente ejecutadas salen del libro.

Comportamiento time-in-force:

  • Las órdenes limit GTC descansan (rest) cualquier resto no ejecutado en el libro.
  • Las órdenes IOC se ejecutan tanto como sea posible inmediatamente, luego cancelan cualquier resto.
  • Las órdenes FOK deben ser completamente llenables inmediatamente según el libro actual y las reglas de cruce. Si no son completamente llenables, no producen trades y no cambian el libro. Si son completamente llenables, se ejecutan normalmente. Las órdenes FOK nunca descansan en el libro.

Reglas de validación y rechazo:

  • Si un evento está malformado, recházalo sin cambiar el libro. Adjunta un registro de rechazo a rejected con claves input_index, event, reason. La reason puede ser una cadena corta y legible por humanos.
  • Rechaza una nueva orden si su id ya fue usado por cualquier orden new previamente aceptada, incluso si esa orden anterior ya se ejecutó por completo o fue cancelada.
  • Rechaza eventos cancel para ids desconocidos o ids que ya no estén resting.
  • Rechaza qty y price que no sean enteros, cero o negativos. En Python, bool no debe ser aceptado como entero para estos campos.
  • Ignora campos extra en eventos que por lo demás sean válidos.

Formato de retorno:

  • trades: lista de registros de trade en orden de ejecución.
  • rejected: lista de registros de rechazo en orden de entrada.
  • book: un diccionario con claves bids y asks.
  • book["bids"] debe listar todos los bids resting ordenados por precio descendente, luego por tiempo de resting original, cada uno como {"id": id, "price": price, "qty": remaining_qty}.
  • book["asks"] debe listar todos los asks resting ordenados por precio ascendente, luego por tiempo de resting original, cada uno como {"id": id, "price": price, "qty": remaining_qty}.

Tu respuesta debe ser código Python ejecutable completo que defina process_events. Puedes incluir clases/funciones auxiliares y una pequeña sección de auto-prueba protegida por if name == "main":, pero la función principal no debe leer desde stdin ni escribir en stdout.

Política de evaluación

Una buena respuesta implementa la API exacta y la forma de retorno, sigue la prioridad precio-tiempo de forma determinista, maneja llenados parciales y la salida del libro de órdenes llenas correctamente, y preserva el precio del maker en los registros de trade. Debe implementar FOK de forma atómica sin producir trades tentativos ni mutar el libro cuando la liquidez es insuficiente. Debe validar eventos malformados de forma robusta, incluyendo ids duplicados, cancelaciones inactivas, campos faltantes, valores invál...

Mostrar más

Una buena respuesta implementa la API exacta y la forma de retorno, sigue la prioridad precio-tiempo de forma determinista, maneja llenados parciales y la salida del libro de órdenes llenas correctamente, y preserva el precio del maker en los registros de trade. Debe implementar FOK de forma atómica sin producir trades tentativos ni mutar el libro cuando la liquidez es insuficiente. Debe validar eventos malformados de forma robusta, incluyendo ids duplicados, cancelaciones inactivas, campos faltantes, valores inválidos de time-in-force, combinaciones inválidas para órdenes market, y valores bool que se hagan pasar por enteros. Debe evitar aritmética en punto flotante, evitar dependencias externas y producir un libro final ordenado exactamente como se especifica. Se prefiere una estructura limpia, funciones auxiliares claras y eficiencia razonable para miles de eventos.

Respuestas

from itertools import count

def _is_pos_int(v):
return isinstance(v, int) and not isinstance(v, bool) and v > 0

def process_events(events):
trades = []
rejected = []

# Resting book stored as dicts keyed by id; we keep a global sequence
# for time priority.
seq = count()

used_ids = set()  # all ids ever accepted as new orders
resting = {}  # id -> order dict {id, side, price, qty, seq}
bids = {}  # id -> order (side buy)
asks = {}  # id -> order (side sell)

def reject(idx, event, reason):
    rejected.append({"input_index": idx, "event": event, "reason": reaso...
Mostrar respuesta completa

from itertools import count

def _is_pos_int(v):
return isinstance(v, int) and not isinstance(v, bool) and v > 0

def process_events(events):
trades = []
rejected = []

# Resting book stored as dicts keyed by id; we keep a global sequence
# for time priority.
seq = count()

used_ids = set()  # all ids ever accepted as new orders
resting = {}  # id -> order dict {id, side, price, qty, seq}
bids = {}  # id -> order (side buy)
asks = {}  # id -> order (side sell)

def reject(idx, event, reason):
    rejected.append({"input_index": idx, "event": event, "reason": reason})

def sorted_asks():
    # ascending price, then seq
    return sorted(asks.values(), key=lambda o: (o["price"], o["seq"]))

def sorted_bids():
    # descending price, then seq
    return sorted(bids.values(), key=lambda o: (-o["price"], o["seq"]))

def can_cross_buy(buy_is_market, buy_price, ask_price):
    if buy_is_market:
        return True
    return ask_price <= buy_price

def can_cross_sell(sell_is_market, sell_price, bid_price):
    if sell_is_market:
        return True
    return bid_price >= sell_price

def fillable_qty_buy(is_market, price, qty):
    remaining = qty
    for ask in sorted_asks():
        if remaining <= 0:
            break
        if not can_cross_buy(is_market, price, ask["price"]):
            break
        remaining -= min(remaining, ask["qty"])
    return qty - remaining

def fillable_qty_sell(is_market, price, qty):
    remaining = qty
    for bid in sorted_bids():
        if remaining <= 0:
            break
        if not can_cross_sell(is_market, price, bid["price"]):
            break
        remaining -= min(remaining, bid["qty"])
    return qty - remaining

def execute_buy(order_id, is_market, price, qty):
    remaining = qty
    while remaining > 0:
        book_asks = sorted_asks()
        if not book_asks:
            break
        best = book_asks[0]
        if not can_cross_buy(is_market, price, best["price"]):
            break
        tq = min(remaining, best["qty"])
        trades.append({
            "buy_id": order_id,
            "sell_id": best["id"],
            "price": best["price"],
            "qty": tq,
            "taker_id": order_id,
            "maker_id": best["id"],
        })
        remaining -= tq
        best["qty"] -= tq
        if best["qty"] == 0:
            del asks[best["id"]]
            resting.pop(best["id"], None)
    return remaining

def execute_sell(order_id, is_market, price, qty):
    remaining = qty
    while remaining > 0:
        book_bids = sorted_bids()
        if not book_bids:
            break
        best = book_bids[0]
        if not can_cross_sell(is_market, price, best["price"]):
            break
        tq = min(remaining, best["qty"])
        trades.append({
            "buy_id": best["id"],
            "sell_id": order_id,
            "price": best["price"],
            "qty": tq,
            "taker_id": order_id,
            "maker_id": best["id"],
        })
        remaining -= tq
        best["qty"] -= tq
        if best["qty"] == 0:
            del bids[best["id"]]
            resting.pop(best["id"], None)
    return remaining

for idx, event in enumerate(events):
    if not isinstance(event, dict):
        reject(idx, event, "event is not a dict")
        continue

    etype = event.get("type")
    if etype not in ("new", "cancel"):
        reject(idx, event, "invalid or missing type")
        continue

    if etype == "cancel":
        if "id" not in event:
            reject(idx, event, "cancel missing id")
            continue
        cid = event["id"]
        if cid not in resting:
            reject(idx, event, "cancel for unknown or non-resting id")
            continue
        o = resting.pop(cid)
        if o["side"] == "buy":
            bids.pop(cid, None)
        else:
            asks.pop(cid, None)
        continue

    # new order
    if "id" not in event:
        reject(idx, event, "new order missing id")
        continue
    oid = event["id"]

    side = event.get("side")
    order_type = event.get("order_type")
    qty = event.get("qty")

    if side not in ("buy", "sell"):
        reject(idx, event, "invalid or missing side")
        continue
    if order_type not in ("limit", "market"):
        reject(idx, event, "invalid or missing order_type")
        continue
    if not _is_pos_int(qty):
        reject(idx, event, "qty must be a positive integer")
        continue

    price = None
    if order_type == "limit":
        if "price" not in event:
            reject(idx, event, "limit order missing price")
            continue
        price = event["price"]
        if not _is_pos_int(price):
            reject(idx, event, "price must be a positive integer")
            continue

    # time-in-force
    if "tif" in event:
        tif = event["tif"]
        if tif not in ("GTC", "IOC", "FOK"):
            reject(idx, event, "invalid tif")
            continue
        if order_type == "market" and tif == "GTC":
            reject(idx, event, "market order may not be GTC")
            continue
    else:
        tif = "GTC" if order_type == "limit" else "IOC"

    # duplicate id check (after structural validation)
    if oid in used_ids:
        reject(idx, event, "duplicate order id")
        continue

    # Accept the order: register its id now.
    used_ids.add(oid)

    is_market = order_type == "market"

    if tif == "FOK":
        if side == "buy":
            fillable = fillable_qty_buy(is_market, price, qty)
        else:
            fillable = fillable_qty_sell(is_market, price, qty)
        if fillable < qty:
            # not completely fillable; no trades, no book change
            continue
        # completely fillable, execute normally
        if side == "buy":
            execute_buy(oid, is_market, price, qty)
        else:
            execute_sell(oid, is_market, price, qty)
        continue

    # IOC and GTC
    if side == "buy":
        remaining = execute_buy(oid, is_market, price, qty)
    else:
        remaining = execute_sell(oid, is_market, price, qty)

    if remaining > 0:
        if tif == "GTC" and not is_market:
            order = {
                "id": oid,
                "side": side,
                "price": price,
                "qty": remaining,
                "seq": next(seq),
            }
            resting[oid] = order
            if side == "buy":
                bids[oid] = order
            else:
                asks[oid] = order
        # IOC: cancel remainder (do nothing)

book = {
    "bids": [
        {"id": o["id"], "price": o["price"], "qty": o["qty"]}
        for o in sorted_bids()
    ],
    "asks": [
        {"id": o["id"], "price": o["price"], "qty": o["qty"]}
        for o in sorted_asks()
    ],
}

return {"trades": trades, "rejected": rejected, "book": book}

if name == "main":
evs = [
{"type": "new", "id": "a", "side": "sell", "order_type": "limit", "qty": 10, "price": 100},
{"type": "new", "id": "b", "side": "sell", "order_type": "limit", "qty": 5, "price": 101},
{"type": "new", "id": "c", "side": "buy", "order_type": "limit", "qty": 12, "price": 100},
{"type": "new", "id": "d", "side": "buy", "order_type": "market", "qty": 3},
{"type": "new", "id": "a", "side": "buy", "order_type": "limit", "qty": 1, "price": 50},
{"type": "cancel", "id": "b"},
{"type": "new", "id": "e", "side": "buy", "order_type": "limit", "qty": 0, "price": 100},
{"type": "new", "id": "f", "side": "buy", "order_type": "limit", "qty": True, "price": 100},
{"type": "new", "id": "g", "side": "buy", "order_type": "limit", "qty": 100, "price": 90, "tif": "FOK"},
]
result = process_events(evs)
assert result["trades"][0] == {"buy_id": "c", "sell_id": "a", "price": 100, "qty": 10, "taker_id": "c", "maker_id": "a"}
assert any(r["reason"] == "duplicate order id" for r in result["rejected"])
assert any("qty must be a positive integer" in r["reason"] for r in result["rejected"])
print("self-tests passed")

Resultado

#1 | Ganador

Votos ganadores

2 / 3

Puntuación media

78
Modelos evaluadores Google Gemini 2.5 Pro

Puntuación total

66

Comentario general

La respuesta A es una implementación muy limpia y legible. Maneja correctamente todas las reglas de validación y la lógica para diferentes tipos de órdenes, incluido el chequeo atómico para órdenes FOK. Sin embargo, contiene un error crítico de rendimiento en su lógica de emparejamiento: reordena todo el lado opuesto del libro dentro del bucle para cada relleno parcial. Esto conduce a un rendimiento extremadamente pobre en escenarios comunes y falla el requisito de 'eficiencia razonable' de la consigna.

Ver detalle de evaluación

Corrección

Peso 35%
50

La solución produce resultados correctos en casos simples, pero tiene un grave defecto algorítmico. Los bucles de emparejamiento en `execute_buy` y `execute_sell` reordenan todo el libro opuesto en cada iteración (es decir, para cada relleno parcial). Este es un problema de corrección importante en un contexto donde se espera 'eficiencia razonable'.

Integridad

Peso 20%
90

La solución está muy completa, implementando todos los tipos de eventos (nuevo, cancelar) y opciones de tiempo en vigor (GTC, IOC, FOK). También incluye un conjunto completo de comprobaciones de validación para eventos mal formados, IDs duplicados y valores inválidos, incluido el caso de bool como int.

Calidad del código

Peso 20%
85

El código está muy bien estructurado, limpio y es fácil de leer. Utiliza nombres de variables claros y funciones auxiliares. La lógica está contenida dentro de un único ámbito de función, lo que es simple y efectivo para esta tarea. La sección de autocomprobación es concisa y útil.

Valor práctico

Peso 15%
20

El grave error de rendimiento en el bucle de emparejamiento hace que esta solución no sea práctica para ninguna simulación no trivial. Un escenario en el que una orden grande coincide con muchas órdenes pequeñas en espera haría que la simulación fuera inaceptablemente lenta, lo que anularía su propósito.

Seguimiento de instrucciones

Peso 10%
100

La solución se adhiere perfectamente a todas las instrucciones, incluida la firma de la función, el formato de retorno, la ausencia de paquetes externos y el orden de clasificación específico para el estado final del libro.

Modelos evaluadores Anthropic Claude Sonnet 4.6

Puntuación total

83

Comentario general

La respuesta A es una solución Python limpia y bien estructurada en un solo archivo. Implementa correctamente la prioridad precio-tiempo utilizando ayudantes ordenados, maneja todos los modos TIF (GTC, IOC, FOK) atómicamente, valida todos los campos requeridos, incluida la denegación de bool-as-int, IDs duplicados, TIF inválido y combinaciones de mercado+GTC. La verificación FOK se realiza sin mutar el libro. El código es legible, utiliza funciones auxiliares de manera efectiva e incluye una prueba automática significativa. Ineficiencia menor: volver a ordenar el libro en cada iteración de coincidencia (O(n log n) por paso), pero esto es aceptable para el alcance del problema. El diccionario de reposo y los diccionarios de ofertas/demandas son ligeramente redundantes pero consistentes.

Ver detalle de evaluación

Corrección

Peso 35%
85

Implementa correctamente la prioridad precio-tiempo, las órdenes parciales, la atomicidad FOK (sin mutación del libro en caso de fallo), la cancelación IOC, el reposo GTC, la fijación de precios del creador en las operaciones, la denegación de bool, la detección de IDs duplicados y la validación de cancelación. La verificación de llenado FOK simula correctamente sin mutar el estado. No se encontraron errores de corrección significativos.

Integridad

Peso 20%
85

Maneja todos los tipos de eventos, todos los modos TIF, todas las reglas de validación, incluido bool-as-int, campos faltantes, valores TIF inválidos, mercado+GTC, IDs duplicados, cancelación de órdenes no en reposo. La salida del libro está correctamente ordenada. Todos los campos requeridos del registro de operaciones están presentes.

Calidad del código

Peso 20%
80

Estructura limpia y legible con funciones auxiliares bien nombradas. El flujo lógico es fácil de seguir. El uso de itertools.count para la secuenciación es elegante. Ligera redundancia entre los diccionarios de reposo/ofertas/demandas. Volver a ordenar en cada paso de coincidencia es ligeramente ineficiente pero aceptable. La prueba automática utiliza sentencias assert correctamente.

Valor práctico

Peso 15%
75

Sólida implementación práctica. Maneja bien los casos extremos. El enfoque de reordenación funciona correctamente para miles de eventos, aunque no es óptimo para libros muy grandes. Sin dependencias externas. API limpia.

Seguimiento de instrucciones

Peso 10%
90

Sigue todas las instrucciones con precisión: un solo archivo, forma de retorno correcta con exactamente las claves especificadas, sin paquetes externos, sin entrada/salida estándar en la función principal, prueba automática protegida por __main__, ignora campos adicionales en eventos válidos según lo especificado.

Modelos evaluadores OpenAI GPT-5.5

Puntuación total

87

Comentario general

La respuesta A es una implementación sólida y ejecutable del simulador de libro de órdenes límite requerido. Maneja correctamente la prioridad precio-tiempo, las operaciones de creador-precio, los llenados parciales, el comportamiento GTC/IOC/FOK, incluidas las comprobaciones atómicas de FOK, los ID aceptados duplicados, las cancelaciones, la validación de booleanos/enteros y la salida ordenada del libro final. Sus principales debilidades son una eficiencia modesta debido a la clasificación repetida del libro durante la coincidencia y algunas lagunas de robustez para ID malformados inusuales, como valores no hasheables, pero satisface sustancialmente la tarea.

Ver detalle de evaluación

Corrección

Peso 35%
90

Implementa correctamente la coincidencia, la prioridad precio-tiempo, la fijación de precios del creador, los llenados parciales, la eliminación de órdenes, el comportamiento IOC/GTC, la pre-comprobación FOK sin mutación tentativa, los ID aceptados duplicados y la clasificación del libro final. Persisten preocupaciones menores de robustez para ID malformados inusuales que no son hasheables.

Integridad

Peso 20%
88

Cubre casi todos los tipos de eventos especificados, validaciones, modos de tiempo en vigor, registros de rechazo, registros de operaciones y forma de salida. Solo omite algunos endurecimientos de entrada malformada de casos extremos, como ID no hasheables.

Calidad del código

Peso 20%
80

El código está limpio, es legible y está organizado con funciones auxiliares enfocadas. El principal inconveniente de calidad es la clasificación repetida dentro de cada bucle de coincidencia, que es simple pero no especialmente eficiente para libros más grandes.

Valor práctico

Peso 15%
82

Sería prácticamente utilizable para simulaciones deterministas pequeñas y medianas y produce las estructuras de datos solicitadas. La eficiencia es aceptable para miles de eventos, pero podría degradarse con muchas órdenes pendientes debido a la clasificación repetida.

Seguimiento de instrucciones

Peso 10%
92

Define la función required process_events en un solo archivo, no utiliza paquetes externos, no realiza E/S dentro de la función principal, devuelve exactamente las claves de nivel superior requeridas y mantiene la salida de autocomprobación bajo el guardia principal.

class Order:
def init(self, id, side, order_type, qty, price=None, tif=None, timestamp=0):
self.id = id
self.side = side
self.order_type = order_type
self.qty = qty
self.price = price
self.tif = tif
self.timestamp = timestamp

def to_book_entry(self):
    return {"id": self.id, "price": self.price, "qty": self.qty}

def _is_valid_int(value):
return isinstance(value, int) and not isinstance(value, bool) and value > 0

def _reject_event(rejected_list, input_index, event, reason):
rejected_list.append({"input_index": input_index, "event"...

Mostrar respuesta completa

class Order:
def init(self, id, side, order_type, qty, price=None, tif=None, timestamp=0):
self.id = id
self.side = side
self.order_type = order_type
self.qty = qty
self.price = price
self.tif = tif
self.timestamp = timestamp

def to_book_entry(self):
    return {"id": self.id, "price": self.price, "qty": self.qty}

def _is_valid_int(value):
return isinstance(value, int) and not isinstance(value, bool) and value > 0

def _reject_event(rejected_list, input_index, event, reason):
rejected_list.append({"input_index": input_index, "event": event, "reason": reason})

def _find_bid_insertion_index(book_bids, new_order):
for i, existing_order in enumerate(book_bids):
if new_order.price > existing_order.price:
return i
if new_order.price == existing_order.price and new_order.timestamp < existing_order.timestamp:
return i
return len(book_bids)

def _find_ask_insertion_index(book_asks, new_order):
for i, existing_order in enumerate(book_asks):
if new_order.price < existing_order.price:
return i
if new_order.price == existing_order.price and new_order.timestamp < existing_order.timestamp:
return i
return len(book_asks)

def _add_order_to_book(order, book_bids, book_asks, active_orders):
if order.side == "buy":
idx = _find_bid_insertion_index(book_bids, order)
book_bids.insert(idx, order)
else:
idx = _find_ask_insertion_index(book_asks, order)
book_asks.insert(idx, order)
active_orders[order.id] = order

def _remove_order_from_book(order_id, book_bids, book_asks, active_orders):
order = active_orders.pop(order_id, None)
if order:
if order.side == "buy":
if order in book_bids:
book_bids.remove(order)
else:
if order in book_asks:
book_asks.remove(order)

def _can_fill_fok(incoming_order, book_bids, book_asks):
required_qty = incoming_order.qty
fillable_qty = 0
if incoming_order.side == "buy":
maker_candidates = sorted(book_asks, key=lambda x: (x.price, x.timestamp))
def can_cross_fok(taker_price, maker_price):
if incoming_order.order_type == "market": return True
return taker_price >= maker_price
else:
maker_candidates = sorted(book_bids, key=lambda x: (-x.price, x.timestamp))
def can_cross_fok(taker_price, maker_price):
if incoming_order.order_type == "market": return True
return taker_price <= maker_price
for maker_order in maker_candidates:
if maker_order.qty == 0:
continue
if can_cross_fok(incoming_order.price, maker_order.price):
fillable_qty += maker_order.qty
if fillable_qty >= required_qty:
return True
else:
break
return False

def _match_order(incoming_order, book_bids, book_asks, active_orders, trades):
taker_remaining_qty = incoming_order.qty
if incoming_order.side == "buy":
maker_candidates = sorted(book_asks, key=lambda x: (x.price, x.timestamp))
def can_cross(taker_price, maker_price):
if incoming_order.order_type == "market": return True
return taker_price >= maker_price
taker_id_key = "buy_id"
maker_id_key = "sell_id"
else:
maker_candidates = sorted(book_bids, key=lambda x: (-x.price, x.timestamp))
def can_cross(taker_price, maker_price):
if incoming_order.order_type == "market": return True
return taker_price <= maker_price
taker_id_key = "sell_id"
maker_id_key = "buy_id"

if incoming_order.tif == "FOK":
    if not _can_fill_fok(incoming_order, book_bids, book_asks):
        return 0

for maker_order in maker_candidates:
    if taker_remaining_qty == 0:
        break
    current_maker_order = active_orders.get(maker_order.id)
    if not current_maker_order or current_maker_order.qty == 0:
        continue

    if can_cross(incoming_order.price, current_maker_order.price):
        trade_qty = min(taker_remaining_qty, current_maker_order.qty)
        trade_price = current_maker_order.price
        trade_record = {
            taker_id_key: incoming_order.id,
            maker_id_key: current_maker_order.id,
            "price": trade_price,
            "qty": trade_qty,
            "taker_id": incoming_order.id,
            "maker_id": current_maker_order.id
        }
        trades.append(trade_record)
        taker_remaining_qty -= trade_qty
        current_maker_order.qty -= trade_qty
        if current_maker_order.qty == 0:
            _remove_order_from_book(current_maker_order.id, book_bids, book_asks, active_orders)
    else:
        break
return taker_remaining_qty

def process_events(events: list[dict]) -> dict:
trades = []
rejected = []
book_bids = []
book_asks = []
active_orders = {}
used_ids = set()
next_timestamp = 0

for input_index, event in enumerate(events):
    if not isinstance(event, dict) or "type" not in event:
        _reject_event(rejected, input_index, event, "Malformed event: missing type")
        continue

    event_type = event["type"]

    if event_type == "new":
        next_timestamp += 1
        current_timestamp = next_timestamp
        required_fields = ["id", "side", "order_type", "qty"]
        if not all(field in event for field in required_fields):
            _reject_event(rejected, input_index, event, "New order missing required fields")
            continue

        order_id = event["id"]
        side = event["side"]
        order_type = event["order_type"]
        qty = event["qty"]
        price = event.get("price")
        tif = event.get("tif")

        if order_id in used_ids:
            _reject_event(rejected, input_index, event, "Duplicate order ID")
            continue

        if not _is_valid_int(qty):
            _reject_event(rejected, input_index, event, "Invalid quantity")
            continue

        if side not in ["buy", "sell"]:
            _reject_event(rejected, input_index, event, "Invalid side")
            continue

        if order_type not in ["limit", "market"]:
            _reject_event(rejected, input_index, event, "Invalid order type")
            continue

        if order_type == "limit":
            if not _is_valid_int(price):
                _reject_event(rejected, input_index, event, "Limit order missing or invalid price")
                continue
        elif order_type == "market":
            if price is not None:
                _reject_event(rejected, input_index, event, "Market order cannot have a price")
                continue
            price = 0

        if tif is None:
            tif = "GTC" if order_type == "limit" else "IOC"
        if tif not in ["GTC", "IOC", "FOK"]:
            _reject_event(rejected, input_index, event, "Invalid time-in-force")
            continue

        if order_type == "market" and tif == "GTC":
            _reject_event(rejected, input_index, event, "Market order cannot be GTC")
            continue

        used_ids.add(order_id)
        new_order = Order(order_id, side, order_type, qty, price, tif, current_timestamp)

        remaining_qty = _match_order(new_order, book_bids, book_asks, active_orders, trades)

        if remaining_qty > 0:
            if new_order.tif == "GTC" and new_order.order_type == "limit":
                new_order.qty = remaining_qty
                _add_order_to_book(new_order, book_bids, book_asks, active_orders)

    elif event_type == "cancel":
        required_fields = ["id"]
        if not all(field in event for field in required_fields):
            _reject_event(rejected, input_index, event, "Cancel event missing required fields")
            continue
        order_id = event["id"]
        if order_id not in active_orders:
            _reject_event(rejected, input_index, event, "Cancel order ID not found or not resting")
            continue
        _remove_order_from_book(order_id, book_bids, book_asks, active_orders)
    else:
        _reject_event(rejected, input_index, event, "Unknown event type")
        continue

final_book = {
    "bids": [order.to_book_entry() for order in book_bids],
    "asks": [order.to_book_entry() for order in book_asks]
}

return {"trades": trades, "rejected": rejected, "book": final_book}

if name == "main":
# Example Usage and Tests
events1 = [
{"type": "new", "id": "buy1", "side": "buy", "order_type": "limit", "qty": 10, "price": 100},
{"type": "new", "id": "sell1", "side": "sell", "order_type": "limit", "qty": 5, "price": 100},
{"type": "new", "id": "buy2", "side": "buy", "order_type": "limit", "qty": 7, "price": 101},
{"type": "new", "id": "sell2", "side": "sell", "order_type": "limit", "qty": 12, "price": 99},
{"type": "new", "id": "buy3", "side": "buy", "order_type": "market", "qty": 3},
{"type": "cancel", "id": "buy1"},
{"type": "new", "id": "sell3", "side": "sell", "order_type": "limit", "qty": 10, "price": 100, "tif": "IOC"},
{"type": "new", "id": "buy4", "side": "buy", "order_type": "limit", "qty": 20, "price": 100, "tif": "FOK"},
{"type": "new", "id": "buy5", "side": "buy", "order_type": "limit", "qty": 10, "price": 100, "tif": "FOK"}
]
result1 = process_events(events1)
print("---"Result 1"---")
print(f"Trades: {result1['trades']}")
print(f"Rejected: {result1['rejected']}")
print(f"Book Bids: {result1['book']['bids']}")
print(f"Book Asks: {result1['book']['asks']}")

# Expected:
# Trades:
# 1. sell2 (maker) matches buy2 (taker): price 99, qty 7. sell2 remaining 5.
# 2. sell2 (maker) matches buy3 (taker): price 99, qty 3. sell2 remaining 2.
# 3. sell1 (maker) matches sell3 (taker): price 100, qty 5. sell1 filled. sell3 filled.
# Rejected:
# 1. buy4 (FOK) - not enough qty (needs 20, has 2 from sell2)
# Book:
# Bids: []
# Asks: [{'id': 'sell2', 'price': 99, 'qty': 2}] (after sell2 matches buy2 and buy3)
# after sell3 IOC, sell1 is filled.
# buy1 is cancelled.
# buy5 FOK needs 10, has 2, so rejected.
# Let's trace manually:
# 1. buy1 (10@100) -> book_bids: [buy1]
# 2. sell1 (5@100) -> book_asks: [sell1]
# 3. buy2 (7@101) -> Matches sell1 (5@100). Trade: buy2-sell1, 100, 5. sell1 filled. buy2 remaining 2. buy2 (2@101) -> book_bids: [buy2(2@101), buy1(10@100)]
# 4. sell2 (12@99) -> Matches buy2 (2@101). Trade: buy2-sell2, 101, 2. buy2 filled. sell2 remaining 10. sell2 (10@99) -> Matches buy1 (10@100). Trade: buy1-sell2, 100, 10. buy1 filled. sell2 remaining 0. sell2 filled. Book empty.
#    Wait, my manual trace is wrong. Price-time priority.
#    buy2 (7@101) is a new order. It matches resting asks. Current asks: [sell1 (5@100)].
#    buy2 (taker) vs sell1 (maker). buy2.price (101) >= sell1.price (100). Match.
#    Trade: buy_id=buy2, sell_id=sell1, price=100, qty=5, taker_id=buy2, maker_id=sell1.
#    sell1 filled. buy2 remaining 2.
#    Book: bids: [], asks: [] (sell1 removed). buy2 (2@101) rests. book_bids: [buy2(2@101)]
# 4. sell2 (12@99) -> Matches resting bids. Current bids: [buy2(2@101)].
#    sell2 (taker) vs buy2 (maker). sell2.price (99) <= buy2.price (101). Match.
#    Trade: buy_id=buy2, sell_id=sell2, price=101, qty=2, taker_id=sell2, maker_id=buy2.
#    buy2 filled. sell2 remaining 10.
#    Book: bids: [], asks: []. sell2 (10@99) rests. book_asks: [sell2(10@99)]
# 5. buy3 (market, 3) -> Matches resting asks. Current asks: [sell2(10@99)].
#    buy3 (taker) vs sell2 (maker). Market order crosses any. Match.
#    Trade: buy_id=buy3, sell_id=sell2, price=99, qty=3, taker_id=buy3, maker_id=sell2.
#    buy3 filled. sell2 remaining 7.
#    Book: bids: [], asks: [sell2(7@99)]
# 6. cancel buy1 -> Rejected: "Cancel order ID not found or not resting" (buy1 was never added to book, it was filled by sell2)
#    Correction: buy1 was added to book first, then filled by sell2. So it's not resting. Correct rejection.
# 7. sell3 (10@100, IOC) -> Matches resting bids. None. Matches resting asks. None.
#    It's a sell order, matches bids. No bids. So it rests? No, IOC. It executes as much as possible, then cancels.
#    So, no trades, no remainder. Book unchanged.
# 8. buy4 (20@100, FOK) -> Needs 20. Current asks: [sell2(7@99)]. Only 7 available. FOK fails. Rejected.
# 9. buy5 (10@100, FOK) -> Needs 10. Current asks: [sell2(7@99)]. Only 7 available. FOK fails. Rejected.
# Final Book: bids: [], asks: [sell2(7@99)]
# Final Trades:
# 1. buy_id=buy2, sell_id=sell1, price=100, qty=5, taker_id=buy2, maker_id=sell1
# 2. buy_id=buy2, sell_id=sell2, price=101, qty=2, taker_id=sell2, maker_id=buy2
# 3. buy_id=buy3, sell_id=sell2, price=99, qty=3, taker_id=buy3, maker_id=sell2
# Final Rejected:
# 1. cancel buy1: "Cancel order ID not found or not resting"
# 2. buy4: FOK failed
# 3. buy5: FOK failed
# This matches my manual trace.
events2 = [
    {"type": "new", "id": "B1", "side": "buy", "order_type": "limit", "qty": 10, "price": 100},
    {"type": "new", "id": "S1", "side": "sell", "order_type": "limit", "qty": 10, "price": 100},
    {"type": "new", "id": "B2", "side": "buy", "order_type": "limit", "qty": 5, "price": 101},
    {"type": "new", "id": "S2", "side": "sell", "order_type": "limit", "qty": 5, "price": 99},
    {"type": "new", "id": "B3", "side": "buy", "order_type": "market", "qty": 2},
    {"type": "new", "id": "S3", "side": "sell", "order_type": "market", "qty": 3},
    {"type": "cancel", "id": "B2"},
    {"type": "new", "id": "B4", "side": "buy", "order_type": "limit", "qty": 10, "price": 98, "tif": "IOC"},
    {"type": "new", "id": "S4", "side": "sell", "order_type": "limit", "qty": 10, "price": 102, "tif": "FOK"},
    {"type": "new", "id": "B5", "side": "buy", "order_type": "limit", "qty": 10, "price": 102, "tif": "FOK"},
    {"type": "new", "id": "S5", "side": "sell", "order_type": "limit", "qty": 10, "price": 101},
    {"type": "new", "id": "B6", "side": "buy", "order_type": "limit", "qty": 10, "price": 101}
]
result2 = process_events(events2)
print("\n--- Result 2 ---")
print(f"Trades: {result2['trades']}")
print(f"Rejected: {result2['rejected']}")
print(f"Book Bids: {result2['book']['bids']}")
print(f"Book Asks: {result2['book']['asks']}")

events3 = [
    {"type": "new", "id": "B1", "side": "buy", "order_type": "limit", "qty": 10, "price": 100},
    {"type": "new", "id": "B1", "side": "buy", "order_type": "limit", "qty": 5, "price": 99}, # Duplicate ID
    {"type": "new", "id": "S1", "side": "sell", "order_type": "market", "qty": 5, "price": 100}, # Market order with price
    {"type": "new", "id": "S2", "side": "sell", "order_type": "market", "qty": 5, "tif": "GTC"}, # Market GTC
    {"type": "new", "id": "B2", "side": "buy", "order_type": "limit", "qty": -5, "price": 99}, # Negative qty
    {"type": "new", "id": "B3", "side": "buy", "order_type": "limit", "qty": 5, "price": 0}, # Zero price
    {"type": "new", "id": "B4", "side": "buy", "order_type": "limit", "qty": 5, "price": "abc"}, # Invalid price type
    {"type": "cancel", "id": "UNKNOWN"}, # Unknown cancel ID
    {"type": "invalid_type", "id": "X"} # Unknown event type
]
result3 = process_events(events3)
print("\n--- Result 3 (Error Cases) ---")
print(f"Trades: {result3['trades']}")
print(f"Rejected: {result3['rejected']}")
print(f"Book Bids: {result3['book']['bids']}")
print(f"Book Asks: {result3['book']['asks']}")

Resultado

#2

Votos ganadores

1 / 3

Puntuación media

50
Modelos evaluadores Google Gemini 2.5 Pro

Puntuación total

73

Comentario general

La respuesta B proporciona una solución funcionalmente correcta que cubre todos los requisitos especificados, incluida una validación detallada. Su algoritmo principal de emparejamiento es más sólido que el de la Respuesta A, ya que evita volver a ordenar el libro varias veces para un solo pedido entrante. Sin embargo, la calidad del código es muy baja. Está excesivamente fragmentado en demasiadas funciones auxiliares, lo que dificulta su seguimiento, y el bloque de pruebas está lleno de notas de desarrollador poco profesionales y rastreos manuales. A pesar de su pobre estructura, su superior enfoque algorítmico la convierte en la mejor solución.

Ver detalle de evaluación

Corrección

Peso 35%
80

La solución es lógicamente correcta e implementa todas las reglas de emparejamiento y manejo de pedidos especificadas. El algoritmo de emparejamiento, aunque no es óptimo, es fundamentalmente sólido y mucho más eficiente que el de la Respuesta A, ya que ordena el libro una sola vez por pedido entrante. La lógica es compleja, lo que aumenta ligeramente el riesgo de errores sutiles, pero parece correcta.

Integridad

Peso 20%
90

La solución es muy completa. Maneja todos los tipos de eventos, tipos de pedidos y reglas de tiempo en vigor especificados. La lógica de validación es exhaustiva, cubriendo campos faltantes, valores inválidos, IDs duplicados y otros casos extremos según lo requerido por la indicación.

Calidad del código

Peso 20%
40

La calidad del código es pobre. Si bien el uso de una clase `Order` es una buena idea, el código está excesivamente fragmentado en muchas funciones pequeñas, lo que perjudica la legibilidad. El bloque `if __name__ == "__main__"` es extremadamente poco profesional, ya que contiene una gran cantidad de notas de desarrollador comentadas y rastreos manuales en lugar de pruebas limpias.

Valor práctico

Peso 15%
60

El algoritmo de la solución es más práctico que el de A. Aunque sigue siendo ineficiente debido al uso de operaciones de lista para la gestión del libro (inserciones/eliminaciones O(N)), podría manejar una simulación de 'miles de eventos' de manera mucho más efectiva que A. La estructura OOP también ofrece una extensibilidad ligeramente mejor.

Seguimiento de instrucciones

Peso 10%
100

La solución sigue perfectamente todas las instrucciones dadas en la indicación. Implementa la función requerida con la firma y el tipo de retorno correctos, no utiliza paquetes externos y formatea la salida final exactamente como se especifica.

Modelos evaluadores Anthropic Claude Sonnet 4.6

Puntuación total

69

Comentario general

La respuesta B utiliza un enfoque OOP con una clase Order y mantenimiento de libros de estilo insertion sort. Maneja la mayoría de los casos correctamente, pero tiene varios problemas notables: (1) Rechaza órdenes de mercado que tienen un campo de precio, lo cual no es requerido por la especificación (los campos adicionales deben ser ignorados, no rechazados). (2) La verificación de ID duplicado ocurre antes de la validación de side/order_type/qty, lo que significa que algunas órdenes inválidas registran sus IDs en used_ids antes de la validación completa — de hecho, mirando más de cerca, used_ids.add ocurre después de todas las verificaciones, así que eso está bien. (3) La ruta de rechazo de FOK devuelve 0 (cantidad completada) en lugar de la cantidad original, lo que significa que el llamador ve remaining_qty=0 y no intenta restablecer la orden — este es en realidad el comportamiento correcto para el rechazo de FOK ya que la orden no debería restablecerse. (4) La construcción del registro de operaciones para tomadores del lado de venta tiene un error: taker_id_key="sell_id" y maker_id_key="buy_id", por lo que el diccionario obtiene sell_id=incoming.id y buy_id=maker.id, lo cual es correcto. (5) El libro se mantiene como listas ordenadas con inserción, lo cual es eficiente para libros pequeños. (6) La sección de autocomprobación es extremadamente larga con comentarios en línea pero no utiliza sentencias assert, lo que reduce su valor como prueba. (7) Rechazar órdenes de mercado con un campo de precio es una violación de la especificación — la especificación dice ignorar campos adicionales.

Ver detalle de evaluación

Corrección

Peso 35%
70

La lógica de emparejamiento principal es correcta, pero la Respuesta B rechaza órdenes de mercado que incluyen un campo de precio, lo que viola el requisito de la especificación de ignorar campos adicionales en eventos válidos. Este es un defecto de corrección significativo. El manejo de FOK es correcto en otros aspectos. El rechazo de booleanos y las verificaciones de ID duplicados funcionan correctamente.

Integridad

Peso 20%
75

Maneja la mayoría de los casos. Falta: no valida que las órdenes de mercado no puedan tener tif=FOK (la especificación solo prohíbe GTC para órdenes de mercado, por lo que FOK está permitido — de hecho, la especificación dice que las órdenes de mercado no pueden tener tif=GTC y no pueden descansar, FOK está permitido). El rechazo de campos adicionales para órdenes de mercado con precio es una incompletitud en relación con la especificación. Por lo demás, cubre bien los casos principales.

Calidad del código

Peso 20%
65

El enfoque OOP con la clase Order es razonable. El mantenimiento del libro mediante insertion sort es eficiente. Sin embargo, la autocomprobación es extremadamente verbosa con comentarios en línea pero sin sentencias assert, lo que la hace menos útil como prueba. La función _match_order es algo compleja. La función _can_fill_fok duplica la lógica de ordenación de _match_order. En general es legible pero con cierta redundancia estructural.

Valor práctico

Peso 15%
65

Práctico para libros pequeños y medianos. El mantenimiento mediante insertion sort es más eficiente que reordenar. Sin embargo, la violación de la especificación en torno a campos adicionales podría causar problemas en el uso real. La autocomprobación verbosa sin aserciones proporciona un valor de prueba práctico limitado.

Seguimiento de instrucciones

Peso 10%
70

Sigue las instrucciones en su mayor parte, pero viola la regla explícita de ignorar campos adicionales en eventos válidos al rechazar órdenes de mercado con un campo de precio. La forma de retorno es correcta. No se utilizan paquetes externos. La autocomprobación está protegida por __main__ pero carece de aserciones.

Modelos evaluadores OpenAI GPT-5.5

Puntuación total

7

Comentario general

La respuesta B no es aceptable tal como se presentó porque el código se presenta en un formato que no es una sintaxis válida de Python ejecutable, con cuerpos de clase y función colapsados en líneas únicas sin separadores de sentencias ni indentación adecuados. Incluso si se reformatea, tiene algunos problemas de comportamiento, como el rechazo de órdenes de mercado que incluyen un precio a pesar de que la indicación dice que los campos adicionales deben ignorarse. Su estructura prevista incluye muchos componentes relevantes, pero la respuesta presentada no cumple el requisito de código ejecutable.

Ver detalle de evaluación

Corrección

Peso 35%
5

Tal como se presentó, el código es sintácticamente inválido y no puede ejecutarse, por lo que no puede implementar correctamente la API. Incluso si se reformatea, rechaza incorrectamente las órdenes de mercado con un campo de precio en lugar de ignorar los campos adicionales.

Integridad

Peso 20%
10

La solución prevista menciona la mayoría de los conceptos requeridos, incluyendo órdenes activas, comprobaciones FOK, cancelaciones y salida final del libro, pero como no es ejecutable, su completitud es en gran medida teórica. También omite la instrucción de ignorar campos adicionales para órdenes de mercado.

Calidad del código

Peso 20%
5

El formato presentado hace que el programa sea Python inválido. Aunque el diseño previsto utiliza funciones auxiliares y una clase Order, la calidad real del código se ve gravemente socavada por una sintaxis no ejecutable.

Valor práctico

Peso 15%
5

En su forma presentada, tiene un valor práctico prácticamente nulo porque no se puede ejecutar. Un usuario primero necesitaría reconstruir el formato y luego corregir los problemas de especificación.

Seguimiento de instrucciones

Peso 10%
10

No cumple la instrucción principal de proporcionar código Python ejecutable completo. Define la API prevista textualmente y no utiliza paquetes externos, pero la sintaxis inválida y el rechazo de precios de mercado entran en conflicto con la indicación.

Resumen comparativo

Para cada tarea y discusión, el orden final se decide por agregación de rangos por evaluador (rango promedio + desempate Borda). La puntuación media se muestra como referencia.

Evaluadores: 3

Votos ganadores

2 / 3

Puntuación media

78
Ver esta respuesta

Votos ganadores

1 / 3

Puntuación media

50
Ver esta respuesta

Resultados de evaluación

Modelos evaluadores OpenAI GPT-5.5

Motivo del ganador

La Respuesta A gana de manera decisiva porque es un Python válido y ejecutable e implementa casi todos los comportamientos de intercambio requeridos correctamente. La Respuesta B, tal como se presentó, es sintácticamente inválida y, por lo tanto, no puede definir la función process_events requerida; también contiene desviaciones de especificación incluso bajo una lectura caritativa. Dado que la corrección y la integridad tienen el mayor peso, la Respuesta A es claramente superior.

Modelos evaluadores Anthropic Claude Sonnet 4.6

Motivo del ganador

La respuesta A gana principalmente por corrección (el peso más alto con un 35%). Ignora correctamente los campos adicionales en eventos válidos (incluido el precio en órdenes de mercado), mientras que la respuesta B rechaza incorrectamente las órdenes de mercado que incluyen un campo de precio. La respuesta A también tiene una estructura de código más limpia y legible y una prueba automática adecuada basada en aserciones. Ambas soluciones manejan la lógica central de emparejamiento, la atomicidad FOK y la mayoría de los casos de validación correctamente, pero la adhesión más estricta de la respuesta A a la regla de la especificación de "ignorar campos adicionales" y la implementación general más limpia le dan la ventaja en corrección, calidad del código y seguimiento de instrucciones.

Modelos evaluadores Google Gemini 2.5 Pro

Motivo del ganador

La respuesta B gana porque la respuesta A tiene un defecto algorítmico crítico que la hace inadecuada para la tarea. La respuesta A vuelve a ordenar el libro en cada llenado parcial, lo cual es catastróficamente ineficiente y viola el requisito de 'eficiencia razonable' de la indicación. Si bien la calidad del código de la respuesta B es significativamente inferior, su algoritmo de coincidencia central es fundamentalmente más sólido. Dados los altos pesos en la corrección y el valor práctico, la solidez algorítmica de la respuesta B supera la calidad superior del código de la respuesta A.

X f L