in connorwstein, Exchange connorwstein / exchange, Hacker News 1.7k Views A first project to explore Rust: an in-memory order book. Design According to [https://www.chrisstucchio.com/blog/2012/hft_apology.html] an order book needs to be organized by price level first and then by arrival time. To simplify the order filling slightly, I’ve enforced that every order involved in a fill is above / below the requested limit for sells / buys. Presumably in practice you could still fill an order if the average fill price satisfied the requested limit. We can have a separate order book per symbol as they are entirely independent and can be handled concurrently. A map can look up the respective order book for a given symbol in O (1) time. Each orderbook is a sorted vector of queues per price level, which gives us O (log (N)) to insert an order at an existing price level and finding a set of fulfilling orders takes O (N) time. Time complexity of filling an order depends on a few things: The order price level distribution. The worst case is a single order per price level, yielding O (N k) to fill where k is the number of orders on the other side of the trade required to fill. The best case is just a single queue at a one price level, yielding O (k). How often we need to remove queues once orders a price level are drained because that results in a vector shift (O (N)). Examples RUST_BACKTRACE=1 RUST_LOG=debug cargo run curl -H "Content-Type: application / json" -d '{"price": 3, "side": "Sell", "amount": 5, "symbol": "AAPL"}' localhost: 8111 / order | jq { "id": "ef1c4f - ff (4b) - 9c - 2019 b1f1db8ca ", "amount": 5, "symbol": "AAPL", "price": 3, side: Sell } curl -H "Content-Type: application / json" -d '{"price": 3, "side": "Sell", "amount": 5, "symbol": "AAPL"}' localhost: 8111 / order | jq { "id": " (bc) - f2cf - (c-9dc6 -) (ea3e) ac ", "amount": 5, "symbol": "AAPL", "price": 3, side: Sell } curl localhost: 8111 / sells | jq { "AAPL": [ [ { "id": "ef1c4f22-ff16-4b40-9c92-881b1f1db8ca", "amount": 5, "symbol": "AAPL", "price": 3, "side": "Sell" }, { "id": "40bc6343-f2cf-486c-9dc6-8111ea3e69ac", "amount": 5, "symbol": "AAPL", "price": 3, "side": "Sell" } ] ], "MSFT": [], "AMZN": [] } curl -H "Content-Type: application / json" -d '{"price": 3, "side": "Buy", "amount": 7, "symbol": "AAPL"}' localhost: 8111 / order | jq { "avg_price": 3 } curl localhost: 8111 / sells { "AMZN": [], "AAPL": [ [ { "id": "40bc6343-f2cf-486c-9dc6-8111ea3e69ac", "amount": 3, "symbol": "AAPL", "price": 3, "side": "Sell" } ] ], "MSFT": [] } Unit tests RUST_BACKTRACE=1 cargo test - --nocapture (Read More 823 See more Previous article Challenges with distributed systems, Hacker News Next article Watch: UAE’s dumped shopping trolleys and how to report them What do you think? 0 Points Upvote Downvote Leave a ReplyCancel replyYour email address will not be published. Required fields are marked *Comment * Name * Email * Website Save my name, email, and website in this browser for the next time I comment. By using this form you agree with the storage and handling of your data by this website. * Post Comment Reply with GIF GIPHY App Key not set. Please check settings
A first project to explore Rust: an in-memory order book. Design According to [https://www.chrisstucchio.com/blog/2012/hft_apology.html] an order book needs to be organized by price level first and then by arrival time. To simplify the order filling slightly, I’ve enforced that every order involved in a fill is above / below the requested limit for sells / buys. Presumably in practice you could still fill an order if the average fill price satisfied the requested limit. We can have a separate order book per symbol as they are entirely independent and can be handled concurrently. A map can look up the respective order book for a given symbol in O (1) time. Each orderbook is a sorted vector of queues per price level, which gives us O (log (N)) to insert an order at an existing price level and finding a set of fulfilling orders takes O (N) time. Time complexity of filling an order depends on a few things: The order price level distribution. The worst case is a single order per price level, yielding O (N k) to fill where k is the number of orders on the other side of the trade required to fill. The best case is just a single queue at a one price level, yielding O (k). How often we need to remove queues once orders a price level are drained because that results in a vector shift (O (N)). Examples RUST_BACKTRACE=1 RUST_LOG=debug cargo run curl -H "Content-Type: application / json" -d '{"price": 3, "side": "Sell", "amount": 5, "symbol": "AAPL"}' localhost: 8111 / order | jq { "id": "ef1c4f - ff (4b) - 9c - 2019 b1f1db8ca ", "amount": 5, "symbol": "AAPL", "price": 3, side: Sell } curl -H "Content-Type: application / json" -d '{"price": 3, "side": "Sell", "amount": 5, "symbol": "AAPL"}' localhost: 8111 / order | jq { "id": " (bc) - f2cf - (c-9dc6 -) (ea3e) ac ", "amount": 5, "symbol": "AAPL", "price": 3, side: Sell } curl localhost: 8111 / sells | jq { "AAPL": [ [ { "id": "ef1c4f22-ff16-4b40-9c92-881b1f1db8ca", "amount": 5, "symbol": "AAPL", "price": 3, "side": "Sell" }, { "id": "40bc6343-f2cf-486c-9dc6-8111ea3e69ac", "amount": 5, "symbol": "AAPL", "price": 3, "side": "Sell" } ] ], "MSFT": [], "AMZN": [] } curl -H "Content-Type: application / json" -d '{"price": 3, "side": "Buy", "amount": 7, "symbol": "AAPL"}' localhost: 8111 / order | jq { "avg_price": 3 } curl localhost: 8111 / sells { "AMZN": [], "AAPL": [ [ { "id": "40bc6343-f2cf-486c-9dc6-8111ea3e69ac", "amount": 3, "symbol": "AAPL", "price": 3, "side": "Sell" } ] ], "MSFT": [] } Unit tests RUST_BACKTRACE=1 cargo test - --nocapture (Read More 823
GIPHY App Key not set. Please check settings