UNPKG

nodejs-order-book

Version:

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

159 lines (158 loc) 6.61 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 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; this._total = 0; this._numOrders = 0; this._depthSide = 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 += 1; } _this._numOrders += 1; _this._volume += order.size; _this._total += order.size * 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 -= 1; } _this._numOrders -= 1; _this._volume -= order.size; _this._total -= order.size * 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 += orderUpdate.size - oldOrder.size; _this._total += orderUpdate.size * newOrderPrice - oldOrder.size * oldOrder.price; _this._prices[oldOrder.price.toString()].updateOrderSize(oldOrder, orderUpdate.size); return oldOrder; }; // returns max level of price this.maxPriceQueue = function () { if (_this._depthSide > 0) { var max = _this._side === types_1.Side.SELL ? _this._priceTree.end : _this._priceTree.begin; return max.value; } }; // returns min level of price this.minPriceQueue = function () { if (_this._depthSide > 0) { var min = _this._side === types_1.Side.SELL ? _this._priceTree.begin : _this._priceTree.end; return min.value; } }; // 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(), " -> ").concat(volume); level = _this.lowerThan(level.price()); } return s; }; var compare = side === types_1.Side.SELL ? function (a, b) { return a - b; } : function (a, b) { return b - a; }; this._priceTree = (0, functional_red_black_tree_1.default)(compare); this._side = side; } return OrderSide; }()); exports.OrderSide = OrderSide;