Orivel Orivel
Open menu

Implement a Deterministic Limit Order Book Simulator

Compare model answers for this Coding benchmark and review scores, judging comments, and related examples.

Login or register to use likes and favorites. Register

X f L

Contents

Task Overview

Benchmark Genres

Coding

Task Creator Model

Answering Models

Judge Models

Task Prompt

Write a single-file Python 3.11 solution implementing the function process_events(events: list[dict]) -> dict. Do not use external packages.

The function must simulate a small exchange limit order book for one instrument. It receives a list of event dictionaries in input order and returns a dictionary with exactly these keys: trades, rejected, book.

Event types:

  1. New order event:
    Required fields: type="new", id, side, order_type, qty.
    side is "buy" or "sell".
    order_type is "limit" or "market".
    qty i...
Show more

Write a single-file Python 3.11 solution implementing the function process_events(events: list[dict]) -> dict. Do not use external packages.

The function must simulate a small exchange limit order book for one instrument. It receives a list of event dictionaries in input order and returns a dictionary with exactly these keys: trades, rejected, book.

Event types:

  1. New order event:
    Required fields: type="new", id, side, order_type, qty.
    side is "buy" or "sell".
    order_type is "limit" or "market".
    qty is a positive integer.
    A limit order also requires price, a positive integer number of cents.
    Optional field tif is time-in-force: "GTC", "IOC", or "FOK". If absent, use "GTC" for limit orders and "IOC" for market orders.
    Market orders may not have tif="GTC" and may not rest on the book.

  2. Cancel event:
    Required fields: type="cancel", id.
    It cancels the remaining quantity of a currently resting order with that id.

Matching rules:

  • The book has bids and asks. Resting buy limit orders are bids; resting sell limit orders are asks.
  • Price-time priority is mandatory: best price first; for the same price, earlier accepted resting order first.
  • A buy order matches resting asks while it can cross: market buy crosses any ask; limit buy crosses asks with ask price <= buy limit price.
  • A sell order matches resting bids while it can cross: market sell crosses any bid; limit sell crosses bids with bid price >= sell limit price.
  • Each trade quantity is min(incoming remaining quantity, resting remaining quantity).
  • Trade price is always the resting maker order's limit price, never the incoming order's price.
  • A trade record must be appended immediately when it happens with exactly these keys: buy_id, sell_id, price, qty, taker_id, maker_id.
  • Partially filled resting orders keep their original priority with the remaining quantity. Fully filled orders leave the book.

Time-in-force behavior:

  • GTC limit orders rest any unfilled remainder on the book.
  • IOC orders execute as much as possible immediately, then cancel any remainder.
  • FOK orders must be completely fillable immediately according to the current book and crossing rules. If not completely fillable, they produce no trades and do not change the book. If completely fillable, execute normally. FOK orders never rest.

Validation and rejection rules:

  • If an event is malformed, reject it without changing the book. Append a rejection record to rejected with keys input_index, event, reason. The reason may be a short human-readable string.
  • Reject a new order if its id is already used by any previously accepted new order, even if that earlier order has since filled or been canceled.
  • Reject cancel events for unknown ids or ids that are no longer resting.
  • Reject non-integer, zero, or negative qty and price values. In Python, bool must not be accepted as an integer for these fields.
  • Ignore extra fields on otherwise valid events.

Return format:

  • trades: list of trade records in execution order.
  • rejected: list of rejection records in input order.
  • book: a dictionary with keys bids and asks.
  • book["bids"] must list all resting bids sorted by descending price, then original resting time, each as {"id": id, "price": price, "qty": remaining_qty}.
  • book["asks"] must list all resting asks sorted by ascending price, then original resting time, each as {"id": id, "price": price, "qty": remaining_qty}.

Your answer should be complete executable Python code defining process_events. You may include helper classes/functions and a small self-test section guarded by if name == "main":, but the core function must not read from stdin or write to stdout.

Judging Policy

A strong answer implements the exact API and return shape, follows price-time priority deterministically, handles partial fills and removal of filled orders correctly, and preserves maker pricing in trade records. It should implement FOK atomically without producing tentative trades or mutating the book when liquidity is insufficient. It should validate malformed events robustly, including duplicate ids, inactive cancels, missing fields, invalid time-in-force values, invalid market-order combinations, and bool valu...

Show more

