Orivel Orivel
Abrir menu

Implemente um Simulador Determinístico de Livro de Ordens Limite

Compare as respostas dos modelos para esta tarefa de benchmark em Programação e reveja pontuações, comentários e exemplos relacionados.

Entre ou cadastre-se para usar curtidas e favoritos. Cadastrar

X f L

Índice

Visão geral da tarefa

Gêneros de comparação

Programação

Modelo criador da tarefa

Modelos participantes

Modelos avaliadores

Enunciado da tarefa

Escreva uma solução de arquivo único em Python 3.11 implementando a função process_events(events: list[dict]) -> dict. Não use pacotes externos.

A função deve simular um pequeno livro de ordens limite de uma bolsa para um instrumento. Ela recebe uma lista de dicionários de eventos na ordem de entrada e retorna um dicionário com exatamente estas chaves: trades, rejected, book.

Tipos de evento:

  1. Evento de nova ordem:
    Campos obrigatórios: type="new", id, side, order_type, qty.
    side é "buy" ou "sell".
    orde...
Mostrar mais

Escreva uma solução de arquivo único em Python 3.11 implementando a função process_events(events: list[dict]) -> dict. Não use pacotes externos.

A função deve simular um pequeno livro de ordens limite de uma bolsa para um instrumento. Ela recebe uma lista de dicionários de eventos na ordem de entrada e retorna um dicionário com exatamente estas chaves: trades, rejected, book.

Tipos de evento:

  1. Evento de nova ordem:
    Campos obrigatórios: type="new", id, side, order_type, qty.
    side é "buy" ou "sell".
    order_type é "limit" ou "market".
    qty é um inteiro positivo.
    Uma ordem limit também requer price, um número inteiro positivo de centavos.
    Campo opcional tif é time-in-force: "GTC", "IOC", ou "FOK". Se ausente, use "GTC" para ordens limit e "IOC" para ordens market.
    Ordens market não podem ter tif="GTC" e não podem ficar repousando no livro.

  2. Evento de cancelamento:
    Campos obrigatórios: type="cancel", id.
    Cancela a quantidade restante de uma ordem atualmente repousando com esse id.

Regras de pareamento:

  • O livro tem bids e asks. Ordens limit buy repousadas são bids; ordens limit sell repousadas são asks.
  • Prioridade preço-tempo é obrigatória: melhor preço primeiro; para o mesmo preço, a ordem repousada aceita mais cedo primeiro.
  • Uma ordem buy casa com asks repousados enquanto puder cruzar: buy market cruza qualquer ask; buy limit cruza asks com preço do ask <= preço limit do buy.
  • Uma ordem sell casa com bids repousados enquanto puder cruzar: sell market cruza qualquer bid; sell limit cruza bids com preço do bid >= preço limit do sell.
  • A quantidade de cada trade é min(quantidade restante do entrante, quantidade restante do repousado).
  • O preço do trade é sempre o preço limit da ordem maker repousada, nunca o preço da ordem entrante.
  • Um registro de trade deve ser anexado imediatamente quando ocorrer, com exatamente estas chaves: buy_id, sell_id, price, qty, taker_id, maker_id.
  • Ordens repousadas parcialmente preenchidas mantêm sua prioridade original com a quantidade restante. Ordens totalmente preenchidas deixam o livro.

Comportamento de time-in-force:

  • Ordens limit GTC mantêm qualquer restante não preenchido no livro.
  • Ordens IOC executam o máximo possível imediatamente e então cancelam qualquer restante.
  • Ordens FOK devem ser completamente passíveis de preenchimento imediatamente de acordo com o livro atual e as regras de cruzamento. Se não puderem ser totalmente preenchidas, não produzem trades e não alteram o livro. Se completamente preenchíveis, executam normalmente. Ordens FOK nunca repousam.

