nodejs-order-book 10.0.1 → 10.1.1
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 +198 -0
- package/dist/cjs/errors.js +47 -45
- package/dist/cjs/index.js +4 -3
- package/dist/cjs/order.js +229 -272
- package/dist/cjs/orderbook.js +848 -784
- package/dist/cjs/orderqueue.js +68 -66
- package/dist/cjs/orderside.js +139 -147
- package/dist/cjs/stopbook.js +69 -69
- package/dist/cjs/stopqueue.js +47 -51
- package/dist/cjs/stopside.js +68 -68
- package/dist/cjs/types.js +8 -1
- package/dist/cjs/utils.js +2 -2
- package/dist/esm/errors.js +47 -46
- package/dist/esm/index.js +2 -2
- package/dist/esm/order.js +227 -273
- package/dist/esm/orderbook.js +844 -781
- package/dist/esm/orderqueue.js +67 -66
- package/dist/esm/orderside.js +134 -143
- package/dist/esm/stopbook.js +67 -68
- package/dist/esm/stopqueue.js +46 -51
- package/dist/esm/stopside.js +64 -65
- package/dist/esm/types.js +7 -0
- package/dist/esm/utils.js +2 -2
- package/dist/types/errors.d.ts +2 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/order.d.ts +5 -1
- package/dist/types/types.d.ts +24 -0
- package/package.json +13 -12
package/dist/cjs/stopside.js
CHANGED
|
@@ -5,75 +5,75 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.StopSide = void 0;
|
|
7
7
|
/* node:coverage ignore next - Don't know why first and last line of each file count as uncovered */
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (_this._prices[strPrice] === undefined) {
|
|
21
|
-
var priceQueue = new stopqueue_1.StopQueue(price);
|
|
22
|
-
_this._prices[strPrice] = priceQueue;
|
|
23
|
-
_this._priceTree = _this._priceTree.insert(price, priceQueue);
|
|
24
|
-
}
|
|
25
|
-
return _this._prices[strPrice].append(order);
|
|
26
|
-
};
|
|
27
|
-
// removes order from definite price level
|
|
28
|
-
this.remove = function (id, stopPrice) {
|
|
29
|
-
var strPrice = stopPrice.toString();
|
|
30
|
-
if (_this._prices[strPrice] === undefined) {
|
|
31
|
-
throw (0, errors_1.CustomError)(errors_1.ERROR.INVALID_PRICE_LEVEL);
|
|
32
|
-
}
|
|
33
|
-
var deletedOrder = _this._prices[strPrice].remove(id);
|
|
34
|
-
if (_this._prices[strPrice].len() === 0) {
|
|
35
|
-
delete _this._prices[strPrice];
|
|
36
|
-
_this._priceTree = _this._priceTree.remove(stopPrice);
|
|
37
|
-
}
|
|
38
|
-
return deletedOrder;
|
|
39
|
-
};
|
|
40
|
-
this.removePriceLevel = function (priceLevel) {
|
|
41
|
-
delete _this._prices[priceLevel.toString()];
|
|
42
|
-
_this._priceTree = _this._priceTree.remove(priceLevel);
|
|
43
|
-
};
|
|
44
|
-
// Get orders queue between two price levels
|
|
45
|
-
this.between = function (priceBefore, marketPrice) {
|
|
46
|
-
var queues = [];
|
|
47
|
-
var lowerBound = priceBefore;
|
|
48
|
-
var upperBound = marketPrice;
|
|
49
|
-
var highest = Math.max(priceBefore, marketPrice);
|
|
50
|
-
var lowest = Math.min(priceBefore, marketPrice);
|
|
51
|
-
if (_this._side === types_1.Side.BUY) {
|
|
52
|
-
lowerBound = highest;
|
|
53
|
-
upperBound = lowest - 1;
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
lowerBound = lowest;
|
|
57
|
-
upperBound = highest + 1;
|
|
58
|
-
}
|
|
59
|
-
_this._priceTree.forEach(function (price, queue) {
|
|
60
|
-
if ((_this._side === types_1.Side.BUY && price >= lowest) ||
|
|
61
|
-
(_this._side === types_1.Side.SELL && price <= highest)) {
|
|
62
|
-
queues.push(queue);
|
|
63
|
-
}
|
|
64
|
-
}, lowerBound, // Inclusive
|
|
65
|
-
upperBound);
|
|
66
|
-
return queues;
|
|
67
|
-
};
|
|
68
|
-
this.priceTree = function () {
|
|
69
|
-
return _this._priceTree;
|
|
70
|
-
};
|
|
71
|
-
var compare = side === types_1.Side.SELL
|
|
72
|
-
? function (a, b) { return a - b; }
|
|
73
|
-
: function (a, b) { return b - a; };
|
|
8
|
+
const functional_red_black_tree_1 = __importDefault(require("functional-red-black-tree"));
|
|
9
|
+
const errors_1 = require("./errors");
|
|
10
|
+
const stopqueue_1 = require("./stopqueue");
|
|
11
|
+
const types_1 = require("./types");
|
|
12
|
+
class StopSide {
|
|
13
|
+
_priceTree;
|
|
14
|
+
_prices = {};
|
|
15
|
+
_side;
|
|
16
|
+
constructor(side) {
|
|
17
|
+
const compare = side === types_1.Side.SELL
|
|
18
|
+
? (a, b) => a - b
|
|
19
|
+
: (a, b) => b - a;
|
|
74
20
|
this._priceTree = (0, functional_red_black_tree_1.default)(compare);
|
|
75
21
|
this._side = side;
|
|
76
22
|
}
|
|
77
|
-
|
|
78
|
-
|
|
23
|
+
// appends order to definite price level
|
|
24
|
+
append = (order) => {
|
|
25
|
+
const price = order.stopPrice;
|
|
26
|
+
const strPrice = price.toString();
|
|
27
|
+
if (this._prices[strPrice] === undefined) {
|
|
28
|
+
const priceQueue = new stopqueue_1.StopQueue(price);
|
|
29
|
+
this._prices[strPrice] = priceQueue;
|
|
30
|
+
this._priceTree = this._priceTree.insert(price, priceQueue);
|
|
31
|
+
}
|
|
32
|
+
return this._prices[strPrice].append(order);
|
|
33
|
+
};
|
|
34
|
+
// removes order from definite price level
|
|
35
|
+
remove = (id, stopPrice) => {
|
|
36
|
+
const strPrice = stopPrice.toString();
|
|
37
|
+
if (this._prices[strPrice] === undefined) {
|
|
38
|
+
throw (0, errors_1.CustomError)(errors_1.ERROR.INVALID_PRICE_LEVEL);
|
|
39
|
+
}
|
|
40
|
+
const deletedOrder = this._prices[strPrice].remove(id);
|
|
41
|
+
if (this._prices[strPrice].len() === 0) {
|
|
42
|
+
delete this._prices[strPrice];
|
|
43
|
+
this._priceTree = this._priceTree.remove(stopPrice);
|
|
44
|
+
}
|
|
45
|
+
return deletedOrder;
|
|
46
|
+
};
|
|
47
|
+
removePriceLevel = (priceLevel) => {
|
|
48
|
+
delete this._prices[priceLevel.toString()];
|
|
49
|
+
this._priceTree = this._priceTree.remove(priceLevel);
|
|
50
|
+
};
|
|
51
|
+
// Get orders queue between two price levels
|
|
52
|
+
between = (priceBefore, marketPrice) => {
|
|
53
|
+
const queues = [];
|
|
54
|
+
let lowerBound = priceBefore;
|
|
55
|
+
let upperBound = marketPrice;
|
|
56
|
+
const highest = Math.max(priceBefore, marketPrice);
|
|
57
|
+
const lowest = Math.min(priceBefore, marketPrice);
|
|
58
|
+
if (this._side === types_1.Side.BUY) {
|
|
59
|
+
lowerBound = highest;
|
|
60
|
+
upperBound = lowest - 1;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
lowerBound = lowest;
|
|
64
|
+
upperBound = highest + 1;
|
|
65
|
+
}
|
|
66
|
+
this._priceTree.forEach((price, queue) => {
|
|
67
|
+
if ((this._side === types_1.Side.BUY && price >= lowest) ||
|
|
68
|
+
(this._side === types_1.Side.SELL && price <= highest)) {
|
|
69
|
+
queues.push(queue);
|
|
70
|
+
}
|
|
71
|
+
}, lowerBound, // Inclusive
|
|
72
|
+
upperBound);
|
|
73
|
+
return queues;
|
|
74
|
+
};
|
|
75
|
+
priceTree = () => {
|
|
76
|
+
return this._priceTree;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
79
|
exports.StopSide = StopSide;
|
package/dist/cjs/types.js
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TimeInForce = exports.OrderType = exports.Side = void 0;
|
|
3
|
+
exports.TimeInForce = exports.OrderType = exports.SelfTradePreventionMode = exports.Side = void 0;
|
|
4
4
|
var Side;
|
|
5
5
|
(function (Side) {
|
|
6
6
|
Side["BUY"] = "buy";
|
|
7
7
|
Side["SELL"] = "sell";
|
|
8
8
|
})(Side || (exports.Side = Side = {}));
|
|
9
|
+
var SelfTradePreventionMode;
|
|
10
|
+
(function (SelfTradePreventionMode) {
|
|
11
|
+
SelfTradePreventionMode["NONE"] = "NONE";
|
|
12
|
+
SelfTradePreventionMode["EXPIRE_TAKER"] = "EXPIRE_TAKER";
|
|
13
|
+
SelfTradePreventionMode["EXPIRE_MAKER"] = "EXPIRE_MAKER";
|
|
14
|
+
SelfTradePreventionMode["EXPIRE_BOTH"] = "EXPIRE_BOTH";
|
|
15
|
+
})(SelfTradePreventionMode || (exports.SelfTradePreventionMode = SelfTradePreventionMode = {}));
|
|
9
16
|
var OrderType;
|
|
10
17
|
(function (OrderType) {
|
|
11
18
|
OrderType["LIMIT"] = "limit";
|
package/dist/cjs/utils.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.safeParse = exports.safeStringify = void 0;
|
|
4
4
|
/* node:coverage ignore next - Don't know why this line is uncovered */
|
|
5
|
-
|
|
5
|
+
const safeStringify = (value) => {
|
|
6
6
|
try {
|
|
7
7
|
return JSON.stringify(value);
|
|
8
8
|
}
|
|
@@ -12,7 +12,7 @@ var safeStringify = function (value) {
|
|
|
12
12
|
};
|
|
13
13
|
exports.safeStringify = safeStringify;
|
|
14
14
|
/* node:coverage ignore next - Don't know why this line is uncovered */
|
|
15
|
-
|
|
15
|
+
const safeParse = (value) => {
|
|
16
16
|
try {
|
|
17
17
|
return JSON.parse(value);
|
|
18
18
|
}
|
package/dist/esm/errors.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
var _a, _b;
|
|
2
1
|
export var ERROR;
|
|
3
2
|
(function (ERROR) {
|
|
4
3
|
ERROR["DEFAULT"] = "DEFAULT";
|
|
@@ -16,62 +15,64 @@ export var ERROR;
|
|
|
16
15
|
ERROR["LIMIT_ORDER_POST_ONLY"] = "LIMIT_ORDER_POST_ONLY";
|
|
17
16
|
ERROR["ORDER_ALREDY_EXISTS"] = "ORDER_ALREDY_EXISTS";
|
|
18
17
|
ERROR["ORDER_NOT_FOUND"] = "ORDER_NOT_FOUND";
|
|
18
|
+
ERROR["STP_TRIGGERED"] = "STP_TRIGGERED";
|
|
19
19
|
})(ERROR || (ERROR = {}));
|
|
20
|
-
export
|
|
20
|
+
export const ErrorCodes = {
|
|
21
21
|
// 10xx General issues
|
|
22
|
-
|
|
22
|
+
[ERROR.DEFAULT]: 1000,
|
|
23
23
|
// 11xx Request issues
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
24
|
+
[ERROR.INVALID_ORDER_TYPE]: 1100,
|
|
25
|
+
[ERROR.INVALID_SIDE]: 1101,
|
|
26
|
+
[ERROR.INVALID_QUANTITY]: 1102,
|
|
27
|
+
[ERROR.INVALID_PRICE]: 1103,
|
|
28
|
+
[ERROR.INVALID_PRICE_OR_QUANTITY]: 1104,
|
|
29
|
+
[ERROR.INVALID_TIF]: 1105,
|
|
30
|
+
[ERROR.LIMIT_ORDER_FOK_NOT_FILLABLE]: 1106,
|
|
31
|
+
[ERROR.LIMIT_ORDER_POST_ONLY]: 1107,
|
|
32
|
+
[ERROR.INVALID_CONDITIONAL_ORDER]: 1108,
|
|
33
|
+
[ERROR.ORDER_ALREDY_EXISTS]: 1109,
|
|
34
|
+
[ERROR.ORDER_NOT_FOUND]: 1110,
|
|
35
35
|
// 12xx Internal error
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
36
|
+
[ERROR.INSUFFICIENT_QUANTITY]: 1200,
|
|
37
|
+
[ERROR.INVALID_PRICE_LEVEL]: 1201,
|
|
38
|
+
[ERROR.INVALID_JOURNAL_LOG]: 1201,
|
|
39
|
+
[ERROR.STP_TRIGGERED]: 1202,
|
|
40
|
+
};
|
|
41
|
+
export const ErrorMessages = {
|
|
42
|
+
[ERROR.DEFAULT]: "Something wrong",
|
|
43
|
+
[ERROR.INSUFFICIENT_QUANTITY]: "Insufficient quantity to calculate price",
|
|
44
|
+
[ERROR.INVALID_CONDITIONAL_ORDER]: "Stop-Limit Order (BUY: marketPrice < stopPrice <= price, SELL: marketPrice > stopPrice >= price). Stop-Market Order (BUY: marketPrice < stopPrice, SELL: marketPrice > stopPrice). OCO order (BUY: price < marketPrice < stopPrice, SELL: price > marketPrice > stopPrice)",
|
|
45
|
+
[ERROR.INVALID_ORDER_TYPE]: "Supported order type are 'limit' and 'market'",
|
|
46
|
+
[ERROR.INVALID_PRICE]: "Invalid order price",
|
|
47
|
+
[ERROR.INVALID_PRICE_LEVEL]: "Invalid order price level",
|
|
48
|
+
[ERROR.INVALID_PRICE_OR_QUANTITY]: "Invalid order price or quantity",
|
|
49
|
+
[ERROR.INVALID_QUANTITY]: "Invalid order quantity",
|
|
50
|
+
[ERROR.INVALID_SIDE]: "Invalid side: must be either 'sell' or 'buy'",
|
|
51
|
+
[ERROR.INVALID_TIF]: "Invalid TimeInForce: must be one of 'GTC', 'IOC' or 'FOK'",
|
|
52
|
+
[ERROR.LIMIT_ORDER_FOK_NOT_FILLABLE]: "Limit FOK order not fillable",
|
|
53
|
+
[ERROR.LIMIT_ORDER_POST_ONLY]: "Post-only limit order rejected because would execute immediately",
|
|
54
|
+
[ERROR.ORDER_ALREDY_EXISTS]: "Order already exists",
|
|
55
|
+
[ERROR.ORDER_NOT_FOUND]: "Order not found",
|
|
56
|
+
[ERROR.INVALID_JOURNAL_LOG]: "Invalid journal log format",
|
|
57
|
+
[ERROR.STP_TRIGGERED]: "Self-trade prevention triggered",
|
|
58
|
+
};
|
|
59
|
+
export class OrderBookError {
|
|
60
|
+
message;
|
|
61
|
+
code;
|
|
62
|
+
constructor(error) {
|
|
63
|
+
let errorMessage;
|
|
61
64
|
if (error != null && ErrorMessages[error] != null) {
|
|
62
65
|
errorMessage = ErrorMessages[error];
|
|
63
66
|
}
|
|
64
67
|
else {
|
|
65
|
-
|
|
66
|
-
errorMessage =
|
|
68
|
+
const customMessage = error === undefined || error === "" ? "" : `: ${error}`;
|
|
69
|
+
errorMessage = `${ErrorMessages.DEFAULT}${customMessage}`;
|
|
67
70
|
}
|
|
68
71
|
this.message = errorMessage;
|
|
69
|
-
this.code =
|
|
72
|
+
this.code = ErrorCodes[error] ?? ErrorCodes[ERROR.DEFAULT];
|
|
70
73
|
}
|
|
71
|
-
|
|
72
|
-
}());
|
|
73
|
-
export { OrderBookError };
|
|
74
|
+
}
|
|
74
75
|
/* node:coverage ignore next - Don't know why this line is uncoverd */
|
|
75
|
-
export
|
|
76
|
+
export const CustomError = (error) => {
|
|
76
77
|
return new OrderBookError(error);
|
|
77
78
|
};
|
package/dist/esm/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* node:coverage disable */
|
|
2
2
|
import { OrderBook } from "./orderbook";
|
|
3
|
-
import { OrderType, Side } from "./types";
|
|
4
|
-
export { OrderBook, OrderType, Side, };
|
|
3
|
+
import { OrderType, SelfTradePreventionMode, Side } from "./types";
|
|
4
|
+
export { OrderBook, OrderType, SelfTradePreventionMode, Side, };
|
|
5
5
|
/* node:coverage enable */
|