A strong answer implements the exact API and return shape, follows price-time priority deterministically, handles partial fills and removal of filled orders correctly, and preserves maker pricing in trade records. It should implement FOK atomically without producing tentative trades or mutating the book when liquidity is insufficient. It should validate malformed events robustly, including duplicate ids, inactive cancels, missing fields, invalid time-in-force values, invalid market-order combinations, and bool values masquerading as integers. It should avoid floating point arithmetic, avoid external dependencies, and produce a final book sorted exactly as specified. Clean structure, clear helper functions, and reasonable efficiency for thousands of events are preferred.

Answers

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...
Show Full Answer

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")

Result

#1 | Winner

Winning Votes

2 / 3

Average Score

78

Total Score

66

Overall Comments

Answer A is a very clean and readable implementation. It correctly handles all validation rules and the logic for different order types, including the atomic check for FOK orders. However, it contains a critical performance bug in its matching logic: it re-sorts the entire opposite side of the book inside the loop for each partial fill. This leads to extremely poor performance in common scenarios and fails the prompt's requirement for 'reasonable efficiency'.

View Score Details

Correctness

Weight 35%
50

The solution produces correct results on simple cases, but it has a severe algorithmic flaw. The matching loops in `execute_buy` and `execute_sell` re-sort the entire opposite book on each iteration (i.e., for each partial fill). This is a major correctness issue in a context where 'reasonable efficiency' is expected.

Completeness

Weight 20%
90

The solution is very complete, implementing all event types (new, cancel) and time-in-force options (GTC, IOC, FOK). It also includes a comprehensive set of validation checks for malformed events, duplicate IDs, and invalid values, including the bool-as-int case.

Code Quality

Weight 20%
85

The code is very well-structured, clean, and easy to read. It uses clear variable names and helper functions. The logic is contained within a single function scope, which is simple and effective for this task. The self-test section is concise and useful.

Practical Value

Weight 15%
20

The severe performance bug in the matching loop renders this solution impractical for any non-trivial simulation. A scenario where one large order matches many small resting orders would cause the simulation to become unacceptably slow, defeating its purpose.

Instruction Following

Weight 10%
100

The solution perfectly adheres to all instructions, including the function signature, return format, lack of external packages, and the specific sorting order for the final book state.

Total Score

83

Overall Comments

Answer A is a clean, well-structured single-file Python solution. It correctly implements price-time priority using sorted helpers, handles all TIF modes (GTC, IOC, FOK) atomically, validates all required fields including bool-as-int rejection, duplicate IDs, invalid TIF, and market+GTC combinations. The FOK check is done without mutating the book. The code is readable, uses helper functions effectively, and includes a meaningful self-test. Minor inefficiency: re-sorting the book on every match iteration (O(n log n) per step), but this is acceptable for the problem scope. The resting dict and bids/asks dicts are slightly redundant but consistent.

View Score Details

Correctness

Weight 35%
85

Correctly implements price-time priority, partial fills, FOK atomicity (no book mutation on failure), IOC cancellation, GTC resting, maker pricing in trades, bool rejection, duplicate ID detection, and cancel validation. The FOK fillable check correctly simulates without mutating state. No significant correctness bugs found.

Completeness

Weight 20%
85

Handles all event types, all TIF modes, all validation rules including bool-as-int, missing fields, invalid TIF values, market+GTC, duplicate IDs, cancel of non-resting orders. Book output is correctly sorted. All required trade record fields are present.

Code Quality

Weight 20%
80

Clean, readable structure with well-named helper functions. Logical flow is easy to follow. The use of itertools.count for sequencing is elegant. Minor redundancy between resting/bids/asks dicts. Re-sorting on each match step is slightly inefficient but acceptable. Self-test uses assert statements properly.

Practical Value

Weight 15%
75

Solid practical implementation. Handles edge cases well. The re-sorting approach works correctly for thousands of events though not optimal for very large books. No external dependencies. Clean API.

Instruction Following

Weight 10%
90

Follows all instructions precisely: single file, correct return shape with exactly the specified keys, no external packages, no stdin/stdout in core function, self-test guarded by __main__, ignores extra fields on valid events as specified.

Judge Models OpenAI GPT-5.5

Total Score

87

Overall Comments

Answer A is a strong, executable implementation of the required limit order book simulator. It correctly handles price-time priority, maker-price trades, partial fills, GTC/IOC/FOK behavior including atomic FOK checks, duplicate accepted IDs, cancellations, bool/int validation, and sorted final book output. Its main weaknesses are modest efficiency from repeatedly sorting the book during matching and a few robustness gaps for unusual malformed IDs such as unhashable values, but it substantially satisfies the task.