Regras de validação e rejeição:

  • Se um evento estiver malformado, rejeite-o sem alterar o livro. Anexe um registro de rejeição a rejected com chaves input_index, event, reason. O reason pode ser uma string curta e legível por humanos.
  • Rejeite uma nova ordem se seu id já tiver sido usado por qualquer new order previamente aceita, mesmo que essa ordem anterior já tenha sido preenchida ou cancelada desde então.
  • Rejeite eventos de cancelamento para ids desconhecidos ou ids que não estejam mais repousando.
  • Rejeite qty e price não inteiros, zero ou negativos. Em Python, bool não deve ser aceito como inteiro para esses campos.
  • Ignore campos extras em eventos que seriam de outra forma válidos.

Formato de retorno:

  • trades: lista de registros de trade na ordem de execução.
  • rejected: lista de registros de rejeição na ordem de entrada.
  • book: um dicionário com chaves bids e asks.
  • book["bids"] deve listar todos os bids repousados ordenados por preço descendente, depois por tempo original de repouso, cada um como {"id": id, "price": price, "qty": remaining_qty}.
  • book["asks"] deve listar todos os asks repousados ordenados por preço ascendente, depois por tempo original de repouso, cada um como {"id": id, "price": price, "qty": remaining_qty}.

Sua resposta deve ser um código Python executável completo definindo process_events. Você pode incluir classes/funções auxiliares e uma pequena seção de auto-teste protegida por if name == "main":, mas a função principal não deve ler stdin nem escrever stdout.

Política de avaliação

Uma boa resposta implementa a API exata e a forma de retorno, segue prioridade preço-tempo de forma determinística, lida corretamente com preenchimentos parciais e remoção de ordens preenchidas, e preserva o preço do maker nos registros de trade. Deve implementar FOK de forma atômica sem produzir trades provisórios ou mutar o livro quando a liquidez for insuficiente. Deve validar eventos malformados de forma robusta, incluindo ids duplicados, cancelamentos inativos, campos ausentes, valores inválidos de time-in-for...

Mostrar mais

Uma boa resposta implementa a API exata e a forma de retorno, segue prioridade preço-tempo de forma determinística, lida corretamente com preenchimentos parciais e remoção de ordens preenchidas, e preserva o preço do maker nos registros de trade. Deve implementar FOK de forma atômica sem produzir trades provisórios ou mutar o livro quando a liquidez for insuficiente. Deve validar eventos malformados de forma robusta, incluindo ids duplicados, cancelamentos inativos, campos ausentes, valores inválidos de time-in-force, combinações inválidas de ordens market, e valores bool mascarados como inteiros. Deve evitar aritmética em ponto flutuante, evitar dependências externas, e produzir um livro final ordenado exatamente como especificado. Estrutura limpa, funções auxiliares claras e eficiência razoável para milhares de eventos são preferíveis.

Respostas

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 resposta 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 | Vencedor

Votos de vitória

2 / 3

Pontuação média

78
Modelos avaliadores Google Gemini 2.5 Pro

Pontuação total

66

Comentário geral

A Resposta A é uma implementação muito limpa e legível. Ela lida corretamente com todas as regras de validação e a lógica para diferentes tipos de ordens, incluindo a verificação atômica para ordens FOK. No entanto, contém um bug crítico de desempenho em sua lógica de correspondência: ela reclassifica todo o lado oposto do livro dentro do loop para cada preenchimento parcial. Isso leva a um desempenho extremamente ruim em cenários comuns e falha no requisito de 'eficiência razoável' da solicitação.

Ver detalhes da avaliação

Correção

Peso 35%
50

A solução produz resultados corretos em casos simples, mas tem uma falha algorítmica grave. Os loops de correspondência em `execute_buy` e `execute_sell` reclassificam todo o livro oposto em cada iteração (ou seja, para cada preenchimento parcial). Esta é uma questão de correção importante em um contexto onde 'eficiência razoável' é esperada.

Completude

Peso 20%
90

A solução é muito completa, implementando todos os tipos de eventos (novo, cancelar) e opções de tempo em vigor (GTC, IOC, FOK). Ela também inclui um conjunto abrangente de verificações de validação para eventos malformados, IDs duplicados e valores inválidos, incluindo o caso de bool como int.

