From 55538ce6dcb1b7e13b453ca873cc5e9ddd8a1a03 Mon Sep 17 00:00:00 2001 From: Karl Ranna Date: Tue, 2 Jul 2019 13:08:19 +0000 Subject: [PATCH] fix(orderbook): show aggregated quantity --- lib/cli/commands/orderbook.ts | 61 ++++++++++++++++------------- test/unit/Command.orderbook.spec.ts | 20 +++++----- 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/lib/cli/commands/orderbook.ts b/lib/cli/commands/orderbook.ts index 69cea72a6..4d63a6858 100644 --- a/lib/cli/commands/orderbook.ts +++ b/lib/cli/commands/orderbook.ts @@ -10,15 +10,15 @@ type FormattedOrderbook = { rows: string[][], }; -type BucketDepth = { +type Bucket = { price: number, - depth: number; + quantity: number; }; type OrderbookJson = { pairId: string, - sell: BucketDepth[], - buy: BucketDepth[], + sell: Bucket[], + buy: Bucket[], }; const COLUMNS = [19, 19, 19, 19]; @@ -28,19 +28,26 @@ const HEADER = [ { content: colors.red('Sell'), colSpan: 2 }, ]; const SECONDARY_HEADER = [ + colors.green('Quantity'), colors.green('Price'), - colors.green('Depth'), colors.red('Price'), - colors.red('Depth'), + colors.red('Quantity'), ]; -const addSide = (buckets: BucketDepth[]): string[] => { +const addSide = (buckets: Bucket[], isBuy = false): string[] => { const bucket = buckets.pop(); if (bucket) { - return [ - bucket.price.toString(), - satsToCoinsStr(bucket.depth), - ]; + if (isBuy) { + return [ + satsToCoinsStr(bucket.quantity), + bucket.price.toString(), + ]; + } else { + return [ + bucket.price.toString(), + satsToCoinsStr(bucket.quantity), + ]; + } } else { return Array.from(Array(COLUMNS_IN_ORDER_SIDE)).map(() => ''); } @@ -55,7 +62,7 @@ export const createOrderbook = (orders: ListOrdersResponse.AsObject, precision: ? sell.length : buy.length; const orderbookRows = Array.from(Array(totalRows)) .map(() => { - return addSide(buy).concat(addSide(sell)); + return addSide(buy, true).concat(addSide(sell)); }); formattedOrderbooks.push({ pairId: tradingPair[0], @@ -94,11 +101,11 @@ const getPriceBuckets = (orders: Order.AsObject[], count = 8): number[] => { return uniquePrices.splice(0, count); }; -const getDepthForBuckets = ( +const getQuantityForBuckets = ( orders: Order.AsObject[], priceBuckets: number[], - filledBuckets: BucketDepth[] = [], -): BucketDepth[] => { + filledBuckets: Bucket[] = [], +): Bucket[] => { // go through all the available price buckets const price = priceBuckets.shift(); if (!price) { @@ -111,15 +118,15 @@ const getDepthForBuckets = ( filteredOrders = orders .filter(order => order.price === price); } - // calculate depth of the bucket - const depth = filteredOrders + // calculate quantity of the bucket + const quantity = filteredOrders .reduce((total, order) => { - return total + order.price * order.quantity; + return total + order.quantity; }, 0); - filledBuckets.push({ price, depth }); + filledBuckets.push({ price, quantity }); // filter orders for the next cycle const restOfOrders = orders.filter(order => order.price !== price); - return getDepthForBuckets(restOfOrders, priceBuckets, filledBuckets); + return getQuantityForBuckets(restOfOrders, priceBuckets, filledBuckets); }; export const createOrderbookSide = (orders: Order.AsObject[], precision = 5) => { @@ -130,12 +137,12 @@ export const createOrderbookSide = (orders: Order.AsObject[], precision = 5) => // get price buckets in which to divide orders to const priceBuckets = getPriceBuckets(orders); // divide prices into buckets - return getDepthForBuckets(orders, priceBuckets); + return getQuantityForBuckets(orders, priceBuckets); }; export const command = 'orderbook [pair_id] [precision]'; -export const describe = 'list the order book'; +export const describe = 'display the order book, with orders aggregated per price point'; export const builder = { pair_id: { @@ -151,16 +158,16 @@ export const builder = { const displayJson = (orders: ListOrdersResponse.AsObject, argv: Arguments) => { const jsonOrderbooks: OrderbookJson[] = []; - const depthInSatoshisPerCoin = (bucket: BucketDepth) => { - bucket.depth = parseFloat( - satsToCoinsStr(bucket.depth), + const quantityInSatoshisPerCoin = (bucket: Bucket) => { + bucket.quantity = parseFloat( + satsToCoinsStr(bucket.quantity), ); }; orders.ordersMap.forEach((tradingPair) => { const buy = createOrderbookSide(tradingPair[1].buyOrdersList, argv.precision); - buy.forEach(depthInSatoshisPerCoin); + buy.forEach(quantityInSatoshisPerCoin); const sell = createOrderbookSide(tradingPair[1].sellOrdersList, argv.precision); - sell.forEach(depthInSatoshisPerCoin); + sell.forEach(quantityInSatoshisPerCoin); jsonOrderbooks.push({ sell, buy, diff --git a/test/unit/Command.orderbook.spec.ts b/test/unit/Command.orderbook.spec.ts index 314a04f86..4ff1c98e7 100644 --- a/test/unit/Command.orderbook.spec.ts +++ b/test/unit/Command.orderbook.spec.ts @@ -55,14 +55,14 @@ describe('Command.orderbook.createOrderbookSide', () => { .concat(createOrders(80, 0.011131, 100000)) .concat(createOrders(100, 0.011111, 100000)); expect(createOrderbookSide(orders)).to.deep.equal([ - { price: 0.01216, depth: 121600 }, - { price: 0.01119, depth: 123090 }, - { price: 0.01118, depth: 33540 }, - { price: 0.01117, depth: 44680 }, - { price: 0.01116, depth: 55800 }, - { price: 0.01115, depth: 66900 }, - { price: 0.01114, depth: 77980 }, - { price: 0.01113, depth: 200140 }, + { price: 0.01216, quantity: 10000000 }, + { price: 0.01119, quantity: 11000000 }, + { price: 0.01118, quantity: 3000000 }, + { price: 0.01117, quantity: 4000000 }, + { price: 0.01116, quantity: 5000000 }, + { price: 0.01115, quantity: 6000000 }, + { price: 0.01114, quantity: 7000000 }, + { price: 0.01113, quantity: 18000000 }, ]); }); @@ -73,8 +73,8 @@ describe('Command.orderbook.createOrderbookSide', () => { .concat(createOrders(30, 0.011181, 100000)) .concat(createOrders(40, 0.011171, 100000)); expect(createOrderbookSide(orders, 3)).to.deep.equal([ - { price: 0.012, depth: 120000 }, - { price: 0.011, depth: 198000 }, + { price: 0.012, quantity: 10000000 }, + { price: 0.011, quantity: 18000000 }, ]); }); });