UNPKG

bot18

Version:

A high-frequency cryptocurrency trading bot by Zenbot creator @carlos8f

143 lines (111 loc) 3.21 kB
const { RBTree } = require('bintrees'); const BigNumber = require('bignumber.js'); const assert = require('assert'); class Orderbook { constructor() { this._ordersByID = {}; this._bids = new RBTree((a, b) => a.price.comparedTo(b.price)); this._asks = new RBTree((a, b) => a.price.comparedTo(b.price)); } _getTree(side) { return side === 'buy' ? this._bids : this._asks; } state(book) { if (book) { book.bids.forEach(order => this.add({ id: order[2], side: 'buy', price: BigNumber(order[0]), size: BigNumber(order[1]), }) ); book.asks.forEach(order => this.add({ id: order[2], side: 'sell', price: BigNumber(order[0]), size: BigNumber(order[1]), }) ); } else { book = { asks: [], bids: [] }; this._bids.reach(bid => book.bids.push(...bid.orders)); this._asks.each(ask => book.asks.push(...ask.orders)); return book; } } get(orderId) { return this._ordersByID[orderId]; } add(order) { order = { id: order.order_id || order.id, side: order.side, price: BigNumber(order.price), size: BigNumber(order.size || order.remaining_size), }; const tree = this._getTree(order.side); let node = tree.find({ price: order.price }); if (!node) { node = { price: order.price, orders: [], }; tree.insert(node); } node.orders.push(order); this._ordersByID[order.id] = order; } remove(orderId) { const order = this.get(orderId); if (!order) { return; } const tree = this._getTree(order.side); const node = tree.find({ price: order.price }); assert(node); const { orders } = node; orders.splice(orders.indexOf(order), 1); if (orders.length === 0) { tree.remove(node); } delete this._ordersByID[order.id]; } match(match) { const size = BigNumber(match.size); const price = BigNumber(match.price); const tree = this._getTree(match.side); const node = tree.find({ price: price }); assert(node); const order = node.orders.find(order => order.id === match.maker_order_id); assert(order); order.size = order.size.minus(size); this._ordersByID[order.id] = order; assert(order.size >= 0); if (order.size.eq(0)) { this.remove(order.id); } } change(change) { // price of null indicates market order if (change.price === null || change.price === undefined) { return; } const size = BigNumber(change.new_size); const price = BigNumber(change.price); const order = this.get(change.order_id); const tree = this._getTree(change.side); const node = tree.find({ price }); if (!node || node.orders.indexOf(order) < 0) { return; } const nodeOrder = node.orders[node.orders.indexOf(order)]; const newSize = parseFloat(order.size); const oldSize = parseFloat(change.old_size); assert.equal(oldSize, newSize); nodeOrder.size = size; this._ordersByID[nodeOrder.id] = nodeOrder; } } module.exports = exports = Orderbook;