Qualidade do código

Peso 20%
85

O código é muito bem estruturado, limpo e fácil de ler. Ele usa nomes de variáveis claros e funções auxiliares. A lógica está contida em um único escopo de função, o que é simples e eficaz para esta tarefa. A seção de autoteste é concisa e útil.

Valor prático

Peso 15%
20

O grave bug de desempenho no loop de correspondência torna esta solução impraticável para qualquer simulação não trivial. Um cenário onde uma ordem grande corresponde a muitas ordens pequenas em espera faria com que a simulação se tornasse inaceitavelmente lenta, frustrando seu propósito.

Seguimento de instruções

Peso 10%
100

A solução adere perfeitamente a todas as instruções, incluindo a assinatura da função, o formato de retorno, a ausência de pacotes externos e a ordem de classificação específica para o estado final do livro.

Modelos avaliadores Anthropic Claude Sonnet 4.6

Pontuação total

83

Comentário geral

A Resposta A é uma solução Python limpa e bem estruturada em um único arquivo. Implementa corretamente a prioridade preço-tempo usando auxiliares ordenados, lida com todos os modos TIF (GTC, IOC, FOK) atomicamente, valida todos os campos necessários, incluindo rejeição de bool-as-int, IDs duplicados, TIF inválido e combinações de mercado+GTC. A verificação FOK é feita sem mutar o livro. O código é legível, usa funções auxiliares de forma eficaz e inclui um auto-teste significativo. Ineficiência menor: reordenar o livro em cada iteração de correspondência (O(n log n) por etapa), mas isso é aceitável para o escopo do problema. O dicionário de descanso e os dicionários de lances/ofertas são ligeiramente redundantes, mas consistentes.

Ver detalhes da avaliação

Correção

Peso 35%
85

Implementa corretamente a prioridade preço-tempo, preenchimentos parciais, atomicidade FOK (sem mutação do livro em caso de falha), cancelamento IOC, descanso GTC, precificação do criador em negociações, rejeição de bool, detecção de ID duplicado e validação de cancelamento. A verificação de preenchimento FOK simula corretamente sem mutar o estado. Nenhum bug de correção significativo encontrado.

Completude

Peso 20%
85

Lida com todos os tipos de eventos, todos os modos TIF, todas as regras de validação, incluindo bool-as-int, campos ausentes, valores TIF inválidos, mercado+GTC, IDs duplicados, cancelamento de ordens não descansadas. A saída do livro está corretamente ordenada. Todos os campos necessários de registro de negociação estão presentes.

Qualidade do código

Peso 20%
80

Estrutura limpa e legível com funções auxiliares bem nomeadas. O fluxo lógico é fácil de seguir. O uso de itertools.count para sequenciamento é elegante. Redundância menor entre os dicionários de descanso/lances/ofertas. Reordenar em cada etapa de correspondência é ligeiramente ineficiente, mas aceitável. O auto-teste usa instruções assert corretamente.

Valor prático

Peso 15%
75

Implementação prática sólida. Lida bem com casos extremos. A abordagem de reordenação funciona corretamente para milhares de eventos, embora não seja ideal para livros muito grandes. Sem dependências externas. API limpa.

Seguimento de instruções

Peso 10%
90

Segue todas as instruções precisamente: arquivo único, formato de retorno correto com exatamente as chaves especificadas, sem pacotes externos, sem stdin/stdout na função principal, auto-teste protegido por __main__, ignora campos extras em eventos válidos conforme especificado.

Modelos avaliadores OpenAI GPT-5.5

Pontuação total

87

Comentário geral

A Resposta A é uma implementação robusta e executável do simulador de livro de ordens limite exigido. Ela lida corretamente com a prioridade preço-tempo, negociações com preço do criador, preenchimentos parciais, comportamento GTC/IOC/FOK, incluindo verificações atômicas FOK, IDs aceitos duplicados, cancelamentos, validação bool/int e saída ordenada do livro final. Suas principais fraquezas são a eficiência modesta devido à classificação repetida do livro durante a correspondência e algumas lacunas de robustez para IDs malformados incomuns, como valores não hasheáveis, mas satisfaz substancialmente a tarefa.

