@fuzefinance/orderbook-bignumber
Version:
Node.js Lmit Order Book for high-frequency trading (HFT).
157 lines (156 loc) • 6.7 kB
JavaScript
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
/* node:coverage ignore next - Don't know why first and last line of each file count as uncovered */
import BigNumber from "bignumber.js";
import createRBTree from "functional-red-black-tree";
import { CustomError, ERROR } from "./errors";
import { OrderFactory } from "./order";
import { OrderQueue } from "./orderqueue";
import { Side } from "./types";
var OrderSide = /** @class */ (function () {
function OrderSide(side) {
var _this = this;
this._prices = {};
this._volume = BigNumber(0);
this._total = BigNumber(0);
this._numOrders = BigNumber(0);
this._depthSide = BigNumber(0);
this._side = Side.SELL;
// returns amount of orders
this.len = function () {
return _this._numOrders;
};
// returns depth of market
this.depth = function () {
return _this._depthSide;
};
// returns total amount of quantity in side
this.volume = function () {
return _this._volume;
};
// returns the total (size * price of each price level) in side
this.total = function () {
return _this._total;
};
// returns the price tree in side
this.priceTree = function () {
return _this._priceTree;
};
// appends order to definite price level
this.append = function (order) {
var price = order.price;
var strPrice = price.toString();
if (_this._prices[strPrice] === undefined) {
var priceQueue = new OrderQueue(price);
_this._prices[strPrice] = priceQueue;
_this._priceTree = _this._priceTree.insert(price, priceQueue);
_this._depthSide = _this._depthSide.plus(1);
}
_this._numOrders = _this._numOrders.plus(1);
_this._volume = _this._volume.plus(order.size);
_this._total = _this._total.plus(order.size.multipliedBy(order.price));
return _this._prices[strPrice].append(order);
};
// removes order from definite price level
this.remove = function (order) {
var price = order.price;
var strPrice = price.toString();
if (_this._prices[strPrice] === undefined) {
throw CustomError(ERROR.INVALID_PRICE_LEVEL);
}
_this._prices[strPrice].remove(order);
if (_this._prices[strPrice].len() === 0) {
delete _this._prices[strPrice];
_this._priceTree = _this._priceTree.remove(price);
_this._depthSide = _this._depthSide.minus(1);
}
_this._numOrders = _this._numOrders.minus(1);
_this._volume = _this._volume.minus(order.size);
_this._total = _this._total.minus(order.size.multipliedBy(order.price));
return order;
};
// Update the price of an order and return the order with the updated price
this.updateOrderPrice = function (oldOrder, orderUpdate) {
_this.remove(oldOrder);
var newOrder = OrderFactory.createOrder(__assign(__assign({}, oldOrder.toObject()), { size: orderUpdate.size !== undefined ? orderUpdate.size : oldOrder.size, price: orderUpdate.price, time: Date.now() }));
_this.append(newOrder);
return newOrder;
};
// Update the price of an order and return the order with the updated price
this.updateOrderSize = function (oldOrder, orderUpdate) {
var _a;
var newOrderPrice = (_a = orderUpdate.price) !== null && _a !== void 0 ? _a : oldOrder.price;
_this._volume = _this._volume.plus(orderUpdate.size.minus(oldOrder.size));
var v1 = orderUpdate.size.multipliedBy(newOrderPrice);
var v2 = oldOrder.size.multipliedBy(oldOrder.price);
_this._total = _this._total.plus(v1.minus(v2));
_this._prices[oldOrder.price.toString()].updateOrderSize(oldOrder, orderUpdate.size);
return oldOrder;
};
// returns max level of price
this.maxPriceQueue = function () {
if (_this._depthSide.isGreaterThan(0)) {
var max = _this._side === Side.SELL ? _this._priceTree.end : _this._priceTree.begin;
return max.value;
}
return;
};
// returns min level of price
this.minPriceQueue = function () {
if (_this._depthSide.isGreaterThan(0)) {
var min = _this._side === Side.SELL ? _this._priceTree.begin : _this._priceTree.end;
return min.value;
}
return;
};
// returns nearest OrderQueue with price less than given
this.lowerThan = function (price) {
var node = _this._side === Side.SELL
? _this._priceTree.lt(price)
: _this._priceTree.gt(price);
return node.value;
};
// returns nearest OrderQueue with price greater than given
this.greaterThan = function (price) {
var node = _this._side === Side.SELL
? _this._priceTree.gt(price)
: _this._priceTree.lt(price);
return node.value;
};
// returns all orders
this.orders = function () {
var orders = [];
for (var price in _this._prices) {
var allOrders = _this._prices[price].toArray();
orders = orders.concat(allOrders);
}
return orders;
};
this.toString = function () {
var s = "";
var level = _this.maxPriceQueue();
while (level !== undefined) {
var volume = level.volume().toString();
s += "\n".concat(level.price().toNumber(), " -> ").concat(volume);
level = _this.lowerThan(level.price());
}
return s;
};
var compare = side === Side.SELL
? function (a, b) { return a.minus(b).toNumber(); }
: function (a, b) { return b.minus(a).toNumber(); };
this._priceTree = createRBTree(compare);
this._side = side;
}
return OrderSide;
}());
export { OrderSide };