Skip to content

Latest commit

 

History

History
141 lines (111 loc) · 5.45 KB

README.md

File metadata and controls

141 lines (111 loc) · 5.45 KB

Namebase Orderbook Coding Challenge

For this coding challenge, the task is to create a price-time priority limit order book data structure [1]. This is a mouthful and sounds more complicated than it is -- for an overview, refer to BACKGROUND.md.

The assets we're buying and selling on this order book are scoops of ice cream, and the currency we're using to buy and sell those scoops is the US penny (market symbol ICEPEN). No complicated decimals here -- integers only!

[1] The subject matter of this coding challenging is not necessarily indicative of this job's responsibilities. It's just a fun software challenge!

Requirements

Your submission should include the ability to:

  1. run some kind of unit tests
  2. create limit buy/sell orders
  3. recover the state of the order book after a crash/restart
  4. retrieve the total quantity at each limit price
  5. retrieve the state of an old order

These features are listed in priority order, so if you feel like you won't have enough time to finish this challenge, start at 1 and work your way down.

Challenge guidelines

Estimated completion time: 1.5-3 hours; please don't spend more time than this! Cut features and make tradeoffs instead.

For the purposes of this challenge, it is far more important to be bug-free than it is to be fast. If all operations run in O(n^2) or faster, then your program's performance and asymptotic complexity will not at all be considered in this challenge.

Note: n is the number of open orders (on the book) and m is the number of closed orders (off the book, no more remaining quantity to trade with).

When you submit your program, be sure to describe any suboptimal design and implementation decisions you made but were unable to fix in the alloted time in your README. We don't expect your submission to be 100% perfect -- software rarely is -- and we would like to get a sense of your ability to self-critique and build products incrementally.

Prioritize 1) being feature complete, 2) including enough tests to convince yourself you don't have any big bugs, and 3) writing clean code that is ready for change. Final tip: be cautious about overthinking your solution. Our reference implementation is just 70 SLOCs (excluding tests).

Submission

Send me ([email protected]) a zip file with your source code (or a link to a github repo) with instructions on how to run your tests.

Technical specification

The ./lib/index.js file should export a single class that implements the following functions:

Sync

Recover the state of the order book from a file. Please do not use a library like sqlite. Use node.js's built-in libraries to write and read to a file that allows you to recover your order book.

/**
 * @param {string} fileName -- the file that contains whatever info you need to recover
 */
sync(fileName);

Limit buy

Add a new limit buy order to the order book. Generates an id so that the client can reference this order in the future.

/**
 * @param {integer} quantity -- how many scoops of ice cream to buy
 * @param {integer} price -- the maximum number of pennies to pay per scoop
 */
buy(quantity, price);

Returns:

{
  id: ...,               // generated by your code, type is up to you
  isBuyOrder: true,      // whether this order is a buy or a sell
  quantity: ...,         // the order's original quantity
  price: ...,            // the order's price
  executedQuantity: ..., // the # of ice cream scoops that this order has purchased
}

Limit sell

Add a new limit sell order to the order book. Generates an id so that the client can reference this order in the future.

/**
 * @param {integer} quantity -- how many scoops of ice cream to sell
 * @param {integer} price -- the minimum number of pennies to receive per scoop
 */
sell(quantity, price);

Returns:

{
  id: ...,               // generated by your code, type is up to you
  isBuyOrder: false,     // whether this order is a buy or a sell
  quantity: ...,         // the order's original quantity
  price: ...,            // the order's price
  executedQuantity: ..., // the # of ice cream scoops that this order has sold
}

Get quantity at price

Retrieve the total number of ice cream scoops being bought or sold at a given limit price.

/**
 * @param {integer} price -- the limit price we're querying the quantity at
 */
getQuantityAtPrice(price);

Returns:

4 
// integer >= 0; the number of ice cream scoops at this price point
// note: all of the orders at a limit price are always on the same side,
//       they are either all BUYs or all SELLs

Get order

Retrieve the state of an old order.

/**
 * @param {number|string|up to you} id -- the order's id
 */
getOrder(id);

Returns:

{
  id: ...,               // generated by your code, type is up to you
  isBuyOrder: false,     // whether this order is a buy or a sell
  quantity: ...,         // the order's original quantity
  price: ...,            // the order's price
  executedQuantity: ..., // the # of ice cream scoops that this order has sold
}

Suboptimal design

  • guid generation relies on poor RNG
  • overall O() can be reduced leveraging BST
  • OOP for sellOrder and buyOrder
  • file system concurrency and error handling
  • logging
  • documentation headers
  • sync is manual, requires differential read/write (1 file per order)
  • remove coupling from business logic and persitence (services, repositories, ...)