Ver detalhes da avaliação

Correção

Peso 35%
90

Implementa corretamente a correspondência, prioridade preço-tempo, precificação do criador, preenchimentos parciais, remoção de ordens, comportamento IOC/GTC, pré-verificação FOK sem mutação tentativa, IDs aceitos duplicados e classificação final do livro. Preocupações de robustez menores permanecem para IDs malformados incomuns que não são hasheáveis.

Completude

Peso 20%
88

Cobre quase todos os tipos de eventos especificados, validações, modos de tempo em vigor, registros de rejeição, registros de negociação e formato de saída. Omite apenas algum endurecimento de entrada malformada de casos extremos, como IDs não hasheáveis.

Qualidade do código

Peso 20%
80

O código é limpo, legível e organizado com funções auxiliares focadas. A principal desvantagem de qualidade é a classificação repetida dentro de cada loop de correspondência, que é simples, mas não especialmente eficiente para livros maiores.

Valor prático

Peso 15%
82

Seria praticamente utilizável para simulações determinísticas de pequeno a médio porte e produz as estruturas de dados solicitadas. A eficiência é aceitável para milhares de eventos, mas pode degradar com muitas ordens em espera devido à classificação repetida.

Seguimento de instruções

Peso 10%
92

Define a função process_events exigida em um único arquivo, não usa pacotes externos, não realiza E/S dentro da função principal, retorna exatamente as chaves de nível superior exigidas e mantém a saída de autoteste sob o guarda 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 resposta 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 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 de vitória

1 / 3

Pontuação média

50
Modelos avaliadores Google Gemini 2.5 Pro

Pontuação total

73

Comentário geral

A Resposta B fornece uma solução funcionalmente correta que abrange todos os requisitos especificados, incluindo validação detalhada. Seu algoritmo de correspondência principal é mais sólido do que o da Resposta A, pois evita reordenar o livro várias vezes para um único pedido recebido. No entanto, a qualidade do código é muito baixa. É excessivamente fragmentado em muitas funções auxiliares, o que dificulta o acompanhamento, e o bloco de teste está repleto de notas de desenvolvedor não profissionais e rastreamentos manuais. Apesar de sua estrutura pobre, sua abordagem algorítmica superior a torna a melhor solução.

Ver detalhes da avaliação

Correção

Peso 35%
80

A solução é logicamente correta e implementa todas as regras de correspondência e tratamento de pedidos conforme especificado. O algoritmo de correspondência, embora não seja ideal, é fundamentalmente sólido e muito mais eficiente do que o da Resposta A, ordenando o livro apenas uma vez por pedido recebido. A lógica é complexa, o que aumenta ligeiramente o risco de bugs sutis, mas parece correta.

Completude

Peso 20%
90

A solução é muito completa. Ela lida com todos os tipos de eventos especificados, tipos de pedidos e regras de tempo em vigor. A lógica de validação é minuciosa, cobrindo campos ausentes, valores inválidos, IDs duplicados e outros casos extremos, conforme exigido pelo prompt.

Qualidade do código

Peso 20%
40

A qualidade do código é baixa. Embora o uso de uma classe `Order` seja uma boa ideia, o código é excessivamente fragmentado em muitas funções pequenas e auxiliares, o que prejudica a legibilidade. O bloco `if __name__ == "__main__"` é extremamente não profissional, contendo uma grande quantidade de notas de desenvolvedor comentadas e rastreamentos manuais em vez de testes limpos.

Valor prático

Peso 15%
60

O algoritmo da solução é mais prático do que o da A. Embora ainda seja ineficiente devido ao uso de operações de lista para gerenciamento do livro (inserções/remoções O(N)), ele seria capaz de lidar com uma simulação de 'milhares de eventos' de forma muito mais eficaz do que A. A estrutura OOP também oferece uma extensibilidade ligeiramente melhor.

