Pro-Rata Order Book
Problem statement
Maintain a finite two-sided limit-order book for one asset and execute immediate-or-cancel aggressor requests using pro-rata allocation. Each operation has one of these forms:
["ADD", side, orderId, price, quantity]["CANCEL", orderId]["MATCH", side, limitPrice, quantity]
An ADD operation places a resting order at the back of its price level. A CANCEL operation removes the unfilled remainder of the named resting order; an unknown, filled, or already cancelled ID is a no-op.
A MATCH operation is an incoming immediate-or-cancel request. A BUY request visits sell prices from lowest to highest while the price is at most its limit. A SELL request visits buy prices from highest to lowest while the price is at least its limit. Any unmatched aggressor quantity is discarded rather than added to the book.
At one visited price level, let need be the smaller of the remaining aggressor quantity and the total resting quantity at that level. For each resting order with quantity q, first assign floor(need * q / total). Assign any leftover units one at a time in arrival order to orders that still have unfilled quantity. Emit positive fills in arrival order, reduce the resting quantities, and remove fully filled orders. A partially filled resting order keeps its original position.
Return every fill in execution order as "restingOrderId|price|quantity". ADD and CANCEL operations produce no output.
Function
executeProRata(operations: String[][]) → String[]Examples
Example 1
operations = [["ADD","SELL","s1","100","6"],["ADD","SELL","s2","100","3"],["ADD","SELL","s3","100","1"],["MATCH","BUY","100","5"],["MATCH","BUY","100","3"]]return = ["s1|100|4","s2|100|1","s1|100|2","s2|100|1"]The first request allocates base quantities [3,1,0] and gives the leftover unit to s1. The remaining quantities are [2,2,1]. The second request allocates base quantities [1,1,0] and again gives the leftover unit to the earliest eligible order, s1.
Example 2
operations = [["ADD","SELL","s1","99","2"],["ADD","SELL","s2","100","4"],["ADD","SELL","s3","100","2"],["MATCH","BUY","100","5"]]return = ["s1|99|2","s2|100|2","s3|100|1"]The request consumes all two units at the better sell price 99. At price 100, the remaining three units split proportionally as two for s2 and one for s3.
Example 3
operations = [["ADD","BUY","b1","101","5"],["ADD","BUY","b2","101","5"],["ADD","BUY","b3","100","8"],["CANCEL","b1"],["MATCH","SELL","100","6"]]return = ["b2|101|5","b3|100|1"]Cancellation removes b1. The sell request first fills all five units of b2 at the best buy price, then fills one unit of b3 at the next eligible price.
Constraints
1 <= operations.length <= 50000- Every operation has one of the three forms described above.
sideisBUYorSELL.orderIdcontains only ASCII letters, digits, hyphens, and underscores, has length from1through40, and does not contain|.- Every
ADDorder ID is unique and is never reused. 1 <= price, quantity <= 10^6, written as base-10 integers.- The total resting quantity at one price level never exceeds
10^9. - Across all
MATCHoperations, at most200000resting orders are inspected and at most200000positive fills are emitted.