bot18
Version:
A high-frequency cryptocurrency trading bot by Zenbot creator @carlos8f
143 lines (111 loc) • 3.21 kB
JavaScript
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;