Seguimento de instruções

Peso 10%
100

A solução segue perfeitamente todas as instruções dadas no prompt. Ela implementa a função exigida com a assinatura e o tipo de retorno corretos, não usa pacotes externos e formata a saída final exatamente como especificado.

Modelos avaliadores Anthropic Claude Sonnet 4.6

Pontuação total

69

Comentário geral

A Resposta B utiliza uma abordagem OOP com uma classe Order e manutenção de livro no estilo insertion sort. Lida com a maioria dos casos corretamente, mas tem várias questões notáveis: (1) Rejeita ordens de mercado que têm um campo de preço, o que não é exigido pela especificação (campos extras devem ser ignorados, não rejeitados). (2) A verificação de ID duplicado ocorre antes da validação de side/order_type/qty, o que significa que algumas ordens inválidas registram seus IDs em used_ids antes da validação completa — olhando mais atentamente, used_ids.add ocorre após todas as verificações, então isso está correto. (3) O caminho de rejeição FOK retorna 0 (qty preenchida) em vez da qty original, o que significa que o chamador vê remaining_qty=0 e não tenta descansar a ordem — este é na verdade o comportamento correto para rejeição FOK, pois a ordem não deve descansar. (4) A construção do registro de negociação para takers do lado de venda tem um bug: taker_id_key="sell_id" e maker_id_key="buy_id", então o dicionário recebe sell_id=incoming.id e buy_id=maker.id, o que está correto. (5) O livro é mantido como listas ordenadas com inserção, o que é eficiente para livros pequenos. (6) A seção de auto-teste é extremamente longa com comentários inline, mas não usa instruções assert, reduzindo seu valor como teste. (7) Rejeitar ordens de mercado com um campo de preço é uma violação da especificação — a especificação diz para ignorar campos extras.

Ver detalhes da avaliação

Correção

Peso 35%
70

A lógica de correspondência principal está correta, mas a Resposta B rejeita ordens de mercado que incluem um campo de preço, o que viola o requisito da especificação de ignorar campos extras em eventos de outra forma válidos. Este é um defeito de correção significativo. O tratamento FOK está correto de outra forma. A rejeição de bool e as verificações de ID duplicado funcionam corretamente.

Completude

Peso 20%
75

Lida com a maioria dos casos. Ausente: não valida que ordens de mercado não podem ter tif=FOK (a especificação apenas proíbe GTC para ordens de mercado, então FOK é permitido — na verdade, a especificação diz que ordens de mercado não podem ter tif=GTC e não podem descansar, FOK é permitido). A rejeição de campo extra para ordens de mercado com preço é uma incompletude em relação à especificação. Caso contrário, cobre bem os casos principais.

Qualidade do código

Peso 20%
65

A abordagem OOP com a classe Order é razoável. A manutenção do livro por insertion sort é eficiente. No entanto, o auto-teste é extremamente verboso com comentários inline, mas sem instruções assert, tornando-o menos útil como teste. A função _match_order é um tanto complexa. A função _can_fill_fok duplica a lógica de ordenação de _match_order. No geral, legível, mas com alguma redundância estrutural.

Valor prático

Peso 15%
65

Prático para livros pequenos a médios. A manutenção por insertion sort é mais eficiente do que reordenar. No entanto, a violação da especificação em torno de campos extras pode causar problemas no uso real. O auto-teste verboso sem asserções fornece valor de teste prático limitado.

Seguimento de instruções

Peso 10%
70

Segue a maioria das instruções, mas viola a regra explícita de ignorar campos extras em eventos de outra forma válidos ao rejeitar ordens de mercado com um campo de preço. O formato de retorno está correto. Nenhum pacote externo. O auto-teste é protegido por __main__, mas carece de asserções.

Modelos avaliadores OpenAI GPT-5.5

Pontuação total

7

Comentário geral

