Order Matching Engine

HARD • Live C++ Rust Java Python
1M
ORDERS
1000
TRADERS
~500
SYMBOLS

Problem Description

Build a high-performance matching engine that processes 1,000,000 orders across ~500 symbols using price-time priority order books.

Your matching engine must:

Evaluation Criteria

Correctness: Your program outputs 5 aggregate values. The first 4 (floats) are compared against the reference with a tolerance of 0.01. The 5th (integer) must match exactly. All 5 must be correct to pass.

Performance: Wall-clock time to process all 1M orders determines tier placement.

Input Format

One line per order
id SIDE price qty trader_id symbol
Where
id is a positive integer order id, SIDE is BUY or SELL, price is the limit price (an integer number of ticks), qty is the order quantity, trader_id identifies the trader (it does not affect matching), and symbol is the instrument ticker (e.g. AAPL).
Stream length
1,000,000 orders across ~500 symbols and 1,000 traders in production. Test data is deterministic per seed.
Output (5 lines)
Process orders in file order. Each incoming order trades against the opposite side of its own symbol's book, best price first, while prices cross: a BUY fills against asks at or below its price, a SELL against bids at or above its price. Any unfilled remainder rests in the book at its limit price.
  1. matched: incoming orders completely filled on arrival.
  2. unmatched: incoming orders that got no fill on arrival.
  3. partial: incoming orders partly filled on arrival (the remainder rests in the book).
  4. avg_latency: reserved; always 0.000000 in this version.
  5. total_trades: number of fills. Each price level an incoming order trades against counts as one fill, however many resting orders sit at that level.
Lines 1 to 4 print as floats with 6 decimals; line 5 is an integer. Categories depend only on what happens on arrival; later fills against a resting order don't change its category.

Output Format & Sample

Sample input (first 8 of 5,000 lines; full file linked below):

1 BUY 1871 5422 884 EW
2 BUY 2002 21 45 PLD
3 BUY 4195 58 544 SAVE
4 BUY 1131 358 38 CDNS
5 SELL 2752 379 109 BITF
6 BUY 1049 1211 351 MSI
7 SELL 4247 673 759 O
8 SELL 2316 454 995 AOS
... (5,000 orders in the full sample)

Expected output for the full 5,000 order sample:

25.000000
4957.000000
18.000000
0.000000
44

↓ download full sample input  |  ↓ download expected output

Test your solution locally: ./your_solution < input.txt | diff - output.txt

