UNPKG

@fuzefinance/orderbook-bignumber

Version:

Node.js Lmit Order Book for high-frequency trading (HFT).

163 lines (162 loc) 7.19 kB
"use strict"; 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); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.OrderSide = void 0; /* node:coverage ignore next - Don't know why first and last line of each file count as uncovered */ var bignumber_js_1 = __importDefault(require("bignumber.js")); var functional_red_black_tree_1 = __importDefault(require("functional-red-black-tree")); var errors_1 = require("./errors"); var order_1 = require("./order"); var orderqueue_1 = require("./orderqueue"); var types_1 = require("./types"); var OrderSide = /** @class */ (function () { function OrderSide(side) { var _this = this; this._prices = {}; this._volume = (0, bignumber_js_1.default)(0); this._total = (0, bignumber_js_1.default)(0); this._numOrders = (0, bignumber_js_1.default)(0); this._depthSide = (0, bignumber_js_1.default)(0); this._side = types_1.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_1.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 (0, errors_1.CustomError)(errors_1.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 = order_1.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 === types_1.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 === types_1.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 === types_1.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 === types_1.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 === types_1.Side.SELL ? function (a, b) { return a.minus(b).toNumber(); } : function (a, b) { return b.minus(a).toNumber(); }; this._priceTree = (0, functional_red_black_tree_1.default)(compare); this._side = side; } return OrderSide; }()); exports.OrderSide = OrderSide;