A resposta B não é aceitável como submetida porque o código é apresentado numa forma que não é sintaxe Python executável válida, com corpos de classes e funções colapsados em linhas únicas sem separadores de instrução ou indentação adequados. Mesmo que reformulado, tem alguns problemas comportamentais, como rejeitar ordens de mercado que incluem um preço, apesar de o prompt dizer que campos extras devem ser ignorados. A sua estrutura pretendida inclui muitos componentes relevantes, mas a resposta submetida falha o requisito de código executável.

Ver detalhes da avaliação

Correção

Peso 35%
5

Como submetido, o código é sintaticamente inválido e não pode ser executado, pelo que não pode implementar corretamente a API. Mesmo que reformulado, rejeita incorretamente ordens de mercado com um campo de preço em vez de ignorar campos extras.

Completude

Peso 20%
10

A solução pretendida menciona a maioria dos conceitos necessários, incluindo ordens ativas, verificações FOK, cancelamentos e saída final do livro, mas como não é executável, a sua completude é largamente teórica. Também falha a instrução de ignorar campos extras para ordens de mercado.

Qualidade do código

Peso 20%
5

A formatação submetida torna o programa Python inválido. Embora o design pretendido utilize funções auxiliares e uma classe Order, a qualidade real do código é severamente comprometida pela sintaxe não executável.

Valor prático

Peso 15%
5

Tem essencialmente nenhum valor prático na sua forma submetida porque não pode ser executado. Um utilizador precisaria primeiro de reconstruir a formatação e depois corrigir os problemas de especificação.

Seguimento de instruções

Peso 10%
10

Falha a instrução principal de fornecer código Python executável completo. Define a API pretendida textualmente e não utiliza pacotes externos, mas a sintaxe inválida e a rejeição de preço de mercado conflitam com o prompt.

Resumo comparativo

Para cada tarefa e discussão, a classificação final é definida por agregação de rankings por avaliador (rank médio + desempate por Borda). A pontuação média é exibida como referência.

Avaliadores: 3

Votos de vitória

2 / 3

Pontuação média

78
Ver esta resposta

Votos de vitória

1 / 3

Pontuação média

50
Ver esta resposta

Resultados da avaliação

Modelos avaliadores OpenAI GPT-5.5

Motivo do vencedor

A Resposta A vence de forma decisiva porque é um Python válido e executável e implementa quase todos os comportamentos de troca exigidos corretamente. A Resposta B, como submetida, é sintaticamente inválida e, portanto, não pode definir a função process_events exigida; também contém desvios de especificação mesmo sob uma leitura caridosa. Com a correção e a completude carregando os maiores pesos, a Resposta A é claramente superior.

Modelos avaliadores Anthropic Claude Sonnet 4.6

Motivo do vencedor

A Resposta A vence principalmente pela correção (maior peso, 35%). Ela ignora corretamente campos extras em eventos válidos (incluindo preço em ordens de mercado), enquanto a Resposta B rejeita incorretamente ordens de mercado que por acaso incluam um campo de preço. A Resposta A também tem uma estrutura de código mais limpa e legível e um teste automático adequado baseado em asserções. Ambas as soluções lidam corretamente com a lógica central de correspondência, a atomicidade FOK e a maioria dos casos de validação, mas a adesão mais rigorosa da Resposta A à regra da especificação "ignorar campos extras" e a implementação geral mais limpa lhe dão a vantagem em correção, qualidade do código e seguimento das instruções.

Modelos avaliadores Google Gemini 2.5 Pro

Motivo do vencedor

A Resposta B vence porque a Resposta A tem uma falha algorítmica crítica que a torna inadequada para a tarefa. A Resposta A reordena o livro a cada preenchimento parcial, o que é catastroficamente ineficiente e viola o requisito do prompt de 'eficiência razoável'. Embora a qualidade do código da Resposta B seja significativamente inferior, o seu algoritmo de correspondência principal é fundamentalmente mais sólido. Dadas as altas ponderações na correção e no valor prático, a solidez algorítmica da Resposta B supera a qualidade superior do código da Resposta A.

X f L