in ,

connorwstein / exchange, Hacker News

connorwstein / exchange, Hacker News
                    

        

A first project to explore Rust: an in-memory order book.

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)).
  •   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": [] }    

      RUST_BACKTRACE=1 cargo test - --nocapture         

  • What do you think?

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    GIPHY App Key not set. Please check settings

    Challenges with distributed systems, Hacker News

    Challenges with distributed systems, Hacker News

    Watch: UAE’s dumped shopping trolleys and how to report them