UNPKG

@saturnnetwork/market-maker-strategy

Version:
156 lines (155 loc) 7.42 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const lodash_1 = __importDefault(require("lodash")); const chalk_1 = __importDefault(require("chalk")); const bignumber_js_1 = require("bignumber.js"); class OrderBookPrinter { constructor(orderbook) { this.orderbook = orderbook; } print() { console.log(chalk_1.default.yellow(`Order Book snapshot at ${new Date()}`)); let chartist = new OrderBookChart(this.orderbook.buys, this.orderbook.sells); console.log(chartist.plot()); } } exports.OrderBookPrinter = OrderBookPrinter; class OrderBookChart { constructor(buys, sells) { this.truncated = false; this.plot = () => { let min = new bignumber_js_1.BigNumber(0); let max = this.buyDepth.gt(this.sellDepth) ? this.buyDepth : this.sellDepth; let range = max; let offset = 3; let padding = ' '; let height = 8; let ratio = new bignumber_js_1.BigNumber(height).dividedBy(range); let min2 = Math.round(min.times(ratio).toNumber()); let max2 = Math.round(max.times(ratio).toNumber()); let rows = Math.abs(max2 - min2); let width = this.buys.length + this.sells.length + offset; let format = (x) => (padding + x.toFixed(2)).slice(-padding.length); let result = new Array(rows + 1); for (let i = 0; i <= rows; i++) { result[i] = new Array(width); for (let j = 0; j < width; j++) { result[i][j] = ' '; } } for (let y = min2; y <= max2; y++) { let label = format(max.toNumber() - (y - min2) * range.toNumber() / rows); result[y - min2][Math.max(offset - label.length, 0)] = label; result[y - min2][offset - 1] = '┤'; } let y0 = Math.round(this.buyDepthAtIndex(0).times(ratio).toNumber()) - min2; result[rows - y0][offset - 1] = chalk_1.default.green('┼'); for (let x = 0; x < this.buys.length - 1; x++) { let y0 = Math.round(this.buyDepthAtIndex(x + 0).times(ratio).toNumber()) - min2; let y1 = Math.round(this.buyDepthAtIndex(x + 1).times(ratio).toNumber()) - min2; if (y0 == y1) { result[rows - y0][x + offset] = chalk_1.default.green('─'); } else { result[rows - y1][x + offset] = chalk_1.default.green((y0 > y1) ? '╰' : '╭'); result[rows - y0][x + offset] = chalk_1.default.green((y0 > y1) ? '╮' : '╯'); let from = Math.min(y0, y1); let to = Math.max(y0, y1); for (let y = from + 1; y < to; y++) { result[rows - y][x + offset] = chalk_1.default.green('│'); } } } let from = Math.round(this.sellDepthAtIndex(0).times(ratio).toNumber()) - min2; let to = Math.round(this.sellDepthAtIndex(1).times(ratio).toNumber()) - min2; if (to != from) { let to = Math.round(this.sellDepthAtIndex(1).times(ratio).toNumber()) - min2; result[rows][this.buys.length + offset - 1] = chalk_1.default.red('╯'); result[rows - to][this.buys.length + offset - 1] = chalk_1.default.red('╭'); for (let y = 1; y < to; y++) { result[rows - y][this.buys.length + offset - 1] = chalk_1.default.red('│'); } } else { result[rows][this.buys.length + offset - 1] = chalk_1.default.red('─'); } for (let x = 1; x < this.sells.length - 1; x++) { let y0 = Math.round(this.sellDepthAtIndex(x + 0).times(ratio).toNumber()) - min2; let y1 = Math.round(this.sellDepthAtIndex(x + 1).times(ratio).toNumber()) - min2; if (y0 == y1) { result[rows - y0][x + offset + this.buys.length - 1] = chalk_1.default.red('─'); } else { result[rows - y1][x + offset + this.buys.length - 1] = chalk_1.default.red((y0 > y1) ? '╰' : '╭'); result[rows - y0][x + offset + this.buys.length - 1] = chalk_1.default.red((y0 > y1) ? '╮' : '╯'); let from = Math.min(y0, y1); let to = Math.max(y0, y1); for (let y = from + 1; y < to; y++) { result[rows - y][x + offset + this.buys.length - 1] = chalk_1.default.red('│'); } } } if (this.truncated) { result[0][width] = chalk_1.default.red('↑'); } return result.map(function (x) { return x.join(''); }).join('\n'); }; this.buys = sells.sort((a, b) => { let aprice = new bignumber_js_1.BigNumber(a.price); let bprice = new bignumber_js_1.BigNumber(b.price); return aprice.minus(bprice).toNumber(); }); this.buyDepth = lodash_1.default.reduce(lodash_1.default.map(sells, (order) => { return this.etherBalance(order); }), (x, y) => x.plus(y), new bignumber_js_1.BigNumber(0)); buys = this.filterSellOrders(buys); this.sells = buys.sort((a, b) => { let aprice = new bignumber_js_1.BigNumber(a.price); let bprice = new bignumber_js_1.BigNumber(b.price); return aprice.minus(bprice).toNumber(); }); this.sellDepth = lodash_1.default.reduce(lodash_1.default.map(buys, (order) => { return this.etherBalance(order); }), (x, y) => x.plus(y), new bignumber_js_1.BigNumber(0)); } buyDepthAtIndex(idx) { let result = this.buyDepth; for (let i = 0; i <= idx; ++i) { result = result.minus(this.etherBalance(this.buys[i])); } return result; } sellDepthAtIndex(idx) { let result = new bignumber_js_1.BigNumber(0); for (let i = 0; i <= idx; ++i) { result = result.plus(this.etherBalance(this.sells[i])); } return result; } filterSellOrders(orders) { let upperLimit = this.buyDepth.times(new bignumber_js_1.BigNumber(1.5)); let currentLimit = new bignumber_js_1.BigNumber(0); let result = []; result.push(orders[0]); result.push(orders[1]); for (let i = 2; i < orders.length; ++i) { currentLimit = currentLimit.plus(this.etherBalance(orders[i])); if (currentLimit.lte(upperLimit)) { result.push(orders[i]); } else { orders[i].balance = upperLimit.dividedBy(new bignumber_js_1.BigNumber(orders[i].price)).toFixed(); result.push(orders[i]); this.truncated = true; break; } } return result; } etherBalance(order) { return new bignumber_js_1.BigNumber(order.balance).times(new bignumber_js_1.BigNumber(order.price)); } }