nodejs-order-book 8.1.0 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,9 +9,10 @@
9
9
 
10
10
  # Node.js Order Book
11
11
 
12
- Ultra-fast Node.js Order Book written in TypeScript for high-frequency trading (HFT) :rocket::rocket:
13
-
12
+ <p align="center">
13
+ Ultra-fast Node.js Order Book written in TypeScript </br> for high-frequency trading (HFT) :rocket::rocket: </br></br>
14
14
  :star: Star me on GitHub — it motivates me a lot!
15
+ </p>
15
16
 
16
17
  ## Table of Contents
17
18
 
@@ -42,15 +43,16 @@ Ultra-fast Node.js Order Book written in TypeScript for high-frequency trading (
42
43
  - [License](#license)
43
44
 
44
45
  ## Features
46
+ > Initially ported from [Go orderbook](https://github.com/i25959341/orderbook), this order book has been enhanced with new features
45
47
 
46
48
  - Standard price-time priority
47
49
  - Supports both market and limit orders
48
- - Supports `post-only` limit order
49
- - Supports conditional orders [**Stop Limit, Stop Market and OCO**](#conditional-orders-) <img src="https://img.shields.io/badge/Experimental-blue" alt="Experimental">
50
- - Supports time in force GTC, FOK and IOC
50
+ - Supports `post-only` limit order <img src="https://img.shields.io/badge/New-green" alt="New">
51
+ - Supports conditional orders [**Stop Limit, Stop Market and OCO**](#conditional-orders-) <img src="https://img.shields.io/badge/New-green" alt="New"> <img src="https://img.shields.io/badge/Experimental-blue" alt="Experimental">
52
+ - Supports time in force GTC, FOK and IOC <img src="https://img.shields.io/badge/New-green" alt="New">
51
53
  - Supports order cancelling
52
- - Supports order price and/or size updating
53
- - Snapshot and journaling functionalities for restoring the order book during server startup
54
+ - Supports order price and/or size updating <img src="https://img.shields.io/badge/New-green" alt="New">
55
+ - Snapshot and journaling functionalities for restoring the order book during server startup <img src="https://img.shields.io/badge/New-green" alt="New">
54
56
  - **High performance (above 300k trades per second)**
55
57
 
56
58
  **Machine:** ASUS ExpertBook, 11th Gen Intel(R) Core(TM) i7-1165G7, 2.80Ghz, 16GB RAM, Node.js v18.4.0.
@@ -391,6 +393,8 @@ A `snapshot` represents the state of the order book at a specific point in time.
391
393
  Snapshots are crucial for restoring the order book to a previous state. The orderbook can restore from a snapshot before processing any journal logs, ensuring consistency and accuracy.
392
394
  After taking the snapshot, you can safely remove all logs preceding the `lastOp` id.
393
395
 
396
+ **Note**: The snapshot of the order book returns an object containing an `array` of `bids` and `asks`, which in turn are arrays of order objects. If the snapshot is saved to the database as a `string`, make sure to pass the snapshot in its original format when initializing the order book. For example, you can achieve this by using `JSON.parse` to convert the string back into its original object form.
397
+
394
398
  ```js
395
399
  const ob = new OrderBook({ enableJournaling: true})
396
400
 
package/dist/cjs/order.js CHANGED
@@ -20,6 +20,7 @@ exports.OrderFactory = exports.StopLimitOrder = exports.StopMarketOrder = export
20
20
  var node_crypto_1 = require("node:crypto");
21
21
  var errors_1 = require("./errors");
22
22
  var types_1 = require("./types");
23
+ var utils_1 = require("./utils");
23
24
  var BaseOrder = /** @class */ (function () {
24
25
  function BaseOrder(options) {
25
26
  var _a, _b;
@@ -78,7 +79,7 @@ var LimitOrder = /** @class */ (function (_super) {
78
79
  _this.toString = function () {
79
80
  return "".concat(_this._id, ":\n type: ").concat(_this.type, "\n side: ").concat(_this._side, "\n size: ").concat(_this._size, "\n origSize: ").concat(_this._origSize, "\n price: ").concat(_this._price, "\n time: ").concat(_this._time, "\n timeInForce: ").concat(_this._timeInForce, "\n makerQty: ").concat(_this._makerQty, "\n takerQty: ").concat(_this._takerQty);
80
81
  };
81
- _this.toJSON = function () { return JSON.stringify(_this.toObject()); };
82
+ _this.toJSON = function () { return (0, utils_1.safeStringify)(_this.toObject()); };
82
83
  _this.toObject = function () { return ({
83
84
  id: _this._id,
84
85
  type: _this.type,
@@ -178,7 +179,7 @@ var StopMarketOrder = /** @class */ (function (_super) {
178
179
  _this.toString = function () {
179
180
  return "".concat(_this._id, ":\n type: ").concat(_this.type, "\n side: ").concat(_this._side, "\n size: ").concat(_this._size, "\n stopPrice: ").concat(_this._stopPrice, "\n time: ").concat(_this._time);
180
181
  };
181
- _this.toJSON = function () { return JSON.stringify(_this.toObject()); };
182
+ _this.toJSON = function () { return (0, utils_1.safeStringify)(_this.toObject()); };
182
183
  _this.toObject = function () { return ({
183
184
  id: _this._id,
184
185
  type: _this.type,
@@ -216,9 +217,9 @@ var StopLimitOrder = /** @class */ (function (_super) {
216
217
  var _a;
217
218
  var _this = _super.call(this, options) || this;
218
219
  _this.toString = function () {
219
- return "".concat(_this._id, ":\n type: ").concat(_this.type, "\n side: ").concat(_this._side, "\n size: ").concat(_this._size, "\n price: ").concat(_this._price, "\n stopPrice: ").concat(_this._stopPrice, "\n timeInForce: ").concat(_this._timeInForce, "\n time: ").concat(_this._time);
220
+ return "".concat(_this._id, ":\n type: ").concat(_this.type, "\n side: ").concat(_this._side, "\n size: ").concat(_this._size, "\n price: ").concat(_this._price, "\n stopPrice: ").concat(_this._stopPrice, "\n\tisOCO: ").concat(_this.isOCO, "\n timeInForce: ").concat(_this._timeInForce, "\n time: ").concat(_this._time);
220
221
  };
221
- _this.toJSON = function () { return JSON.stringify(_this.toObject()); };
222
+ _this.toJSON = function () { return (0, utils_1.safeStringify)(_this.toObject()); };
222
223
  _this.toObject = function () { return ({
223
224
  id: _this._id,
224
225
  type: _this.type,
@@ -226,6 +227,7 @@ var StopLimitOrder = /** @class */ (function (_super) {
226
227
  size: _this._size,
227
228
  price: _this._price,
228
229
  stopPrice: _this._stopPrice,
230
+ isOCO: _this.isOCO,
229
231
  timeInForce: _this._timeInForce,
230
232
  time: _this._time,
231
233
  }); };
@@ -190,7 +190,8 @@ var OrderBook = /** @class */ (function () {
190
190
  * @returns The order if exists or `undefined`
191
191
  */
192
192
  this.order = function (orderID) {
193
- return _this.orders[orderID];
193
+ var _a;
194
+ return (_a = _this.orders[orderID]) === null || _a === void 0 ? void 0 : _a.toObject();
194
195
  };
195
196
  // Returns price levels and volume at price level
196
197
  this.depth = function () {
@@ -246,10 +247,10 @@ var OrderBook = /** @class */ (function () {
246
247
  var bids = [];
247
248
  var asks = [];
248
249
  _this.bids.priceTree().forEach(function (price, orders) {
249
- bids.push({ price: price, orders: orders.toArray() });
250
+ bids.push({ price: price, orders: orders.toArray().map(function (o) { return o.toObject(); }) });
250
251
  });
251
252
  _this.asks.priceTree().forEach(function (price, orders) {
252
- asks.push({ price: price, orders: orders.toArray() });
253
+ asks.push({ price: price, orders: orders.toArray().map(function (o) { return o.toObject(); }) });
253
254
  });
254
255
  return { bids: bids, asks: asks, ts: Date.now(), lastOp: _this._lastOp };
255
256
  };
@@ -336,7 +337,7 @@ var OrderBook = /** @class */ (function () {
336
337
  isOCO: true,
337
338
  });
338
339
  _this.stopBook.add(stopLimit);
339
- response.done.push(stopLimit);
340
+ response.done.push(stopLimit.toObject());
340
341
  }
341
342
  else {
342
343
  response.err = (0, errors_1.CustomError)(errors_1.ERROR.INVALID_CONDITIONAL_ORDER);
@@ -346,7 +347,7 @@ var OrderBook = /** @class */ (function () {
346
347
  this._stopOrder = function (stopOrder, response) {
347
348
  if (_this.stopBook.validConditionalOrder(_this._marketPrice, stopOrder)) {
348
349
  _this.stopBook.add(stopOrder);
349
- response.done.push(stopOrder);
350
+ response.done.push(stopOrder.toObject());
350
351
  }
351
352
  else {
352
353
  response.err = (0, errors_1.CustomError)(errors_1.ERROR.INVALID_CONDITIONAL_ORDER);
@@ -359,16 +360,18 @@ var OrderBook = /** @class */ (function () {
359
360
  var level = _a[_i];
360
361
  for (var _b = 0, _c = level.orders; _b < _c.length; _b++) {
361
362
  var order = _c[_b];
362
- _this.orders[order.id] = order;
363
- _this.bids.append(order);
363
+ var newOrder = order_1.OrderFactory.createOrder(order);
364
+ _this.orders[newOrder.id] = newOrder;
365
+ _this.bids.append(newOrder);
364
366
  }
365
367
  }
366
368
  for (var _d = 0, _e = snapshot.asks; _d < _e.length; _d++) {
367
369
  var level = _e[_d];
368
370
  for (var _f = 0, _g = level.orders; _f < _g.length; _f++) {
369
371
  var order = _g[_f];
370
- _this.orders[order.id] = order;
371
- _this.asks.append(order);
372
+ var newOrder = order_1.OrderFactory.createOrder(order);
373
+ _this.orders[newOrder.id] = newOrder;
374
+ _this.asks.append(newOrder);
372
375
  }
373
376
  }
374
377
  };
@@ -379,6 +382,7 @@ var OrderBook = /** @class */ (function () {
379
382
  * @returns The removed order if exists or `undefined`
380
383
  */
381
384
  this._cancelOrder = function (orderID, internalDeletion) {
385
+ var _a, _b;
382
386
  if (internalDeletion === void 0) { internalDeletion = false; }
383
387
  var order = _this.orders[orderID];
384
388
  if (order === undefined)
@@ -386,11 +390,12 @@ var OrderBook = /** @class */ (function () {
386
390
  delete _this.orders[orderID];
387
391
  var side = order.side === types_1.Side.BUY ? _this.bids : _this.asks;
388
392
  var response = {
389
- order: side.remove(order),
393
+ order: (_a = side.remove(order)) === null || _a === void 0 ? void 0 : _a.toObject(),
390
394
  };
391
395
  // Delete OCO Order only when the delete request comes from user
392
396
  if (!internalDeletion && order.ocoStopPrice !== undefined) {
393
- response.stopOrder = _this.stopBook.remove(order.side, orderID, order.ocoStopPrice);
397
+ response.stopOrder = (_b = _this.stopBook
398
+ .remove(order.side, orderID, order.ocoStopPrice)) === null || _b === void 0 ? void 0 : _b.toObject();
394
399
  }
395
400
  if (_this.enableJournaling) {
396
401
  response.log = {
@@ -463,7 +468,7 @@ var OrderBook = /** @class */ (function () {
463
468
  order = order_1.OrderFactory.createOrder(__assign({ type: types_1.OrderType.LIMIT, id: orderID, side: side, size: quantityToTrade, origSize: size, price: price, time: Date.now(), timeInForce: timeInForce, postOnly: postOnly, takerQty: takerQty, makerQty: makerQty }, (ocoStopPrice !== undefined ? { ocoStopPrice: ocoStopPrice } : {})));
464
469
  if (response.done.length > 0) {
465
470
  response.partialQuantityProcessed = size - quantityToTrade;
466
- response.partial = order;
471
+ response.partial = order.toObject();
467
472
  }
468
473
  _this.orders[orderID] = sideToAdd.append(order);
469
474
  }
@@ -492,7 +497,7 @@ var OrderBook = /** @class */ (function () {
492
497
  takerQty: takerQty,
493
498
  makerQty: makerQty,
494
499
  });
495
- response.done.push(order);
500
+ response.done.push(order.toObject());
496
501
  }
497
502
  // If IOC order was not matched completely remove from the order book
498
503
  if (timeInForce === types_1.TimeInForce.IOC && response.quantityLeft > 0) {
@@ -538,7 +543,7 @@ var OrderBook = /** @class */ (function () {
538
543
  timeInForce: stopOrder.timeInForce,
539
544
  }, response);
540
545
  }
541
- response.activated.push(stopOrder);
546
+ response.activated.push(stopOrder.toObject());
542
547
  });
543
548
  }
544
549
  };
@@ -650,10 +655,11 @@ var OrderBook = /** @class */ (function () {
650
655
  var headOrder = orderQueue.head();
651
656
  if (headOrder !== undefined) {
652
657
  if (response.quantityLeft < headOrder.size) {
653
- response.partial = order_1.OrderFactory.createOrder(__assign(__assign({}, headOrder.toObject()), { size: headOrder.size - response.quantityLeft }));
654
- _this.orders[headOrder.id] = response.partial;
658
+ var partial = order_1.OrderFactory.createOrder(__assign(__assign({}, headOrder.toObject()), { size: headOrder.size - response.quantityLeft }));
659
+ response.partial = partial.toObject();
660
+ _this.orders[headOrder.id] = partial;
655
661
  response.partialQuantityProcessed = response.quantityLeft;
656
- orderQueue.update(headOrder, response.partial);
662
+ orderQueue.update(headOrder, partial);
657
663
  response.quantityLeft = 0;
658
664
  }
659
665
  else {
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.safeParse = exports.safeStringify = void 0;
4
+ /* node:coverage ignore next - Don't know why this line is uncovered */
5
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
6
+ var safeStringify = function (value) {
7
+ try {
8
+ return JSON.stringify(value);
9
+ }
10
+ catch (error) {
11
+ return null;
12
+ }
13
+ };
14
+ exports.safeStringify = safeStringify;
15
+ /* node:coverage ignore next - Don't know why this line is uncovered */
16
+ var safeParse = function (value) {
17
+ try {
18
+ return JSON.parse(value);
19
+ }
20
+ catch (error) {
21
+ return null;
22
+ }
23
+ };
24
+ exports.safeParse = safeParse;
package/dist/esm/order.js CHANGED
@@ -17,6 +17,7 @@ var __extends = (this && this.__extends) || (function () {
17
17
  import { randomUUID } from "node:crypto";
18
18
  import { CustomError, ERROR } from "./errors";
19
19
  import { OrderType, } from "./types";
20
+ import { safeStringify } from "./utils";
20
21
  var BaseOrder = /** @class */ (function () {
21
22
  function BaseOrder(options) {
22
23
  var _a, _b;
@@ -75,7 +76,7 @@ var LimitOrder = /** @class */ (function (_super) {
75
76
  _this.toString = function () {
76
77
  return "".concat(_this._id, ":\n type: ").concat(_this.type, "\n side: ").concat(_this._side, "\n size: ").concat(_this._size, "\n origSize: ").concat(_this._origSize, "\n price: ").concat(_this._price, "\n time: ").concat(_this._time, "\n timeInForce: ").concat(_this._timeInForce, "\n makerQty: ").concat(_this._makerQty, "\n takerQty: ").concat(_this._takerQty);
77
78
  };
78
- _this.toJSON = function () { return JSON.stringify(_this.toObject()); };
79
+ _this.toJSON = function () { return safeStringify(_this.toObject()); };
79
80
  _this.toObject = function () { return ({
80
81
  id: _this._id,
81
82
  type: _this.type,
@@ -175,7 +176,7 @@ var StopMarketOrder = /** @class */ (function (_super) {
175
176
  _this.toString = function () {
176
177
  return "".concat(_this._id, ":\n type: ").concat(_this.type, "\n side: ").concat(_this._side, "\n size: ").concat(_this._size, "\n stopPrice: ").concat(_this._stopPrice, "\n time: ").concat(_this._time);
177
178
  };
178
- _this.toJSON = function () { return JSON.stringify(_this.toObject()); };
179
+ _this.toJSON = function () { return safeStringify(_this.toObject()); };
179
180
  _this.toObject = function () { return ({
180
181
  id: _this._id,
181
182
  type: _this.type,
@@ -213,9 +214,9 @@ var StopLimitOrder = /** @class */ (function (_super) {
213
214
  var _a;
214
215
  var _this = _super.call(this, options) || this;
215
216
  _this.toString = function () {
216
- return "".concat(_this._id, ":\n type: ").concat(_this.type, "\n side: ").concat(_this._side, "\n size: ").concat(_this._size, "\n price: ").concat(_this._price, "\n stopPrice: ").concat(_this._stopPrice, "\n timeInForce: ").concat(_this._timeInForce, "\n time: ").concat(_this._time);
217
+ return "".concat(_this._id, ":\n type: ").concat(_this.type, "\n side: ").concat(_this._side, "\n size: ").concat(_this._size, "\n price: ").concat(_this._price, "\n stopPrice: ").concat(_this._stopPrice, "\n\tisOCO: ").concat(_this.isOCO, "\n timeInForce: ").concat(_this._timeInForce, "\n time: ").concat(_this._time);
217
218
  };
218
- _this.toJSON = function () { return JSON.stringify(_this.toObject()); };
219
+ _this.toJSON = function () { return safeStringify(_this.toObject()); };
219
220
  _this.toObject = function () { return ({
220
221
  id: _this._id,
221
222
  type: _this.type,
@@ -223,6 +224,7 @@ var StopLimitOrder = /** @class */ (function (_super) {
223
224
  size: _this._size,
224
225
  price: _this._price,
225
226
  stopPrice: _this._stopPrice,
227
+ isOCO: _this.isOCO,
226
228
  timeInForce: _this._timeInForce,
227
229
  time: _this._time,
228
230
  }); };
@@ -187,7 +187,8 @@ var OrderBook = /** @class */ (function () {
187
187
  * @returns The order if exists or `undefined`
188
188
  */
189
189
  this.order = function (orderID) {
190
- return _this.orders[orderID];
190
+ var _a;
191
+ return (_a = _this.orders[orderID]) === null || _a === void 0 ? void 0 : _a.toObject();
191
192
  };
192
193
  // Returns price levels and volume at price level
193
194
  this.depth = function () {
@@ -243,10 +244,10 @@ var OrderBook = /** @class */ (function () {
243
244
  var bids = [];
244
245
  var asks = [];
245
246
  _this.bids.priceTree().forEach(function (price, orders) {
246
- bids.push({ price: price, orders: orders.toArray() });
247
+ bids.push({ price: price, orders: orders.toArray().map(function (o) { return o.toObject(); }) });
247
248
  });
248
249
  _this.asks.priceTree().forEach(function (price, orders) {
249
- asks.push({ price: price, orders: orders.toArray() });
250
+ asks.push({ price: price, orders: orders.toArray().map(function (o) { return o.toObject(); }) });
250
251
  });
251
252
  return { bids: bids, asks: asks, ts: Date.now(), lastOp: _this._lastOp };
252
253
  };
@@ -333,7 +334,7 @@ var OrderBook = /** @class */ (function () {
333
334
  isOCO: true,
334
335
  });
335
336
  _this.stopBook.add(stopLimit);
336
- response.done.push(stopLimit);
337
+ response.done.push(stopLimit.toObject());
337
338
  }
338
339
  else {
339
340
  response.err = CustomError(ERROR.INVALID_CONDITIONAL_ORDER);
@@ -343,7 +344,7 @@ var OrderBook = /** @class */ (function () {
343
344
  this._stopOrder = function (stopOrder, response) {
344
345
  if (_this.stopBook.validConditionalOrder(_this._marketPrice, stopOrder)) {
345
346
  _this.stopBook.add(stopOrder);
346
- response.done.push(stopOrder);
347
+ response.done.push(stopOrder.toObject());
347
348
  }
348
349
  else {
349
350
  response.err = CustomError(ERROR.INVALID_CONDITIONAL_ORDER);
@@ -356,16 +357,18 @@ var OrderBook = /** @class */ (function () {
356
357
  var level = _a[_i];
357
358
  for (var _b = 0, _c = level.orders; _b < _c.length; _b++) {
358
359
  var order = _c[_b];
359
- _this.orders[order.id] = order;
360
- _this.bids.append(order);
360
+ var newOrder = OrderFactory.createOrder(order);
361
+ _this.orders[newOrder.id] = newOrder;
362
+ _this.bids.append(newOrder);
361
363
  }
362
364
  }
363
365
  for (var _d = 0, _e = snapshot.asks; _d < _e.length; _d++) {
364
366
  var level = _e[_d];
365
367
  for (var _f = 0, _g = level.orders; _f < _g.length; _f++) {
366
368
  var order = _g[_f];
367
- _this.orders[order.id] = order;
368
- _this.asks.append(order);
369
+ var newOrder = OrderFactory.createOrder(order);
370
+ _this.orders[newOrder.id] = newOrder;
371
+ _this.asks.append(newOrder);
369
372
  }
370
373
  }
371
374
  };
@@ -376,6 +379,7 @@ var OrderBook = /** @class */ (function () {
376
379
  * @returns The removed order if exists or `undefined`
377
380
  */
378
381
  this._cancelOrder = function (orderID, internalDeletion) {
382
+ var _a, _b;
379
383
  if (internalDeletion === void 0) { internalDeletion = false; }
380
384
  var order = _this.orders[orderID];
381
385
  if (order === undefined)
@@ -383,11 +387,12 @@ var OrderBook = /** @class */ (function () {
383
387
  delete _this.orders[orderID];
384
388
  var side = order.side === Side.BUY ? _this.bids : _this.asks;
385
389
  var response = {
386
- order: side.remove(order),
390
+ order: (_a = side.remove(order)) === null || _a === void 0 ? void 0 : _a.toObject(),
387
391
  };
388
392
  // Delete OCO Order only when the delete request comes from user
389
393
  if (!internalDeletion && order.ocoStopPrice !== undefined) {
390
- response.stopOrder = _this.stopBook.remove(order.side, orderID, order.ocoStopPrice);
394
+ response.stopOrder = (_b = _this.stopBook
395
+ .remove(order.side, orderID, order.ocoStopPrice)) === null || _b === void 0 ? void 0 : _b.toObject();
391
396
  }
392
397
  if (_this.enableJournaling) {
393
398
  response.log = {
@@ -460,7 +465,7 @@ var OrderBook = /** @class */ (function () {
460
465
  order = OrderFactory.createOrder(__assign({ type: OrderType.LIMIT, id: orderID, side: side, size: quantityToTrade, origSize: size, price: price, time: Date.now(), timeInForce: timeInForce, postOnly: postOnly, takerQty: takerQty, makerQty: makerQty }, (ocoStopPrice !== undefined ? { ocoStopPrice: ocoStopPrice } : {})));
461
466
  if (response.done.length > 0) {
462
467
  response.partialQuantityProcessed = size - quantityToTrade;
463
- response.partial = order;
468
+ response.partial = order.toObject();
464
469
  }
465
470
  _this.orders[orderID] = sideToAdd.append(order);
466
471
  }
@@ -489,7 +494,7 @@ var OrderBook = /** @class */ (function () {
489
494
  takerQty: takerQty,
490
495
  makerQty: makerQty,
491
496
  });
492
- response.done.push(order);
497
+ response.done.push(order.toObject());
493
498
  }
494
499
  // If IOC order was not matched completely remove from the order book
495
500
  if (timeInForce === TimeInForce.IOC && response.quantityLeft > 0) {
@@ -535,7 +540,7 @@ var OrderBook = /** @class */ (function () {
535
540
  timeInForce: stopOrder.timeInForce,
536
541
  }, response);
537
542
  }
538
- response.activated.push(stopOrder);
543
+ response.activated.push(stopOrder.toObject());
539
544
  });
540
545
  }
541
546
  };
@@ -647,10 +652,11 @@ var OrderBook = /** @class */ (function () {
647
652
  var headOrder = orderQueue.head();
648
653
  if (headOrder !== undefined) {
649
654
  if (response.quantityLeft < headOrder.size) {
650
- response.partial = OrderFactory.createOrder(__assign(__assign({}, headOrder.toObject()), { size: headOrder.size - response.quantityLeft }));
651
- _this.orders[headOrder.id] = response.partial;
655
+ var partial = OrderFactory.createOrder(__assign(__assign({}, headOrder.toObject()), { size: headOrder.size - response.quantityLeft }));
656
+ response.partial = partial.toObject();
657
+ _this.orders[headOrder.id] = partial;
652
658
  response.partialQuantityProcessed = response.quantityLeft;
653
- orderQueue.update(headOrder, response.partial);
659
+ orderQueue.update(headOrder, partial);
654
660
  response.quantityLeft = 0;
655
661
  }
656
662
  else {
@@ -0,0 +1,19 @@
1
+ /* node:coverage ignore next - Don't know why this line is uncovered */
2
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
3
+ export var safeStringify = function (value) {
4
+ try {
5
+ return JSON.stringify(value);
6
+ }
7
+ catch (error) {
8
+ return null;
9
+ }
10
+ };
11
+ /* node:coverage ignore next - Don't know why this line is uncovered */
12
+ export var safeParse = function (value) {
13
+ try {
14
+ return JSON.parse(value);
15
+ }
16
+ catch (error) {
17
+ return null;
18
+ }
19
+ };
@@ -35,7 +35,7 @@ export declare class LimitOrder extends BaseOrder {
35
35
  get takerQty(): number;
36
36
  get ocoStopPrice(): number | undefined;
37
37
  toString: () => string;
38
- toJSON: () => string;
38
+ toJSON: () => string | null;
39
39
  toObject: () => ILimitOrder;
40
40
  }
41
41
  export declare class StopMarketOrder extends BaseOrder {
@@ -45,7 +45,7 @@ export declare class StopMarketOrder extends BaseOrder {
45
45
  get type(): OrderType.STOP_MARKET;
46
46
  get stopPrice(): number;
47
47
  toString: () => string;
48
- toJSON: () => string;
48
+ toJSON: () => string | null;
49
49
  toObject: () => IStopMarketOrder;
50
50
  }
51
51
  export declare class StopLimitOrder extends BaseOrder {
@@ -62,7 +62,7 @@ export declare class StopLimitOrder extends BaseOrder {
62
62
  get timeInForce(): TimeInForce;
63
63
  get isOCO(): boolean;
64
64
  toString: () => string;
65
- toJSON: () => string;
65
+ toJSON: () => string | null;
66
66
  toObject: () => IStopLimitOrder;
67
67
  }
68
68
  export declare const OrderFactory: {
@@ -1,6 +1,5 @@
1
1
  import { type OrderBookError } from "./errors";
2
- import { type LimitOrder } from "./order";
3
- import { type CreateOrderOptions, type ICancelOrder, type IProcessOrder, type LimitOrderOptions, type MarketOrderOptions, type OCOOrderOptions, type OrderBookOptions, type OrderUpdatePrice, type OrderUpdateSize, Side, type Snapshot, type StopLimitOrderOptions, type StopMarketOrderOptions } from "./types";
2
+ import { type CreateOrderOptions, type ICancelOrder, type ILimitOrder, type IProcessOrder, type LimitOrderOptions, type MarketOrderOptions, type OCOOrderOptions, type OrderBookOptions, type OrderUpdatePrice, type OrderUpdateSize, Side, type Snapshot, type StopLimitOrderOptions, type StopMarketOrderOptions } from "./types";
4
3
  export declare class OrderBook {
5
4
  private orders;
6
5
  private _lastOp;
@@ -131,7 +130,7 @@ export declare class OrderBook {
131
130
  * @param orderID - The ID of the order to be returned
132
131
  * @returns The order if exists or `undefined`
133
132
  */
134
- order: (orderID: string) => LimitOrder | undefined;
133
+ order: (orderID: string) => ILimitOrder | undefined;
135
134
  depth: () => [Array<[number, number]>, Array<[number, number]>];
136
135
  toString: () => string;
137
136
  calculateMarketPrice: (side: Side, size: number) => {
@@ -140,22 +140,25 @@ export interface IStopLimitOrder {
140
140
  stopPrice: number;
141
141
  timeInForce: TimeInForce;
142
142
  time: number;
143
+ isOCO: boolean;
143
144
  }
144
145
  /**
145
146
  * Represents an order in the order book.
146
147
  */
147
148
  export type OrderOptions = InternalMarketOrderOptions | InternalLimitOrderOptions | InternalStopLimitOrderOptions | InternalStopMarketOrderOptions;
148
149
  export type StopOrderOptions = StopMarketOrderOptions | StopLimitOrderOptions | OCOOrderOptions;
150
+ export type IStopOrder = IStopLimitOrder | IStopMarketOrder;
151
+ export type IOrder = ILimitOrder | IStopOrder;
149
152
  /**
150
153
  * Represents the result of processing an order.
151
154
  */
152
155
  export interface IProcessOrder {
153
156
  /** Array of fully processed orders. */
154
- done: Order[];
157
+ done: IOrder[];
155
158
  /** Array of activated (stop limit or stop market) orders */
156
- activated: StopOrder[];
159
+ activated: IStopOrder[];
157
160
  /** The partially processed order, if any. */
158
- partial: LimitOrder | null;
161
+ partial: ILimitOrder | null;
159
162
  /** The quantity that has been processed in the partial order. */
160
163
  partialQuantityProcessed: number;
161
164
  /** The remaining quantity that needs to be processed. */
@@ -294,8 +297,8 @@ export type CreateOrderOptions = ({
294
297
  * Represents a cancel order operation.
295
298
  */
296
299
  export interface ICancelOrder {
297
- order: LimitOrder;
298
- stopOrder?: StopOrder;
300
+ order: ILimitOrder;
301
+ stopOrder?: IStopOrder;
299
302
  /** Optional log related to the order cancellation. */
300
303
  log?: CancelOrderJournalLog;
301
304
  }
@@ -345,14 +348,14 @@ export interface Snapshot {
345
348
  /** Price of the ask order */
346
349
  price: number;
347
350
  /** List of orders associated with this price */
348
- orders: LimitOrder[];
351
+ orders: ILimitOrder[];
349
352
  }>;
350
353
  /** List of bid orders, each with a price and a list of associated orders */
351
354
  bids: Array<{
352
355
  /** Price of the bid order */
353
356
  price: number;
354
357
  /** List of orders associated with this price */
355
- orders: LimitOrder[];
358
+ orders: ILimitOrder[];
356
359
  }>;
357
360
  /** Unix timestamp representing when the snapshot was taken */
358
361
  ts: number;
@@ -0,0 +1,2 @@
1
+ export declare const safeStringify: (value: any) => string | null;
2
+ export declare const safeParse: <T>(value: string) => T | null;