nodejs-order-book 10.0.0 → 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 +317 -40
- 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 -782
- 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 +4 -5
- 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 -779
- 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 +4 -5
- package/dist/types/errors.d.ts +2 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/order.d.ts +5 -1
- package/dist/types/types.d.ts +24 -0
- package/dist/types/utils.d.ts +1 -1
- package/package.json +13 -12
package/dist/cjs/orderqueue.js
CHANGED
|
@@ -5,74 +5,76 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.OrderQueue = 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
|
-
this.toArray = function () {
|
|
18
|
-
return _this._orders.toArray();
|
|
19
|
-
};
|
|
20
|
-
// returns price level of the queue
|
|
21
|
-
this.price = function () {
|
|
22
|
-
return _this._price;
|
|
23
|
-
};
|
|
24
|
-
// returns price level of the queue
|
|
25
|
-
this.volume = function () {
|
|
26
|
-
return _this._volume;
|
|
27
|
-
};
|
|
28
|
-
// returns top order in queue
|
|
29
|
-
this.head = function () {
|
|
30
|
-
return _this._orders.peekFront();
|
|
31
|
-
};
|
|
32
|
-
// returns bottom order in queue
|
|
33
|
-
this.tail = function () {
|
|
34
|
-
return _this._orders.peekBack();
|
|
35
|
-
};
|
|
36
|
-
// adds order to tail of the queue
|
|
37
|
-
this.append = function (order) {
|
|
38
|
-
_this._volume += order.size;
|
|
39
|
-
_this._orders.push(order);
|
|
40
|
-
_this._ordersMap[order.id] = _this._orders.length - 1;
|
|
41
|
-
return order;
|
|
42
|
-
};
|
|
43
|
-
// sets up new order to list value
|
|
44
|
-
this.update = function (oldOrder, newOrder) {
|
|
45
|
-
_this._volume -= oldOrder.size;
|
|
46
|
-
_this._volume += newOrder.size;
|
|
47
|
-
// Remove old order from head
|
|
48
|
-
_this._orders.shift();
|
|
49
|
-
delete _this._ordersMap[oldOrder.id];
|
|
50
|
-
// Add new order to head
|
|
51
|
-
_this._orders.unshift(newOrder);
|
|
52
|
-
_this._ordersMap[newOrder.id] = 0;
|
|
53
|
-
};
|
|
54
|
-
// removes order from the queue
|
|
55
|
-
this.remove = function (order) {
|
|
56
|
-
_this._volume -= order.size;
|
|
57
|
-
var deletedOrderIndex = _this._ordersMap[order.id];
|
|
58
|
-
_this._orders.removeOne(deletedOrderIndex);
|
|
59
|
-
delete _this._ordersMap[order.id];
|
|
60
|
-
// Update all orders indexes where index is greater than the deleted one
|
|
61
|
-
for (var orderId in _this._ordersMap) {
|
|
62
|
-
if (_this._ordersMap[orderId] > deletedOrderIndex) {
|
|
63
|
-
_this._ordersMap[orderId] -= 1;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
this.updateOrderSize = function (order, size) {
|
|
68
|
-
_this._volume += size - order.size; // update volume
|
|
69
|
-
order.size = size;
|
|
70
|
-
order.time = Date.now();
|
|
71
|
-
};
|
|
8
|
+
const denque_1 = __importDefault(require("denque"));
|
|
9
|
+
class OrderQueue {
|
|
10
|
+
_price;
|
|
11
|
+
_volume;
|
|
12
|
+
// { orderID: index } index in denque
|
|
13
|
+
_orders;
|
|
14
|
+
_ordersMap = {};
|
|
15
|
+
constructor(price) {
|
|
72
16
|
this._price = price;
|
|
73
17
|
this._volume = 0;
|
|
74
18
|
this._orders = new denque_1.default();
|
|
75
19
|
}
|
|
76
|
-
|
|
77
|
-
|
|
20
|
+
// returns the number of orders in queue
|
|
21
|
+
len = () => {
|
|
22
|
+
return this._orders.length;
|
|
23
|
+
};
|
|
24
|
+
toArray = () => {
|
|
25
|
+
return this._orders.toArray();
|
|
26
|
+
};
|
|
27
|
+
// returns price level of the queue
|
|
28
|
+
price = () => {
|
|
29
|
+
return this._price;
|
|
30
|
+
};
|
|
31
|
+
// returns price level of the queue
|
|
32
|
+
volume = () => {
|
|
33
|
+
return this._volume;
|
|
34
|
+
};
|
|
35
|
+
// returns top order in queue
|
|
36
|
+
head = () => {
|
|
37
|
+
return this._orders.peekFront();
|
|
38
|
+
};
|
|
39
|
+
// returns bottom order in queue
|
|
40
|
+
tail = () => {
|
|
41
|
+
return this._orders.peekBack();
|
|
42
|
+
};
|
|
43
|
+
// adds order to tail of the queue
|
|
44
|
+
append = (order) => {
|
|
45
|
+
this._volume += order.size;
|
|
46
|
+
this._orders.push(order);
|
|
47
|
+
this._ordersMap[order.id] = this._orders.length - 1;
|
|
48
|
+
return order;
|
|
49
|
+
};
|
|
50
|
+
// sets up new order to list value
|
|
51
|
+
update = (oldOrder, newOrder) => {
|
|
52
|
+
this._volume -= oldOrder.size;
|
|
53
|
+
this._volume += newOrder.size;
|
|
54
|
+
// Remove old order from head
|
|
55
|
+
this._orders.shift();
|
|
56
|
+
delete this._ordersMap[oldOrder.id];
|
|
57
|
+
// Add new order to head
|
|
58
|
+
this._orders.unshift(newOrder);
|
|
59
|
+
this._ordersMap[newOrder.id] = 0;
|
|
60
|
+
};
|
|
61
|
+
// removes order from the queue
|
|
62
|
+
remove = (order) => {
|
|
63
|
+
this._volume -= order.size;
|
|
64
|
+
const deletedOrderIndex = this._ordersMap[order.id];
|
|
65
|
+
this._orders.removeOne(deletedOrderIndex);
|
|
66
|
+
delete this._ordersMap[order.id];
|
|
67
|
+
// Update all orders indexes where index is greater than the deleted one
|
|
68
|
+
for (const orderId in this._ordersMap) {
|
|
69
|
+
if (this._ordersMap[orderId] > deletedOrderIndex) {
|
|
70
|
+
this._ordersMap[orderId] -= 1;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
updateOrderSize = (order, size) => {
|
|
75
|
+
this._volume += size - order.size; // update volume
|
|
76
|
+
order.size = size;
|
|
77
|
+
order.time = Date.now();
|
|
78
|
+
};
|
|
79
|
+
}
|
|
78
80
|
exports.OrderQueue = OrderQueue;
|
package/dist/cjs/orderside.js
CHANGED
|
@@ -1,158 +1,150 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __assign = (this && this.__assign) || function () {
|
|
3
|
-
__assign = Object.assign || function(t) {
|
|
4
|
-
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
-
s = arguments[i];
|
|
6
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
-
t[p] = s[p];
|
|
8
|
-
}
|
|
9
|
-
return t;
|
|
10
|
-
};
|
|
11
|
-
return __assign.apply(this, arguments);
|
|
12
|
-
};
|
|
13
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
4
|
};
|
|
16
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
6
|
exports.OrderSide = void 0;
|
|
18
7
|
/* node:coverage ignore next - Don't know why first and last line of each file count as uncovered */
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
};
|
|
37
|
-
// returns depth of market
|
|
38
|
-
this.depth = function () {
|
|
39
|
-
return _this._depthSide;
|
|
40
|
-
};
|
|
41
|
-
// returns total amount of quantity in side
|
|
42
|
-
this.volume = function () {
|
|
43
|
-
return _this._volume;
|
|
44
|
-
};
|
|
45
|
-
// returns the total (size * price of each price level) in side
|
|
46
|
-
this.total = function () {
|
|
47
|
-
return _this._total;
|
|
48
|
-
};
|
|
49
|
-
// returns the price tree in side
|
|
50
|
-
this.priceTree = function () {
|
|
51
|
-
return _this._priceTree;
|
|
52
|
-
};
|
|
53
|
-
// appends order to definite price level
|
|
54
|
-
this.append = function (order) {
|
|
55
|
-
var price = order.price;
|
|
56
|
-
var strPrice = price.toString();
|
|
57
|
-
if (_this._prices[strPrice] === undefined) {
|
|
58
|
-
var priceQueue = new orderqueue_1.OrderQueue(price);
|
|
59
|
-
_this._prices[strPrice] = priceQueue;
|
|
60
|
-
_this._priceTree = _this._priceTree.insert(price, priceQueue);
|
|
61
|
-
_this._depthSide += 1;
|
|
62
|
-
}
|
|
63
|
-
_this._numOrders += 1;
|
|
64
|
-
_this._volume += order.size;
|
|
65
|
-
_this._total += order.size * order.price;
|
|
66
|
-
return _this._prices[strPrice].append(order);
|
|
67
|
-
};
|
|
68
|
-
// removes order from definite price level
|
|
69
|
-
this.remove = function (order) {
|
|
70
|
-
var price = order.price;
|
|
71
|
-
var strPrice = price.toString();
|
|
72
|
-
if (_this._prices[strPrice] === undefined) {
|
|
73
|
-
throw (0, errors_1.CustomError)(errors_1.ERROR.INVALID_PRICE_LEVEL);
|
|
74
|
-
}
|
|
75
|
-
_this._prices[strPrice].remove(order);
|
|
76
|
-
if (_this._prices[strPrice].len() === 0) {
|
|
77
|
-
delete _this._prices[strPrice];
|
|
78
|
-
_this._priceTree = _this._priceTree.remove(price);
|
|
79
|
-
_this._depthSide -= 1;
|
|
80
|
-
}
|
|
81
|
-
_this._numOrders -= 1;
|
|
82
|
-
_this._volume -= order.size;
|
|
83
|
-
_this._total -= order.size * order.price;
|
|
84
|
-
return order;
|
|
85
|
-
};
|
|
86
|
-
// Update the price of an order and return the order with the updated price
|
|
87
|
-
this.updateOrderPrice = function (oldOrder, orderUpdate) {
|
|
88
|
-
_this.remove(oldOrder);
|
|
89
|
-
var newOrder = order_1.OrderFactory.createOrder(__assign(__assign({}, oldOrder.toObject()), { size: orderUpdate.size !== undefined ? orderUpdate.size : oldOrder.size, price: orderUpdate.price, time: Date.now() }));
|
|
90
|
-
_this.append(newOrder);
|
|
91
|
-
return newOrder;
|
|
92
|
-
};
|
|
93
|
-
// Update the price of an order and return the order with the updated price
|
|
94
|
-
this.updateOrderSize = function (oldOrder, orderUpdate) {
|
|
95
|
-
var _a;
|
|
96
|
-
var newOrderPrice = (_a = orderUpdate.price) !== null && _a !== void 0 ? _a : oldOrder.price;
|
|
97
|
-
_this._volume += orderUpdate.size - oldOrder.size;
|
|
98
|
-
_this._total +=
|
|
99
|
-
orderUpdate.size * newOrderPrice - oldOrder.size * oldOrder.price;
|
|
100
|
-
_this._prices[oldOrder.price.toString()].updateOrderSize(oldOrder, orderUpdate.size);
|
|
101
|
-
return oldOrder;
|
|
102
|
-
};
|
|
103
|
-
// returns max level of price
|
|
104
|
-
this.maxPriceQueue = function () {
|
|
105
|
-
if (_this._depthSide > 0) {
|
|
106
|
-
var max = _this._side === types_1.Side.SELL ? _this._priceTree.end : _this._priceTree.begin;
|
|
107
|
-
return max.value;
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
// returns min level of price
|
|
111
|
-
this.minPriceQueue = function () {
|
|
112
|
-
if (_this._depthSide > 0) {
|
|
113
|
-
var min = _this._side === types_1.Side.SELL ? _this._priceTree.begin : _this._priceTree.end;
|
|
114
|
-
return min.value;
|
|
115
|
-
}
|
|
116
|
-
};
|
|
117
|
-
// returns nearest OrderQueue with price less than given
|
|
118
|
-
this.lowerThan = function (price) {
|
|
119
|
-
var node = _this._side === types_1.Side.SELL
|
|
120
|
-
? _this._priceTree.lt(price)
|
|
121
|
-
: _this._priceTree.gt(price);
|
|
122
|
-
return node.value;
|
|
123
|
-
};
|
|
124
|
-
// returns nearest OrderQueue with price greater than given
|
|
125
|
-
this.greaterThan = function (price) {
|
|
126
|
-
var node = _this._side === types_1.Side.SELL
|
|
127
|
-
? _this._priceTree.gt(price)
|
|
128
|
-
: _this._priceTree.lt(price);
|
|
129
|
-
return node.value;
|
|
130
|
-
};
|
|
131
|
-
// returns all orders
|
|
132
|
-
this.orders = function () {
|
|
133
|
-
var orders = [];
|
|
134
|
-
for (var price in _this._prices) {
|
|
135
|
-
var allOrders = _this._prices[price].toArray();
|
|
136
|
-
orders = orders.concat(allOrders);
|
|
137
|
-
}
|
|
138
|
-
return orders;
|
|
139
|
-
};
|
|
140
|
-
this.toString = function () {
|
|
141
|
-
var s = "";
|
|
142
|
-
var level = _this.maxPriceQueue();
|
|
143
|
-
while (level !== undefined) {
|
|
144
|
-
var volume = level.volume().toString();
|
|
145
|
-
s += "\n".concat(level.price(), " -> ").concat(volume);
|
|
146
|
-
level = _this.lowerThan(level.price());
|
|
147
|
-
}
|
|
148
|
-
return s;
|
|
149
|
-
};
|
|
150
|
-
var compare = side === types_1.Side.SELL
|
|
151
|
-
? function (a, b) { return a - b; }
|
|
152
|
-
: 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 order_1 = require("./order");
|
|
11
|
+
const orderqueue_1 = require("./orderqueue");
|
|
12
|
+
const types_1 = require("./types");
|
|
13
|
+
class OrderSide {
|
|
14
|
+
_priceTree;
|
|
15
|
+
_prices = {};
|
|
16
|
+
_volume = 0;
|
|
17
|
+
_total = 0;
|
|
18
|
+
_numOrders = 0;
|
|
19
|
+
_depthSide = 0;
|
|
20
|
+
_side = types_1.Side.SELL;
|
|
21
|
+
constructor(side) {
|
|
22
|
+
const compare = side === types_1.Side.SELL
|
|
23
|
+
? (a, b) => a - b
|
|
24
|
+
: (a, b) => b - a;
|
|
153
25
|
this._priceTree = (0, functional_red_black_tree_1.default)(compare);
|
|
154
26
|
this._side = side;
|
|
155
27
|
}
|
|
156
|
-
|
|
157
|
-
|
|
28
|
+
// returns amount of orders
|
|
29
|
+
len = () => {
|
|
30
|
+
return this._numOrders;
|
|
31
|
+
};
|
|
32
|
+
// returns depth of market
|
|
33
|
+
depth = () => {
|
|
34
|
+
return this._depthSide;
|
|
35
|
+
};
|
|
36
|
+
// returns total amount of quantity in side
|
|
37
|
+
volume = () => {
|
|
38
|
+
return this._volume;
|
|
39
|
+
};
|
|
40
|
+
// returns the total (size * price of each price level) in side
|
|
41
|
+
total = () => {
|
|
42
|
+
return this._total;
|
|
43
|
+
};
|
|
44
|
+
// returns the price tree in side
|
|
45
|
+
priceTree = () => {
|
|
46
|
+
return this._priceTree;
|
|
47
|
+
};
|
|
48
|
+
// appends order to definite price level
|
|
49
|
+
append = (order) => {
|
|
50
|
+
const price = order.price;
|
|
51
|
+
const strPrice = price.toString();
|
|
52
|
+
if (this._prices[strPrice] === undefined) {
|
|
53
|
+
const priceQueue = new orderqueue_1.OrderQueue(price);
|
|
54
|
+
this._prices[strPrice] = priceQueue;
|
|
55
|
+
this._priceTree = this._priceTree.insert(price, priceQueue);
|
|
56
|
+
this._depthSide += 1;
|
|
57
|
+
}
|
|
58
|
+
this._numOrders += 1;
|
|
59
|
+
this._volume += order.size;
|
|
60
|
+
this._total += order.size * order.price;
|
|
61
|
+
return this._prices[strPrice].append(order);
|
|
62
|
+
};
|
|
63
|
+
// removes order from definite price level
|
|
64
|
+
remove = (order) => {
|
|
65
|
+
const price = order.price;
|
|
66
|
+
const strPrice = price.toString();
|
|
67
|
+
if (this._prices[strPrice] === undefined) {
|
|
68
|
+
throw (0, errors_1.CustomError)(errors_1.ERROR.INVALID_PRICE_LEVEL);
|
|
69
|
+
}
|
|
70
|
+
this._prices[strPrice].remove(order);
|
|
71
|
+
if (this._prices[strPrice].len() === 0) {
|
|
72
|
+
delete this._prices[strPrice];
|
|
73
|
+
this._priceTree = this._priceTree.remove(price);
|
|
74
|
+
this._depthSide -= 1;
|
|
75
|
+
}
|
|
76
|
+
this._numOrders -= 1;
|
|
77
|
+
this._volume -= order.size;
|
|
78
|
+
this._total -= order.size * order.price;
|
|
79
|
+
return order;
|
|
80
|
+
};
|
|
81
|
+
// Update the price of an order and return the order with the updated price
|
|
82
|
+
updateOrderPrice = (oldOrder, orderUpdate) => {
|
|
83
|
+
this.remove(oldOrder);
|
|
84
|
+
const newOrder = order_1.OrderFactory.createOrder({
|
|
85
|
+
...oldOrder.toObject(),
|
|
86
|
+
size: orderUpdate.size !== undefined ? orderUpdate.size : oldOrder.size,
|
|
87
|
+
price: orderUpdate.price,
|
|
88
|
+
time: Date.now(),
|
|
89
|
+
});
|
|
90
|
+
this.append(newOrder);
|
|
91
|
+
return newOrder;
|
|
92
|
+
};
|
|
93
|
+
// Update the price of an order and return the order with the updated price
|
|
94
|
+
updateOrderSize = (oldOrder, orderUpdate) => {
|
|
95
|
+
const newOrderPrice = orderUpdate.price ?? oldOrder.price;
|
|
96
|
+
this._volume += orderUpdate.size - oldOrder.size;
|
|
97
|
+
this._total +=
|
|
98
|
+
orderUpdate.size * newOrderPrice - oldOrder.size * oldOrder.price;
|
|
99
|
+
this._prices[oldOrder.price.toString()].updateOrderSize(oldOrder, orderUpdate.size);
|
|
100
|
+
return oldOrder;
|
|
101
|
+
};
|
|
102
|
+
// returns max level of price
|
|
103
|
+
maxPriceQueue = () => {
|
|
104
|
+
if (this._depthSide > 0) {
|
|
105
|
+
const max = this._side === types_1.Side.SELL ? this._priceTree.end : this._priceTree.begin;
|
|
106
|
+
return max.value;
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
// returns min level of price
|
|
110
|
+
minPriceQueue = () => {
|
|
111
|
+
if (this._depthSide > 0) {
|
|
112
|
+
const min = this._side === types_1.Side.SELL ? this._priceTree.begin : this._priceTree.end;
|
|
113
|
+
return min.value;
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
// returns nearest OrderQueue with price less than given
|
|
117
|
+
lowerThan = (price) => {
|
|
118
|
+
const node = this._side === types_1.Side.SELL
|
|
119
|
+
? this._priceTree.lt(price)
|
|
120
|
+
: this._priceTree.gt(price);
|
|
121
|
+
return node.value;
|
|
122
|
+
};
|
|
123
|
+
// returns nearest OrderQueue with price greater than given
|
|
124
|
+
greaterThan = (price) => {
|
|
125
|
+
const node = this._side === types_1.Side.SELL
|
|
126
|
+
? this._priceTree.gt(price)
|
|
127
|
+
: this._priceTree.lt(price);
|
|
128
|
+
return node.value;
|
|
129
|
+
};
|
|
130
|
+
// returns all orders
|
|
131
|
+
orders = () => {
|
|
132
|
+
let orders = [];
|
|
133
|
+
for (const price in this._prices) {
|
|
134
|
+
const allOrders = this._prices[price].toArray();
|
|
135
|
+
orders = orders.concat(allOrders);
|
|
136
|
+
}
|
|
137
|
+
return orders;
|
|
138
|
+
};
|
|
139
|
+
toString = () => {
|
|
140
|
+
let s = "";
|
|
141
|
+
let level = this.maxPriceQueue();
|
|
142
|
+
while (level !== undefined) {
|
|
143
|
+
const volume = level.volume().toString();
|
|
144
|
+
s += `\n${level.price()} -> ${volume}`;
|
|
145
|
+
level = this.lowerThan(level.price());
|
|
146
|
+
}
|
|
147
|
+
return s;
|
|
148
|
+
};
|
|
149
|
+
}
|
|
158
150
|
exports.OrderSide = OrderSide;
|
package/dist/cjs/stopbook.js
CHANGED
|
@@ -1,76 +1,76 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.StopBook = void 0;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
var stopSide = order.side === types_1.Side.BUY ? _this.bids : _this.asks;
|
|
11
|
-
stopSide.append(order);
|
|
12
|
-
};
|
|
13
|
-
this.remove = function (side, id, stopPrice) {
|
|
14
|
-
var stopSide = side === types_1.Side.BUY ? _this.bids : _this.asks;
|
|
15
|
-
return stopSide.remove(id, stopPrice);
|
|
16
|
-
};
|
|
17
|
-
this.removePriceLevel = function (side, priceLevel) {
|
|
18
|
-
var stopSide = side === types_1.Side.BUY ? _this.bids : _this.asks;
|
|
19
|
-
stopSide.removePriceLevel(priceLevel);
|
|
20
|
-
};
|
|
21
|
-
this.getConditionalOrders = function (side, priceBefore, marketPrice) {
|
|
22
|
-
var stopSide = side === types_1.Side.BUY ? _this.bids : _this.asks;
|
|
23
|
-
return stopSide.between(priceBefore, marketPrice);
|
|
24
|
-
};
|
|
25
|
-
/**
|
|
26
|
-
* Stop-Limit Order:
|
|
27
|
-
* Buy: marketPrice < stopPrice <= price
|
|
28
|
-
* Sell: marketPrice > stopPrice >= price
|
|
29
|
-
* Stop-Market Order:
|
|
30
|
-
* Buy: marketPrice < stopPrice
|
|
31
|
-
* Sell: marketPrice > stopPrice
|
|
32
|
-
*/
|
|
33
|
-
this.validConditionalOrder = function (marketPrice, order) {
|
|
34
|
-
var response = false;
|
|
35
|
-
var type = order.type, side = order.side, stopPrice = order.stopPrice;
|
|
36
|
-
if (type === types_1.OrderType.STOP_LIMIT) {
|
|
37
|
-
// Buy: marketPrice < stopPrice <= price
|
|
38
|
-
if (side === types_1.Side.BUY &&
|
|
39
|
-
marketPrice < stopPrice &&
|
|
40
|
-
stopPrice <= order.price) {
|
|
41
|
-
response = true;
|
|
42
|
-
}
|
|
43
|
-
// Sell: marketPrice > stopPrice >= price
|
|
44
|
-
if (side === types_1.Side.SELL &&
|
|
45
|
-
marketPrice > stopPrice &&
|
|
46
|
-
stopPrice >= order.price) {
|
|
47
|
-
response = true;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
// Buy: marketPrice < stopPrice
|
|
52
|
-
if (side === types_1.Side.BUY && marketPrice < stopPrice)
|
|
53
|
-
response = true;
|
|
54
|
-
// Sell: marketPrice > stopPrice
|
|
55
|
-
if (side === types_1.Side.SELL && marketPrice > stopPrice)
|
|
56
|
-
response = true;
|
|
57
|
-
}
|
|
58
|
-
return response;
|
|
59
|
-
};
|
|
60
|
-
this.snapshot = function () {
|
|
61
|
-
var bids = [];
|
|
62
|
-
var asks = [];
|
|
63
|
-
_this.bids.priceTree().forEach(function (price, orders) {
|
|
64
|
-
bids.push({ price: price, orders: orders.toArray().map(function (o) { return o.toObject(); }) });
|
|
65
|
-
});
|
|
66
|
-
_this.asks.priceTree().forEach(function (price, orders) {
|
|
67
|
-
asks.push({ price: price, orders: orders.toArray().map(function (o) { return o.toObject(); }) });
|
|
68
|
-
});
|
|
69
|
-
return { bids: bids, asks: asks };
|
|
70
|
-
};
|
|
4
|
+
const stopside_1 = require("./stopside");
|
|
5
|
+
const types_1 = require("./types");
|
|
6
|
+
class StopBook {
|
|
7
|
+
bids;
|
|
8
|
+
asks;
|
|
9
|
+
constructor() {
|
|
71
10
|
this.bids = new stopside_1.StopSide(types_1.Side.BUY);
|
|
72
11
|
this.asks = new stopside_1.StopSide(types_1.Side.SELL);
|
|
73
12
|
}
|
|
74
|
-
|
|
75
|
-
|
|
13
|
+
add = (order) => {
|
|
14
|
+
const stopSide = order.side === types_1.Side.BUY ? this.bids : this.asks;
|
|
15
|
+
stopSide.append(order);
|
|
16
|
+
};
|
|
17
|
+
remove = (side, id, stopPrice) => {
|
|
18
|
+
const stopSide = side === types_1.Side.BUY ? this.bids : this.asks;
|
|
19
|
+
return stopSide.remove(id, stopPrice);
|
|
20
|
+
};
|
|
21
|
+
removePriceLevel = (side, priceLevel) => {
|
|
22
|
+
const stopSide = side === types_1.Side.BUY ? this.bids : this.asks;
|
|
23
|
+
stopSide.removePriceLevel(priceLevel);
|
|
24
|
+
};
|
|
25
|
+
getConditionalOrders = (side, priceBefore, marketPrice) => {
|
|
26
|
+
const stopSide = side === types_1.Side.BUY ? this.bids : this.asks;
|
|
27
|
+
return stopSide.between(priceBefore, marketPrice);
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Stop-Limit Order:
|
|
31
|
+
* Buy: marketPrice < stopPrice <= price
|
|
32
|
+
* Sell: marketPrice > stopPrice >= price
|
|
33
|
+
* Stop-Market Order:
|
|
34
|
+
* Buy: marketPrice < stopPrice
|
|
35
|
+
* Sell: marketPrice > stopPrice
|
|
36
|
+
*/
|
|
37
|
+
validConditionalOrder = (marketPrice, order) => {
|
|
38
|
+
let response = false;
|
|
39
|
+
const { type, side, stopPrice } = order;
|
|
40
|
+
if (type === types_1.OrderType.STOP_LIMIT) {
|
|
41
|
+
// Buy: marketPrice < stopPrice <= price
|
|
42
|
+
if (side === types_1.Side.BUY &&
|
|
43
|
+
marketPrice < stopPrice &&
|
|
44
|
+
stopPrice <= order.price) {
|
|
45
|
+
response = true;
|
|
46
|
+
}
|
|
47
|
+
// Sell: marketPrice > stopPrice >= price
|
|
48
|
+
if (side === types_1.Side.SELL &&
|
|
49
|
+
marketPrice > stopPrice &&
|
|
50
|
+
stopPrice >= order.price) {
|
|
51
|
+
response = true;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
// Buy: marketPrice < stopPrice
|
|
56
|
+
if (side === types_1.Side.BUY && marketPrice < stopPrice)
|
|
57
|
+
response = true;
|
|
58
|
+
// Sell: marketPrice > stopPrice
|
|
59
|
+
if (side === types_1.Side.SELL && marketPrice > stopPrice)
|
|
60
|
+
response = true;
|
|
61
|
+
}
|
|
62
|
+
return response;
|
|
63
|
+
};
|
|
64
|
+
snapshot = () => {
|
|
65
|
+
const bids = [];
|
|
66
|
+
const asks = [];
|
|
67
|
+
this.bids.priceTree().forEach((price, orders) => {
|
|
68
|
+
bids.push({ price, orders: orders.toArray().map((o) => o.toObject()) });
|
|
69
|
+
});
|
|
70
|
+
this.asks.priceTree().forEach((price, orders) => {
|
|
71
|
+
asks.push({ price, orders: orders.toArray().map((o) => o.toObject()) });
|
|
72
|
+
});
|
|
73
|
+
return { bids, asks };
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
76
|
exports.StopBook = StopBook;
|
package/dist/cjs/stopqueue.js
CHANGED
|
@@ -5,58 +5,54 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.StopQueue = 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
|
-
this.len = function () {
|
|
15
|
-
return _this._orders.length;
|
|
16
|
-
};
|
|
17
|
-
// remove order from head of queue
|
|
18
|
-
this.removeFromHead = function () {
|
|
19
|
-
// We can't use the shift method here because we need
|
|
20
|
-
// to update index in the map, so we use the remove(id) function
|
|
21
|
-
var order = _this._orders.peekFront();
|
|
22
|
-
if (order === undefined)
|
|
23
|
-
return;
|
|
24
|
-
return _this.remove(order.id);
|
|
25
|
-
};
|
|
26
|
-
// adds order to tail of the queue
|
|
27
|
-
this.append = function (order) {
|
|
28
|
-
_this._orders.push(order);
|
|
29
|
-
_this._ordersMap[order.id] = _this._orders.length - 1;
|
|
30
|
-
return order;
|
|
31
|
-
};
|
|
32
|
-
// removes order from the queue
|
|
33
|
-
this.remove = function (id) {
|
|
34
|
-
var deletedOrderIndex = _this._ordersMap[id];
|
|
35
|
-
if (deletedOrderIndex === undefined)
|
|
36
|
-
return;
|
|
37
|
-
var deletedOrder = _this._orders.removeOne(deletedOrderIndex);
|
|
38
|
-
delete _this._ordersMap[id];
|
|
39
|
-
// Update all orders indexes where index is greater than the deleted one
|
|
40
|
-
for (var orderId in _this._ordersMap) {
|
|
41
|
-
if (_this._ordersMap[orderId] > deletedOrderIndex) {
|
|
42
|
-
_this._ordersMap[orderId] -= 1;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return deletedOrder;
|
|
46
|
-
};
|
|
47
|
-
this.toArray = function () {
|
|
48
|
-
return _this._orders.toArray();
|
|
49
|
-
};
|
|
8
|
+
const denque_1 = __importDefault(require("denque"));
|
|
9
|
+
class StopQueue {
|
|
10
|
+
_price;
|
|
11
|
+
_orders;
|
|
12
|
+
_ordersMap = {};
|
|
13
|
+
constructor(price) {
|
|
50
14
|
this._price = price;
|
|
51
15
|
this._orders = new denque_1.default();
|
|
52
16
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
17
|
+
get price() {
|
|
18
|
+
return this._price;
|
|
19
|
+
}
|
|
20
|
+
// returns the number of orders in queue
|
|
21
|
+
len = () => {
|
|
22
|
+
return this._orders.length;
|
|
23
|
+
};
|
|
24
|
+
// remove order from head of queue
|
|
25
|
+
removeFromHead = () => {
|
|
26
|
+
// We can't use the shift method here because we need
|
|
27
|
+
// to update index in the map, so we use the remove(id) function
|
|
28
|
+
const order = this._orders.peekFront();
|
|
29
|
+
if (order === undefined)
|
|
30
|
+
return;
|
|
31
|
+
return this.remove(order.id);
|
|
32
|
+
};
|
|
33
|
+
// adds order to tail of the queue
|
|
34
|
+
append = (order) => {
|
|
35
|
+
this._orders.push(order);
|
|
36
|
+
this._ordersMap[order.id] = this._orders.length - 1;
|
|
37
|
+
return order;
|
|
38
|
+
};
|
|
39
|
+
// removes order from the queue
|
|
40
|
+
remove = (id) => {
|
|
41
|
+
const deletedOrderIndex = this._ordersMap[id];
|
|
42
|
+
if (deletedOrderIndex === undefined)
|
|
43
|
+
return;
|
|
44
|
+
const deletedOrder = this._orders.removeOne(deletedOrderIndex);
|
|
45
|
+
delete this._ordersMap[id];
|
|
46
|
+
// Update all orders indexes where index is greater than the deleted one
|
|
47
|
+
for (const orderId in this._ordersMap) {
|
|
48
|
+
if (this._ordersMap[orderId] > deletedOrderIndex) {
|
|
49
|
+
this._ordersMap[orderId] -= 1;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return deletedOrder;
|
|
53
|
+
};
|
|
54
|
+
toArray = () => {
|
|
55
|
+
return this._orders.toArray();
|
|
56
|
+
};
|
|
57
|
+
}
|
|
62
58
|
exports.StopQueue = StopQueue;
|