View Score Details

Correctness

Weight 35%
90

Correctly implements matching, price-time priority, maker pricing, partial fills, order removal, IOC/GTC behavior, FOK pre-checking without tentative mutation, duplicate accepted IDs, and final book sorting. Minor robustness concerns remain for unusual malformed IDs that are unhashable.

Completeness

Weight 20%
88

Covers almost all specified event types, validations, time-in-force modes, rejection records, trade records, and output shape. It omits only some edge-case malformed-input hardening such as unhashable IDs.

Code Quality

Weight 20%
80

The code is clean, readable, and organized with focused helper functions. The main quality drawback is repeated sorting inside each matching loop, which is simple but not especially efficient for larger books.

Practical Value

Weight 15%
82

Would be practically usable for small to medium deterministic simulations and produces the requested data structures. Efficiency is acceptable for thousands of events but could degrade with many resting orders due to repeated sorting.

Instruction Following

Weight 10%
92

Defines the required process_events function in a single file, uses no external packages, does not perform I/O inside the core function, returns exactly the required top-level keys, and keeps self-test output under the main guard.

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 > 0def _reject_event(rejected_list, input_index, event, reason): rejected_list.append({"input_index": input_index, "event": event, "reason"...

Show Full Answer

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 > 0def _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] = orderdef _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 Falsedef _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_qtydef 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']}")

Result

#2

Winning Votes

1 / 3

Average Score

50

Total Score

73

Overall Comments

Answer B provides a functionally correct solution that covers all specified requirements, including detailed validation. Its core matching algorithm is more sound than Answer A's, as it avoids re-sorting the book multiple times for a single incoming order. However, the code quality is very low. It is overly fragmented into too many helper functions, making it hard to follow, and the test block is filled with unprofessional developer notes and manual traces. Despite its poor structure, its superior algorithmic approach makes it the better solution.

View Score Details

Correctness

Weight 35%
80

The solution is logically correct and implements all matching and order handling rules as specified. The matching algorithm, while not optimal, is fundamentally sound and much more efficient than Answer A's, sorting the book only once per incoming order. The logic is complex, which slightly increases the risk of subtle bugs, but appears correct.

Completeness

Weight 20%
90

The solution is very complete. It handles all specified event types, order types, and time-in-force rules. The validation logic is thorough, covering missing fields, invalid values, duplicate IDs, and other edge cases as required by the prompt.

Code Quality

Weight 20%
40

The code quality is poor. While the use of an `Order` class is a good idea, the code is excessively fragmented into many small helper functions, which harms readability. The `if __name__ == "__main__"` block is extremely unprofessional, containing a large amount of commented-out developer notes and manual traces instead of clean tests.

Practical Value

Weight 15%
60

The solution's algorithm is more practical than A's. Although it is still inefficient due to using list operations for book management (O(N) inserts/removals), it would be able to handle a simulation of 'thousands of events' much more effectively than A. The OOP structure also offers slightly better extensibility.

Instruction Following

Weight 10%
100

The solution perfectly follows all instructions given in the prompt. It implements the required function with the correct signature and return type, uses no external packages, and formats the final output exactly as specified.

Total Score

69

Overall Comments

Answer B uses an OOP approach with an Order class and insertion-sort-style book maintenance. It handles most cases correctly but has several notable issues: (1) It rejects market orders that have a price field, which is not required by the spec (extra fields should be ignored, not rejected). (2) The duplicate ID check happens before side/order_type/qty validation, meaning some invalid orders get their IDs registered in used_ids before full validation — actually looking more carefully, used_ids.add happens after all checks, so that's fine. (3) The FOK rejection path returns 0 (filled qty) instead of the original qty, which means the caller sees remaining_qty=0 and doesn't try to rest the order — this is actually correct behavior for FOK rejection since the order shouldn't rest. (4) The trade record construction for sell-side takers has a bug: taker_id_key="sell_id" and maker_id_key="buy_id", so the dict gets sell_id=incoming.id and buy_id=maker.id, which is correct. (5) The book is maintained as sorted lists with insertion, which is efficient for small books. (6) The self-test section is extremely long with inline comments but doesn't use assert statements, reducing its value as a test. (7) Rejecting market orders with a price field is a spec violation — the spec says to ignore extra fields.

View Score Details

Correctness

Weight 35%
70

Core matching logic is correct, but Answer B rejects market orders that include a price field, which violates the spec requirement to ignore extra fields on otherwise valid events. This is a meaningful correctness defect. FOK handling is otherwise correct. Bool rejection and duplicate ID checks work properly.

Completeness

Weight 20%
75

Handles most cases. Missing: does not validate that market orders cannot have tif=FOK (the spec only prohibits GTC for market orders, so FOK is allowed — actually the spec says market orders may not have tif=GTC and may not rest, FOK is allowed). The extra-field rejection for market orders with price is an incompleteness relative to spec. Otherwise covers the main cases well.

Code Quality

Weight 20%
65

OOP approach with Order class is reasonable. Insertion-sort book maintenance is efficient. However, the self-test is extremely verbose with inline comments but no assert statements, making it less useful as a test. The _match_order function is somewhat complex. The _can_fill_fok function duplicates sorting logic from _match_order. Overall readable but with some structural redundancy.

Practical Value

Weight 15%
65

Practical for small to medium books. The insertion-sort maintenance is more efficient than re-sorting. However, the spec violation around extra fields could cause issues in real usage. The verbose self-test with no assertions provides limited practical testing value.

Instruction Following

Weight 10%
70

Mostly follows instructions but violates the explicit rule to ignore extra fields on otherwise valid events by rejecting market orders with a price field. Return shape is correct. No external packages. Self-test is guarded by __main__ but lacks assertions.

Judge Models OpenAI GPT-5.5

Total Score

7

Overall Comments

Answer B is not acceptable as submitted because the code is presented in a form that is not valid executable Python syntax, with class and function bodies collapsed onto single lines without proper statement separators or indentation. Even if reformatted, it has some behavioral issues, such as rejecting market orders that include a price despite the prompt saying extra fields should be ignored. Its intended structure includes many relevant components, but the submitted answer fails the executable-code requirement.

View Score Details

Correctness

Weight 35%
5

As submitted, the code is syntactically invalid and cannot run, so it cannot correctly implement the API. Even if reformatted, it incorrectly rejects market orders with a price field rather than ignoring extra fields.

Completeness

Weight 20%
10

The intended solution mentions most required concepts, including active orders, FOK checks, cancels, and final book output, but because it is not executable its completeness is largely theoretical. It also misses the instruction to ignore extra fields for market orders.

Code Quality

Weight 20%
5

The submitted formatting makes the program invalid Python. Although the intended design uses helper functions and an Order class, the actual code quality is severely undermined by non-executable syntax.

Practical Value

Weight 15%
5

It has essentially no practical value in its submitted form because it cannot be executed. A user would first need to reconstruct the formatting and then fix specification issues.

Instruction Following

Weight 10%
10

Fails the core instruction to provide complete executable Python code. It does define the intended API textually and uses no external packages, but the invalid syntax and market-price rejection conflict with the prompt.

Comparison Summary

Final rank order is determined by judge-wise rank aggregation (average rank + Borda tie-break). Average score is shown for reference.

Judges: 3

Winning Votes

2 / 3

Average Score

78
View this answer

Winning Votes

1 / 3

Average Score

50
View this answer

Judging Results

Judge Models OpenAI GPT-5.5

Why This Side Won

Answer A wins decisively because it is valid executable Python and implements nearly all required exchange behaviors correctly. Answer B, as submitted, is syntactically invalid and therefore cannot define the required process_events function; it also contains specification deviations even under a charitable reading. With correctness and completeness carrying the largest weights, Answer A is clearly superior.

Why This Side Won

Answer A wins primarily on correctness (highest weight at 35%). It correctly ignores extra fields on valid events (including price on market orders), whereas Answer B incorrectly rejects market orders that happen to include a price field. Answer A also has cleaner, more readable code structure and a proper assert-based self-test. Both solutions handle the core matching logic, FOK atomicity, and most validation cases correctly, but Answer A's stricter adherence to the spec's "ignore extra fields" rule and overall cleaner implementation give it the edge across correctness, code quality, and instruction following.

Why This Side Won

Answer B wins because Answer A has a critical algorithmic flaw that makes it unsuitable for the task. Answer A re-sorts the book on every single partial fill, which is catastrophically inefficient and violates the prompt's requirement for 'reasonable efficiency'. While Answer B's code quality is significantly lower, its core matching algorithm is fundamentally more sound. Given the high weights on correctness and practical value, the algorithmic soundness of Answer B outweighs the superior code quality of Answer A.

X f L