Common Pitfalls

  • Maintain a separate book per symbol. All matching is price-time priority within a single symbol; cross-symbol matches don't exist.
  • Partial fills are required. An incoming BUY at 100 for 50 against a SELL at 100 for 80 matches 50; the SELL stays in the book with 30 left.
  • Best-bid > ask wins on the incoming side (a BUY at 105 vs an existing SELL at 100 trades at 100, the resting side's price).
  • Numbers can be large. Use 64-bit ints for cumulative quantities and notional. C++ int overflows at ~2.1B; cumulative qty across 1M orders blows past it.
  • Symbols are arbitrary strings. Don't assume a max length or fixed alphabet; use a hash map keyed by string.

Performance Tier Thresholds (applied by the grader)

LanguageGoldSilverBronzeTier 4
C++<500ms<2000ms<10000mselse PASS
Rust<500ms<2000ms<10000mselse PASS
Java<1000ms<4000ms<15000mselse PASS
Python<5000ms<15000ms<60000mselse PASS

Submission Rules

Starter Templates

C++
#include <cstdio>
#include <map>
#include <vector>
#include <string>
using namespace std;

struct Order {
    int order_id, price, qty, trader_id;
    string side, symbol;
};

int main() {
    // Per-symbol order books: buy_book[symbol] sorted desc by price, sell_book asc
    map<string, map<int, vector<Order>, greater<int>>> buy_book;
    map<string, map<int, vector<Order>>> sell_book;

    long long matched = 0, unmatched = 0, partial = 0, total_trades = 0;
    double total_latency = 0;
    int total_orders = 0;

    int oid, price, qty, tid;
    char side[8], symbol[16];

    while (scanf("%d %s %d %d %d %s", &oid, side, &price, &qty, &tid, symbol) == 6) {
        total_orders++;
        // Implement: match against opposite book using price-time priority
        // Track matched_orders, unmatched_orders, partial_fills, total_trades
    }

    double avg_lat = total_orders > 0 ? total_latency / total_orders : 0.0;
    printf("%.6f\n", (double)matched);
    printf("%.6f\n", (double)unmatched);
    printf("%.6f\n", (double)partial);
    printf("%.6f\n", avg_lat);
    printf("%lld\n", total_trades);
    return 0;
}
Python
import sys
from collections import defaultdict

buy_book = defaultdict(list)   # symbol -> [(price, order_id, qty, trader_id), ...] max-heap
sell_book = defaultdict(list)  # symbol -> [(price, order_id, qty, trader_id), ...] min-heap

matched = 0
unmatched = 0
partial = 0
total_trades = 0
total_latency = 0.0
total_orders = 0

for line in sys.stdin:
    parts = line.strip().split()
    if len(parts) != 6:
        continue
    oid, side, price, qty, tid, symbol = int(parts[0]), parts[1], int(parts[2]), int(parts[3]), int(parts[4]), parts[5]
    total_orders += 1

    # Implement: match against opposite book using price-time priority
    # Track matched, unmatched, partial, total_trades

avg_lat = total_latency / total_orders if total_orders > 0 else 0.0
print(f"{matched:.6f}")
print(f"{unmatched:.6f}")
print(f"{partial:.6f}")
print(f"{avg_lat:.6f}")
print(total_trades)
Rust
use std::io::{self, BufRead, Write, BufWriter};
use std::collections::HashMap;

fn main() {
    let stdin = io::stdin();
    let stdout = io::stdout();
    let mut out = BufWriter::new(stdout.lock());

    let mut matched: i64 = 0;
    let mut unmatched: i64 = 0;
    let mut partial: i64 = 0;
    let mut total_trades: i64 = 0;
    let mut total_latency: f64 = 0.0;
    let mut total_orders: i64 = 0;

    for line in stdin.lock().lines() {
        let line = line.unwrap();
        let parts: Vec<&str> = line.trim().split_whitespace().collect();
        if parts.len() != 6 { continue; }
        let _oid: i32 = parts[0].parse().unwrap();
        let side = parts[1];
        let price: i32 = parts[2].parse().unwrap();
        let qty: i32 = parts[3].parse().unwrap();
        let _tid: i32 = parts[4].parse().unwrap();
        let symbol = parts[5];
        total_orders += 1;

        // Implement: match against opposite book using price-time priority
    }

    let avg_lat = if total_orders > 0 { total_latency / total_orders as f64 } else { 0.0 };
    writeln!(out, "{:.6}", matched as f64).unwrap();
    writeln!(out, "{:.6}", unmatched as f64).unwrap();
    writeln!(out, "{:.6}", partial as f64).unwrap();
    writeln!(out, "{:.6}", avg_lat).unwrap();
    writeln!(out, "{}", total_trades).unwrap();
}
Java
import java.util.*;
import java.io.*;

public class Solution {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        long matched = 0, unmatched = 0, partial = 0, totalTrades = 0;
        double totalLatency = 0.0;
        int totalOrders = 0;

        String line;
        while ((line = br.readLine()) != null) {
            String[] parts = line.trim().split("\\s+");
            if (parts.length != 6) continue;
            int oid = Integer.parseInt(parts[0]);
            String side = parts[1];
            int price = Integer.parseInt(parts[2]);
            int qty = Integer.parseInt(parts[3]);
            int tid = Integer.parseInt(parts[4]);
            String symbol = parts[5];
            totalOrders++;

            // Implement: match against opposite book using price-time priority
        }

        double avgLat = totalOrders > 0 ? totalLatency / totalOrders : 0.0;
        System.out.printf("%.6f%n", (double) matched);
        System.out.printf("%.6f%n", (double) unmatched);
        System.out.printf("%.6f%n", (double) partial);
        System.out.printf("%.6f%n", avgLat);
        System.out.printf("%d%n", totalTrades);
    }
}

Submit Your Solution

Supported formats: .cpp, .py, .rs, .java, or raw text