Problem · Design

Limit Order Book Matching Engine

Learn this problem
HardCitadel logoCitadelFULLTIMEPHONE SCREEN

Problem statement

Process a finite sequence of limit-order submissions for one asset. Each operation has one of these forms:

  • ["BUY", orderId, price, quantity]
  • ["SELL", orderId, price, quantity]

All order IDs are unique. Process operations in input order. An incoming buy may trade with resting sells whose price is at most its limit, while an incoming sell may trade with resting buys whose price is at least its limit.

Always match the best available price first: the lowest sell price for a buy, or the highest buy price for a sell. Within one price level, match resting orders in arrival order. Each trade uses the resting order's price and the largest quantity possible between the incoming and resting orders. A partially filled incoming order continues matching; any remainder rests at the back of its price level.

Return every trade in execution order as "buyOrderId|sellOrderId|price|quantity". Submissions that do not trade produce no output.

Function

matchOrders(operations: String[][]) → String[]

Examples

Example 1

operations = [["BUY","b1","100","5"],["SELL","s1","90","2"],["SELL","s2","100","4"],["BUY","b2","101","1"]]return = ["b1|s1|100|2","b1|s2|100|3","b2|s2|100|1"]

Sell s1 first consumes two units of resting buy b1 at b1's price. Sell s2 consumes the remaining three units, then its one-unit remainder rests and is filled by b2 at s2's resting price.

Example 2

operations = [["SELL","s1","105","2"],["SELL","s2","103","1"],["BUY","b1","106","3"]]return = ["b1|s2|103|1","b1|s1|105|2"]

The incoming buy crosses both sells, but the lower price 103 has priority over 105.

Example 3

operations = [["BUY","b1","100","2"],["BUY","b2","100","3"],["SELL","s1","101","4"],["SELL","s2","100","4"]]return = ["b1|s2|100|2","b2|s2|100|2"]

Sell s1 does not cross the buy price. Sell s2 does, and equal-price buys fill in first-in-first-out order.

Constraints

  • 1 <= operations.length <= 200000
  • Every operation has exactly four strings and one of the forms described above.
  • orderId contains only ASCII letters, digits, hyphens, and underscores, has length from 1 through 40, and does not contain |.
  • Every order ID is unique.
  • 1 <= price, quantity <= 10^9, written as base-10 integers.
  • The number of generated trades and every remaining quantity fit in memory and signed 64-bit arithmetic.

More Citadel problems

drafts saved locally
public String[] matchOrders(String[][] operations) {
    // Write your code here.
}
operations[["BUY","b1","100","5"],["SELL","s1","90","2"],["SELL","s2","100","4"],["BUY","b2","101","1"]]
expected["b1|s1|100|2", "b1|s2|100|3", "b2|s2|100|1"]
checking account