@drift-labs/sdk 0.2.0-master.26 → 0.2.0-master.28
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/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +1 -0
- package/lib/accounts/pollingClearingHouseAccountSubscriber.js +3 -0
- package/lib/accounts/types.d.ts +2 -0
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +1 -0
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +3 -0
- package/lib/admin.d.ts +5 -2
- package/lib/admin.js +30 -4
- package/lib/clearingHouse.d.ts +3 -0
- package/lib/clearingHouse.js +19 -1
- package/lib/clearingHouseUser.d.ts +11 -9
- package/lib/clearingHouseUser.js +184 -108
- package/lib/config.js +1 -1
- package/lib/dlob/DLOB.d.ts +73 -0
- package/lib/dlob/DLOB.js +557 -0
- package/lib/dlob/DLOBNode.d.ts +52 -0
- package/lib/dlob/DLOBNode.js +82 -0
- package/lib/dlob/NodeList.d.ts +26 -0
- package/lib/dlob/NodeList.js +138 -0
- package/lib/idl/clearing_house.json +123 -203
- package/lib/index.d.ts +5 -0
- package/lib/index.js +5 -0
- package/lib/math/market.d.ts +3 -2
- package/lib/math/market.js +17 -12
- package/lib/math/orders.d.ts +3 -3
- package/lib/math/orders.js +31 -16
- package/lib/math/position.d.ts +3 -3
- package/lib/math/position.js +23 -16
- package/lib/math/repeg.js +8 -0
- package/lib/math/spotBalance.d.ts +3 -0
- package/lib/math/spotBalance.js +18 -1
- package/lib/math/spotPosition.d.ts +5 -1
- package/lib/math/spotPosition.js +16 -1
- package/lib/types.d.ts +25 -24
- package/lib/types.js +9 -3
- package/lib/userMap/userMap.d.ts +25 -0
- package/lib/userMap/userMap.js +73 -0
- package/lib/userMap/userStatsMap.d.ts +19 -0
- package/lib/userMap/userStatsMap.js +68 -0
- package/package.json +6 -3
- package/src/accounts/pollingClearingHouseAccountSubscriber.ts +4 -0
- package/src/accounts/types.ts +1 -0
- package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +6 -0
- package/src/admin.ts +50 -8
- package/src/clearingHouse.ts +30 -1
- package/src/clearingHouseUser.ts +366 -167
- package/src/config.ts +1 -1
- package/src/dlob/DLOB.ts +884 -0
- package/src/dlob/DLOBNode.ts +163 -0
- package/src/dlob/NodeList.ts +185 -0
- package/src/idl/clearing_house.json +123 -203
- package/src/index.ts +5 -0
- package/src/math/market.ts +22 -13
- package/src/math/orders.ts +29 -21
- package/src/math/position.ts +36 -22
- package/src/math/repeg.ts +9 -0
- package/src/math/spotBalance.ts +26 -0
- package/src/math/spotPosition.ts +42 -1
- package/src/types.ts +26 -24
- package/src/userMap/userMap.ts +100 -0
- package/src/userMap/userStatsMap.ts +110 -0
- package/tests/bn/test.ts +2 -3
- package/tests/dlob/helpers.ts +322 -0
- package/tests/dlob/test.ts +2865 -0
- package/my-script/.env +0 -7
- package/my-script/getUserStats.ts +0 -106
- package/my-script/multiConnections.ts +0 -119
- package/my-script/test-regex.ts +0 -11
- package/my-script/utils.ts +0 -52
- package/src/accounts/bulkAccountLoader.js +0 -249
- package/src/accounts/bulkUserStatsSubscription.js +0 -75
- package/src/accounts/bulkUserSubscription.js +0 -75
- package/src/accounts/fetch.js +0 -92
- package/src/accounts/pollingClearingHouseAccountSubscriber.js +0 -465
- package/src/accounts/pollingOracleSubscriber.js +0 -156
- package/src/accounts/pollingTokenAccountSubscriber.js +0 -141
- package/src/accounts/pollingUserAccountSubscriber.js +0 -208
- package/src/accounts/pollingUserStatsAccountSubscriber.js +0 -208
- package/src/accounts/types.js +0 -28
- package/src/accounts/utils.js +0 -7
- package/src/accounts/webSocketAccountSubscriber.js +0 -138
- package/src/accounts/webSocketClearingHouseAccountSubscriber.js +0 -433
- package/src/accounts/webSocketUserAccountSubscriber.js +0 -113
- package/src/accounts/webSocketUserStatsAccountSubsriber.js +0 -113
- package/src/addresses/pda.js +0 -186
- package/src/admin.js +0 -1284
- package/src/assert/assert.js +0 -9
- package/src/clearingHouse.js +0 -3433
- package/src/clearingHouseConfig.js +0 -2
- package/src/clearingHouseUser.js +0 -874
- package/src/clearingHouseUserConfig.js +0 -2
- package/src/clearingHouseUserStats.js +0 -115
- package/src/clearingHouseUserStatsConfig.js +0 -2
- package/src/config.js +0 -80
- package/src/constants/numericConstants.js +0 -48
- package/src/constants/perpMarkets.js +0 -42
- package/src/constants/spotMarkets.js +0 -51
- package/src/events/eventList.js +0 -120
- package/src/events/eventSubscriber.js +0 -202
- package/src/events/fetchLogs.js +0 -117
- package/src/events/pollingLogProvider.js +0 -113
- package/src/events/sort.js +0 -41
- package/src/events/txEventCache.js +0 -74
- package/src/events/types.js +0 -25
- package/src/events/webSocketLogProvider.js +0 -76
- package/src/factory/bigNum.js +0 -393
- package/src/factory/oracleClient.js +0 -20
- package/src/index.js +0 -75
- package/src/math/amm.js +0 -422
- package/src/math/auction.js +0 -42
- package/src/math/conversion.js +0 -12
- package/src/math/funding.js +0 -296
- package/src/math/insurance.js +0 -27
- package/src/math/margin.js +0 -77
- package/src/math/market.js +0 -105
- package/src/math/oracles.js +0 -56
- package/src/math/orders.js +0 -153
- package/src/math/position.js +0 -172
- package/src/math/repeg.js +0 -128
- package/src/math/spotBalance.js +0 -176
- package/src/math/spotMarket.js +0 -8
- package/src/math/spotPosition.js +0 -8
- package/src/math/trade.js +0 -260
- package/src/math/utils.js +0 -27
- package/src/oracles/oracleClientCache.js +0 -20
- package/src/oracles/pythClient.js +0 -81
- package/src/oracles/quoteAssetOracleClient.js +0 -63
- package/src/oracles/switchboardClient.js +0 -101
- package/src/oracles/types.js +0 -2
- package/src/orderParams.js +0 -28
- package/src/serum/serumSubscriber.js +0 -102
- package/src/serum/types.js +0 -2
- package/src/slot/SlotSubscriber.js +0 -86
- package/src/token/index.js +0 -38
- package/src/tokenFaucet.js +0 -323
- package/src/tx/retryTxSender.js +0 -280
- package/src/tx/types.js +0 -2
- package/src/tx/utils.js +0 -18
- package/src/types.js +0 -216
- package/src/userName.js +0 -20
- package/src/util/computeUnits.js +0 -62
- package/src/util/promiseTimeout.js +0 -14
- package/src/util/tps.js +0 -61
- package/src/wallet.js +0 -72
|
@@ -0,0 +1,2865 @@
|
|
|
1
|
+
import { expect } from 'chai';
|
|
2
|
+
import { PublicKey, Keypair } from '@solana/web3.js';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
getVariant,
|
|
6
|
+
MarketType,
|
|
7
|
+
DLOB,
|
|
8
|
+
BN,
|
|
9
|
+
BASE_PRECISION,
|
|
10
|
+
PositionDirection,
|
|
11
|
+
OrderStatus,
|
|
12
|
+
OrderType,
|
|
13
|
+
OrderTriggerCondition,
|
|
14
|
+
} from '../../src';
|
|
15
|
+
|
|
16
|
+
import { mockPerpMarkets, mockSpotMarkets } from './helpers';
|
|
17
|
+
|
|
18
|
+
function insertOrderToDLOB(
|
|
19
|
+
dlob: DLOB,
|
|
20
|
+
userAccount: PublicKey,
|
|
21
|
+
orderType: OrderType,
|
|
22
|
+
marketType: MarketType,
|
|
23
|
+
orderId: BN,
|
|
24
|
+
marketIndex: BN,
|
|
25
|
+
price: BN,
|
|
26
|
+
baseAssetAmount: BN,
|
|
27
|
+
direction: PositionDirection,
|
|
28
|
+
auctionStartPrice: BN,
|
|
29
|
+
auctionEndPrice: BN,
|
|
30
|
+
slot?: BN,
|
|
31
|
+
timeInForce = 30
|
|
32
|
+
) {
|
|
33
|
+
dlob.insertOrder(
|
|
34
|
+
{
|
|
35
|
+
status: OrderStatus.OPEN,
|
|
36
|
+
orderType,
|
|
37
|
+
marketType,
|
|
38
|
+
ts: new BN(getMockTimestamp()),
|
|
39
|
+
slot: slot || new BN(1),
|
|
40
|
+
orderId,
|
|
41
|
+
userOrderId: 0,
|
|
42
|
+
marketIndex,
|
|
43
|
+
price,
|
|
44
|
+
baseAssetAmount,
|
|
45
|
+
baseAssetAmountFilled: new BN(0),
|
|
46
|
+
quoteAssetAmount: new BN(0),
|
|
47
|
+
quoteAssetAmountFilled: new BN(0),
|
|
48
|
+
fee: new BN(0),
|
|
49
|
+
direction,
|
|
50
|
+
reduceOnly: false,
|
|
51
|
+
triggerPrice: new BN(0),
|
|
52
|
+
triggerCondition: OrderTriggerCondition.ABOVE,
|
|
53
|
+
triggered: false,
|
|
54
|
+
existingPositionDirection: PositionDirection.LONG,
|
|
55
|
+
postOnly: false,
|
|
56
|
+
immediateOrCancel: true,
|
|
57
|
+
oraclePriceOffset: new BN(0),
|
|
58
|
+
auctionDuration: 10,
|
|
59
|
+
auctionStartPrice,
|
|
60
|
+
auctionEndPrice,
|
|
61
|
+
timeInForce,
|
|
62
|
+
},
|
|
63
|
+
userAccount
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function insertTriggerOrderToDLOB(
|
|
68
|
+
dlob: DLOB,
|
|
69
|
+
userAccount: PublicKey,
|
|
70
|
+
orderType: OrderType,
|
|
71
|
+
marketType: MarketType,
|
|
72
|
+
orderId: BN,
|
|
73
|
+
marketIndex: BN,
|
|
74
|
+
price: BN,
|
|
75
|
+
baseAssetAmount: BN,
|
|
76
|
+
direction: PositionDirection,
|
|
77
|
+
triggerPrice: BN,
|
|
78
|
+
triggerCondition: OrderTriggerCondition,
|
|
79
|
+
auctionStartPrice: BN,
|
|
80
|
+
auctionEndPrice: BN,
|
|
81
|
+
slot?: BN,
|
|
82
|
+
timeInForce = 30
|
|
83
|
+
) {
|
|
84
|
+
dlob.insertOrder(
|
|
85
|
+
{
|
|
86
|
+
status: OrderStatus.OPEN,
|
|
87
|
+
orderType,
|
|
88
|
+
marketType,
|
|
89
|
+
ts: new BN(getMockTimestamp()),
|
|
90
|
+
slot: slot || new BN(1),
|
|
91
|
+
orderId,
|
|
92
|
+
userOrderId: 0,
|
|
93
|
+
marketIndex,
|
|
94
|
+
price,
|
|
95
|
+
baseAssetAmount,
|
|
96
|
+
baseAssetAmountFilled: new BN(0),
|
|
97
|
+
quoteAssetAmount: new BN(0),
|
|
98
|
+
quoteAssetAmountFilled: new BN(0),
|
|
99
|
+
fee: new BN(0),
|
|
100
|
+
direction,
|
|
101
|
+
reduceOnly: false,
|
|
102
|
+
triggerPrice,
|
|
103
|
+
triggerCondition,
|
|
104
|
+
triggered: false,
|
|
105
|
+
existingPositionDirection: PositionDirection.LONG,
|
|
106
|
+
postOnly: false,
|
|
107
|
+
immediateOrCancel: true,
|
|
108
|
+
oraclePriceOffset: new BN(0),
|
|
109
|
+
auctionDuration: 10,
|
|
110
|
+
auctionStartPrice,
|
|
111
|
+
auctionEndPrice,
|
|
112
|
+
timeInForce,
|
|
113
|
+
},
|
|
114
|
+
userAccount
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
let mockTs = 1;
|
|
119
|
+
function getMockTimestamp(): number {
|
|
120
|
+
return mockTs++;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
describe('DLOB Tests', () => {
|
|
124
|
+
it('Fresh DLOB is empty', () => {
|
|
125
|
+
const dlob = new DLOB(mockPerpMarkets, mockSpotMarkets, false);
|
|
126
|
+
const vAsk = new BN(11);
|
|
127
|
+
const vBid = new BN(10);
|
|
128
|
+
const oracle = {
|
|
129
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
130
|
+
slot: new BN(12),
|
|
131
|
+
confidence: new BN(1),
|
|
132
|
+
hasSufficientNumberOfDataPoints: true,
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// check perps
|
|
136
|
+
for (const market of mockPerpMarkets) {
|
|
137
|
+
let foundAsks = 0;
|
|
138
|
+
for (const _ask of dlob.getAsks(
|
|
139
|
+
market.marketIndex,
|
|
140
|
+
vAsk,
|
|
141
|
+
0,
|
|
142
|
+
MarketType.PERP,
|
|
143
|
+
oracle
|
|
144
|
+
)) {
|
|
145
|
+
foundAsks++;
|
|
146
|
+
}
|
|
147
|
+
expect(foundAsks).to.equal(1);
|
|
148
|
+
|
|
149
|
+
let foundBids = 0;
|
|
150
|
+
for (const _bid of dlob.getBids(
|
|
151
|
+
market.marketIndex,
|
|
152
|
+
vBid,
|
|
153
|
+
0,
|
|
154
|
+
MarketType.PERP,
|
|
155
|
+
oracle
|
|
156
|
+
)) {
|
|
157
|
+
foundBids++;
|
|
158
|
+
}
|
|
159
|
+
expect(foundBids).to.equal(1);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// check spots
|
|
163
|
+
for (const market of mockSpotMarkets) {
|
|
164
|
+
let foundAsks = 0;
|
|
165
|
+
for (const _ask of dlob.getAsks(
|
|
166
|
+
market.marketIndex,
|
|
167
|
+
undefined,
|
|
168
|
+
0,
|
|
169
|
+
MarketType.SPOT,
|
|
170
|
+
oracle
|
|
171
|
+
)) {
|
|
172
|
+
foundAsks++;
|
|
173
|
+
}
|
|
174
|
+
expect(foundAsks).to.equal(0);
|
|
175
|
+
let foundBids = 0;
|
|
176
|
+
for (const _bid of dlob.getBids(
|
|
177
|
+
market.marketIndex,
|
|
178
|
+
undefined,
|
|
179
|
+
0,
|
|
180
|
+
MarketType.SPOT,
|
|
181
|
+
oracle
|
|
182
|
+
)) {
|
|
183
|
+
foundBids++;
|
|
184
|
+
}
|
|
185
|
+
expect(foundBids).to.equal(0);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
describe('DLOB Perp Tests', () => {
|
|
191
|
+
it('Test proper bids', () => {
|
|
192
|
+
const vAsk = new BN(15);
|
|
193
|
+
const vBid = new BN(10);
|
|
194
|
+
const dlob = new DLOB(mockPerpMarkets, mockSpotMarkets, false);
|
|
195
|
+
const marketIndex = new BN(0);
|
|
196
|
+
|
|
197
|
+
const slot = 12;
|
|
198
|
+
const oracle = {
|
|
199
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
200
|
+
slot: new BN(slot),
|
|
201
|
+
confidence: new BN(1),
|
|
202
|
+
hasSufficientNumberOfDataPoints: true,
|
|
203
|
+
};
|
|
204
|
+
const testCases = [
|
|
205
|
+
{
|
|
206
|
+
expectedIdx: 3,
|
|
207
|
+
isVamm: false,
|
|
208
|
+
orderId: new BN(5),
|
|
209
|
+
price: new BN(0),
|
|
210
|
+
direction: PositionDirection.LONG,
|
|
211
|
+
orderType: OrderType.MARKET,
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
expectedIdx: 4,
|
|
215
|
+
isVamm: false,
|
|
216
|
+
orderId: new BN(6),
|
|
217
|
+
price: new BN(0),
|
|
218
|
+
direction: PositionDirection.LONG,
|
|
219
|
+
orderType: OrderType.MARKET,
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
expectedIdx: 5,
|
|
223
|
+
isVamm: false,
|
|
224
|
+
orderId: new BN(7),
|
|
225
|
+
price: new BN(0),
|
|
226
|
+
direction: PositionDirection.LONG,
|
|
227
|
+
orderType: OrderType.MARKET,
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
expectedIdx: 0,
|
|
231
|
+
isVamm: false,
|
|
232
|
+
orderId: new BN(1),
|
|
233
|
+
price: new BN(12),
|
|
234
|
+
direction: PositionDirection.LONG,
|
|
235
|
+
orderType: OrderType.LIMIT,
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
expectedIdx: 1,
|
|
239
|
+
isVamm: false,
|
|
240
|
+
orderId: new BN(2),
|
|
241
|
+
price: new BN(11),
|
|
242
|
+
direction: PositionDirection.LONG,
|
|
243
|
+
orderType: OrderType.LIMIT,
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
expectedIdx: 7,
|
|
247
|
+
isVamm: false,
|
|
248
|
+
orderId: new BN(3),
|
|
249
|
+
price: new BN(8),
|
|
250
|
+
direction: PositionDirection.LONG,
|
|
251
|
+
orderType: OrderType.LIMIT,
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
expectedIdx: 2,
|
|
255
|
+
isVamm: true,
|
|
256
|
+
orderId: undefined,
|
|
257
|
+
price: undefined,
|
|
258
|
+
direction: undefined,
|
|
259
|
+
orderType: undefined,
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
expectedIdx: 6,
|
|
263
|
+
isVamm: false,
|
|
264
|
+
orderId: new BN(4),
|
|
265
|
+
price: new BN(9),
|
|
266
|
+
direction: PositionDirection.LONG,
|
|
267
|
+
orderType: OrderType.LIMIT,
|
|
268
|
+
},
|
|
269
|
+
];
|
|
270
|
+
|
|
271
|
+
for (const t of testCases) {
|
|
272
|
+
if (t.isVamm) {
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
insertOrderToDLOB(
|
|
276
|
+
dlob,
|
|
277
|
+
Keypair.generate().publicKey,
|
|
278
|
+
t.orderType || OrderType.LIMIT,
|
|
279
|
+
MarketType.PERP,
|
|
280
|
+
t.orderId || new BN(0), // orderId
|
|
281
|
+
marketIndex,
|
|
282
|
+
t.price || new BN(0), // price
|
|
283
|
+
BASE_PRECISION, // quantity
|
|
284
|
+
t.direction || PositionDirection.LONG,
|
|
285
|
+
vBid,
|
|
286
|
+
vAsk
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const expectedTestCase = testCases.sort((a, b) => {
|
|
291
|
+
// ascending order
|
|
292
|
+
return a.expectedIdx - b.expectedIdx;
|
|
293
|
+
});
|
|
294
|
+
const bids = dlob.getBids(marketIndex, vBid, slot, MarketType.PERP, oracle);
|
|
295
|
+
|
|
296
|
+
console.log('The Book Bids:');
|
|
297
|
+
let countBids = 0;
|
|
298
|
+
for (const bid of bids) {
|
|
299
|
+
console.log(
|
|
300
|
+
` . vAMMNode? ${bid.isVammNode()}, ${JSON.stringify(
|
|
301
|
+
bid.order?.orderType
|
|
302
|
+
)} , ${bid.order?.orderId.toString()} , vammTestgetPRice: ${bid.getPrice(
|
|
303
|
+
oracle,
|
|
304
|
+
slot
|
|
305
|
+
)}, price: ${bid.order?.price.toString()}, quantity: ${bid.order?.baseAssetAmountFilled.toString()}/${bid.order?.baseAssetAmount.toString()}`
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
expect(bid.isVammNode()).to.be.eq(expectedTestCase[countBids].isVamm);
|
|
309
|
+
expect(bid.order?.orderId.toNumber()).to.equal(
|
|
310
|
+
expectedTestCase[countBids].orderId?.toNumber()
|
|
311
|
+
);
|
|
312
|
+
expect(bid.order?.price.toNumber()).to.equal(
|
|
313
|
+
expectedTestCase[countBids].price?.toNumber()
|
|
314
|
+
);
|
|
315
|
+
expect(bid.order?.direction).to.equal(
|
|
316
|
+
expectedTestCase[countBids].direction
|
|
317
|
+
);
|
|
318
|
+
expect(bid.order?.orderType).to.equal(
|
|
319
|
+
expectedTestCase[countBids].orderType
|
|
320
|
+
);
|
|
321
|
+
countBids++;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
expect(countBids).to.equal(testCases.length);
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
it('Test proper bids on multiple markets', () => {
|
|
328
|
+
const vAsk = new BN(15);
|
|
329
|
+
const vBid = new BN(10);
|
|
330
|
+
const dlob = new DLOB(mockPerpMarkets, mockSpotMarkets, false);
|
|
331
|
+
const marketIndex0 = new BN(0);
|
|
332
|
+
const marketIndex1 = new BN(1);
|
|
333
|
+
|
|
334
|
+
const slot = 12;
|
|
335
|
+
const oracle = {
|
|
336
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
337
|
+
slot: new BN(slot),
|
|
338
|
+
confidence: new BN(1),
|
|
339
|
+
hasSufficientNumberOfDataPoints: true,
|
|
340
|
+
};
|
|
341
|
+
const testCases = [
|
|
342
|
+
{
|
|
343
|
+
expectedIdx: 3,
|
|
344
|
+
isVamm: false,
|
|
345
|
+
orderId: new BN(5),
|
|
346
|
+
price: new BN(0),
|
|
347
|
+
direction: PositionDirection.LONG,
|
|
348
|
+
orderType: OrderType.MARKET,
|
|
349
|
+
marketIndex: marketIndex0,
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
expectedIdx: 4,
|
|
353
|
+
isVamm: false,
|
|
354
|
+
orderId: new BN(6),
|
|
355
|
+
price: new BN(0),
|
|
356
|
+
direction: PositionDirection.LONG,
|
|
357
|
+
orderType: OrderType.MARKET,
|
|
358
|
+
marketIndex: marketIndex0,
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
expectedIdx: 5,
|
|
362
|
+
isVamm: false,
|
|
363
|
+
orderId: new BN(7),
|
|
364
|
+
price: new BN(0),
|
|
365
|
+
direction: PositionDirection.LONG,
|
|
366
|
+
orderType: OrderType.MARKET,
|
|
367
|
+
marketIndex: marketIndex1,
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
expectedIdx: 0,
|
|
371
|
+
isVamm: false,
|
|
372
|
+
orderId: new BN(1),
|
|
373
|
+
price: new BN(12),
|
|
374
|
+
direction: PositionDirection.LONG,
|
|
375
|
+
orderType: OrderType.LIMIT,
|
|
376
|
+
marketIndex: marketIndex0,
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
expectedIdx: 1,
|
|
380
|
+
isVamm: false,
|
|
381
|
+
orderId: new BN(2),
|
|
382
|
+
price: new BN(11),
|
|
383
|
+
direction: PositionDirection.LONG,
|
|
384
|
+
orderType: OrderType.LIMIT,
|
|
385
|
+
marketIndex: marketIndex0,
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
expectedIdx: 7,
|
|
389
|
+
isVamm: false,
|
|
390
|
+
orderId: new BN(3),
|
|
391
|
+
price: new BN(8),
|
|
392
|
+
direction: PositionDirection.LONG,
|
|
393
|
+
orderType: OrderType.LIMIT,
|
|
394
|
+
marketIndex: marketIndex0,
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
expectedIdx: 6,
|
|
398
|
+
isVamm: false,
|
|
399
|
+
orderId: new BN(4),
|
|
400
|
+
price: new BN(9),
|
|
401
|
+
direction: PositionDirection.LONG,
|
|
402
|
+
orderType: OrderType.LIMIT,
|
|
403
|
+
marketIndex: marketIndex1,
|
|
404
|
+
},
|
|
405
|
+
];
|
|
406
|
+
|
|
407
|
+
for (const t of testCases) {
|
|
408
|
+
if (t.isVamm) {
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
insertOrderToDLOB(
|
|
412
|
+
dlob,
|
|
413
|
+
Keypair.generate().publicKey,
|
|
414
|
+
t.orderType || OrderType.LIMIT,
|
|
415
|
+
MarketType.PERP,
|
|
416
|
+
t.orderId || new BN(0), // orderId
|
|
417
|
+
t.marketIndex,
|
|
418
|
+
t.price || new BN(0), // price
|
|
419
|
+
BASE_PRECISION, // quantity
|
|
420
|
+
t.direction || PositionDirection.LONG,
|
|
421
|
+
vBid,
|
|
422
|
+
vAsk
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const bids0 = dlob.getBids(
|
|
427
|
+
marketIndex0,
|
|
428
|
+
vBid,
|
|
429
|
+
slot,
|
|
430
|
+
MarketType.PERP,
|
|
431
|
+
oracle
|
|
432
|
+
);
|
|
433
|
+
let countBids0 = 0;
|
|
434
|
+
for (const bid of bids0) {
|
|
435
|
+
console.log(
|
|
436
|
+
` . vAMMNode? ${bid.isVammNode()}, ${JSON.stringify(
|
|
437
|
+
bid.order?.orderType
|
|
438
|
+
)} , ${bid.order?.orderId.toString()} , vammTestgetPRice: ${bid.getPrice(
|
|
439
|
+
oracle,
|
|
440
|
+
slot
|
|
441
|
+
)}, price: ${bid.order?.price.toString()}, quantity: ${bid.order?.baseAssetAmountFilled.toString()}/${bid.order?.baseAssetAmount.toString()}`
|
|
442
|
+
);
|
|
443
|
+
countBids0++;
|
|
444
|
+
}
|
|
445
|
+
expect(countBids0).to.equal(6);
|
|
446
|
+
|
|
447
|
+
const bids1 = dlob.getBids(
|
|
448
|
+
marketIndex1,
|
|
449
|
+
vBid,
|
|
450
|
+
slot,
|
|
451
|
+
MarketType.PERP,
|
|
452
|
+
oracle
|
|
453
|
+
);
|
|
454
|
+
let countBids1 = 0;
|
|
455
|
+
for (const bid of bids1) {
|
|
456
|
+
console.log(
|
|
457
|
+
` . vAMMNode? ${bid.isVammNode()}, ${JSON.stringify(
|
|
458
|
+
bid.order?.orderType
|
|
459
|
+
)} , ${bid.order?.orderId.toString()} , vammTestgetPRice: ${bid.getPrice(
|
|
460
|
+
oracle,
|
|
461
|
+
slot
|
|
462
|
+
)}, price: ${bid.order?.price.toString()}, quantity: ${bid.order?.baseAssetAmountFilled.toString()}/${bid.order?.baseAssetAmount.toString()}`
|
|
463
|
+
);
|
|
464
|
+
|
|
465
|
+
countBids1++;
|
|
466
|
+
}
|
|
467
|
+
expect(countBids1).to.equal(3);
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
it('Test proper asks', () => {
|
|
471
|
+
const vAsk = new BN(15);
|
|
472
|
+
const vBid = new BN(10);
|
|
473
|
+
const dlob = new DLOB(mockPerpMarkets, mockSpotMarkets, false);
|
|
474
|
+
const marketIndex = new BN(0);
|
|
475
|
+
|
|
476
|
+
const slot = 12;
|
|
477
|
+
const oracle = {
|
|
478
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
479
|
+
slot: new BN(slot),
|
|
480
|
+
confidence: new BN(1),
|
|
481
|
+
hasSufficientNumberOfDataPoints: true,
|
|
482
|
+
};
|
|
483
|
+
const testCases = [
|
|
484
|
+
{
|
|
485
|
+
expectedIdx: 0,
|
|
486
|
+
isVamm: false,
|
|
487
|
+
orderId: new BN(3),
|
|
488
|
+
price: new BN(0),
|
|
489
|
+
direction: PositionDirection.SHORT,
|
|
490
|
+
orderType: OrderType.MARKET,
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
expectedIdx: 1,
|
|
494
|
+
isVamm: false,
|
|
495
|
+
orderId: new BN(4),
|
|
496
|
+
price: new BN(0),
|
|
497
|
+
direction: PositionDirection.SHORT,
|
|
498
|
+
orderType: OrderType.MARKET,
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
expectedIdx: 2,
|
|
502
|
+
isVamm: false,
|
|
503
|
+
orderId: new BN(5),
|
|
504
|
+
price: new BN(0),
|
|
505
|
+
direction: PositionDirection.SHORT,
|
|
506
|
+
orderType: OrderType.MARKET,
|
|
507
|
+
},
|
|
508
|
+
{
|
|
509
|
+
expectedIdx: 3,
|
|
510
|
+
isVamm: false,
|
|
511
|
+
orderId: new BN(1),
|
|
512
|
+
price: new BN(13),
|
|
513
|
+
direction: PositionDirection.SHORT,
|
|
514
|
+
orderType: OrderType.LIMIT,
|
|
515
|
+
},
|
|
516
|
+
{
|
|
517
|
+
expectedIdx: 6,
|
|
518
|
+
isVamm: false,
|
|
519
|
+
orderId: new BN(6),
|
|
520
|
+
price: new BN(16),
|
|
521
|
+
direction: PositionDirection.SHORT,
|
|
522
|
+
orderType: OrderType.LIMIT,
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
expectedIdx: 5,
|
|
526
|
+
isVamm: true,
|
|
527
|
+
orderId: undefined,
|
|
528
|
+
price: undefined,
|
|
529
|
+
direction: undefined,
|
|
530
|
+
orderType: undefined,
|
|
531
|
+
},
|
|
532
|
+
{
|
|
533
|
+
expectedIdx: 7,
|
|
534
|
+
isVamm: false,
|
|
535
|
+
orderId: new BN(7),
|
|
536
|
+
price: new BN(17),
|
|
537
|
+
direction: PositionDirection.SHORT,
|
|
538
|
+
orderType: OrderType.LIMIT,
|
|
539
|
+
},
|
|
540
|
+
{
|
|
541
|
+
expectedIdx: 4,
|
|
542
|
+
isVamm: false,
|
|
543
|
+
orderId: new BN(2),
|
|
544
|
+
price: new BN(14),
|
|
545
|
+
direction: PositionDirection.SHORT,
|
|
546
|
+
orderType: OrderType.LIMIT,
|
|
547
|
+
},
|
|
548
|
+
];
|
|
549
|
+
|
|
550
|
+
for (const t of testCases) {
|
|
551
|
+
if (t.isVamm) {
|
|
552
|
+
continue;
|
|
553
|
+
}
|
|
554
|
+
insertOrderToDLOB(
|
|
555
|
+
dlob,
|
|
556
|
+
Keypair.generate().publicKey,
|
|
557
|
+
t.orderType || OrderType.LIMIT,
|
|
558
|
+
MarketType.PERP,
|
|
559
|
+
t.orderId || new BN(0), // orderId
|
|
560
|
+
marketIndex,
|
|
561
|
+
t.price || new BN(0), // price
|
|
562
|
+
BASE_PRECISION, // quantity
|
|
563
|
+
t.direction || PositionDirection.SHORT,
|
|
564
|
+
vBid,
|
|
565
|
+
vAsk
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
const expectedTestCase = testCases.sort((a, b) => {
|
|
570
|
+
// ascending order
|
|
571
|
+
return a.expectedIdx - b.expectedIdx;
|
|
572
|
+
});
|
|
573
|
+
const asks = dlob.getAsks(marketIndex, vAsk, slot, MarketType.PERP, oracle);
|
|
574
|
+
|
|
575
|
+
console.log('The Book Asks:');
|
|
576
|
+
let countAsks = 0;
|
|
577
|
+
for (const ask of asks) {
|
|
578
|
+
console.log(
|
|
579
|
+
` . vAMMNode? ${ask.isVammNode()}, ${JSON.stringify(
|
|
580
|
+
ask.order?.orderType
|
|
581
|
+
)} , ${ask.order?.orderId.toString()} , vammTestgetPRice: ${ask.getPrice(
|
|
582
|
+
oracle,
|
|
583
|
+
slot
|
|
584
|
+
)}, price: ${ask.order?.price.toString()}, quantity: ${ask.order?.baseAssetAmountFilled.toString()}/${ask.order?.baseAssetAmount.toString()}`
|
|
585
|
+
);
|
|
586
|
+
|
|
587
|
+
expect(ask.isVammNode()).to.be.eq(expectedTestCase[countAsks].isVamm);
|
|
588
|
+
expect(ask.order?.orderId.toNumber()).to.equal(
|
|
589
|
+
expectedTestCase[countAsks].orderId?.toNumber()
|
|
590
|
+
);
|
|
591
|
+
expect(ask.order?.price.toNumber()).to.equal(
|
|
592
|
+
expectedTestCase[countAsks].price?.toNumber()
|
|
593
|
+
);
|
|
594
|
+
expect(ask.order?.direction).to.equal(
|
|
595
|
+
expectedTestCase[countAsks].direction
|
|
596
|
+
);
|
|
597
|
+
expect(ask.order?.orderType).to.equal(
|
|
598
|
+
expectedTestCase[countAsks].orderType
|
|
599
|
+
);
|
|
600
|
+
countAsks++;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
expect(countAsks).to.equal(testCases.length);
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
it('Test insert market orders', () => {
|
|
607
|
+
const vAsk = new BN(11);
|
|
608
|
+
const vBid = new BN(10);
|
|
609
|
+
const dlob = new DLOB(mockPerpMarkets, mockSpotMarkets, false);
|
|
610
|
+
const marketIndex = new BN(0);
|
|
611
|
+
const oracle = {
|
|
612
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
613
|
+
slot: new BN(12),
|
|
614
|
+
confidence: new BN(1),
|
|
615
|
+
hasSufficientNumberOfDataPoints: true,
|
|
616
|
+
};
|
|
617
|
+
|
|
618
|
+
// 3 mkt buys
|
|
619
|
+
for (let i = 0; i < 3; i++) {
|
|
620
|
+
insertOrderToDLOB(
|
|
621
|
+
dlob,
|
|
622
|
+
Keypair.generate().publicKey,
|
|
623
|
+
OrderType.MARKET,
|
|
624
|
+
MarketType.PERP,
|
|
625
|
+
new BN(i + 1),
|
|
626
|
+
marketIndex,
|
|
627
|
+
new BN(0),
|
|
628
|
+
BASE_PRECISION,
|
|
629
|
+
PositionDirection.LONG,
|
|
630
|
+
vBid,
|
|
631
|
+
vAsk
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// 3 mkt sells
|
|
636
|
+
for (let i = 0; i < 3; i++) {
|
|
637
|
+
insertOrderToDLOB(
|
|
638
|
+
dlob,
|
|
639
|
+
Keypair.generate().publicKey,
|
|
640
|
+
OrderType.MARKET,
|
|
641
|
+
MarketType.PERP,
|
|
642
|
+
new BN(i + 1),
|
|
643
|
+
marketIndex,
|
|
644
|
+
new BN(0),
|
|
645
|
+
BASE_PRECISION,
|
|
646
|
+
PositionDirection.SHORT,
|
|
647
|
+
vBid,
|
|
648
|
+
vAsk
|
|
649
|
+
);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
let asks = 0;
|
|
653
|
+
for (const ask of dlob.getAsks(
|
|
654
|
+
marketIndex,
|
|
655
|
+
vAsk,
|
|
656
|
+
2,
|
|
657
|
+
MarketType.PERP,
|
|
658
|
+
oracle
|
|
659
|
+
)) {
|
|
660
|
+
// vamm node is last in asks
|
|
661
|
+
asks++;
|
|
662
|
+
|
|
663
|
+
if (ask.order) {
|
|
664
|
+
// market orders
|
|
665
|
+
expect(getVariant(ask.order?.status)).to.equal('open');
|
|
666
|
+
expect(getVariant(ask.order?.orderType)).to.equal('market');
|
|
667
|
+
expect(getVariant(ask.order?.direction)).to.equal('short');
|
|
668
|
+
expect(ask.order?.orderId.toNumber()).to.equal(asks);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
expect(asks).to.equal(4); // vamm ask + 3 orders
|
|
672
|
+
|
|
673
|
+
let bids = 0;
|
|
674
|
+
for (const bid of dlob.getBids(
|
|
675
|
+
marketIndex,
|
|
676
|
+
vBid,
|
|
677
|
+
2,
|
|
678
|
+
MarketType.PERP,
|
|
679
|
+
oracle
|
|
680
|
+
)) {
|
|
681
|
+
if (bids === 0) {
|
|
682
|
+
// vamm node
|
|
683
|
+
expect(bid.order).to.equal(undefined);
|
|
684
|
+
} else {
|
|
685
|
+
// market orders
|
|
686
|
+
expect(getVariant(bid.order?.status)).to.equal('open');
|
|
687
|
+
expect(getVariant(bid.order?.orderType)).to.equal('market');
|
|
688
|
+
expect(getVariant(bid.order?.direction)).to.equal('long');
|
|
689
|
+
expect(bid.order?.orderId.toNumber()).to.equal(bids);
|
|
690
|
+
}
|
|
691
|
+
bids++;
|
|
692
|
+
}
|
|
693
|
+
expect(bids).to.equal(4); // vamm bid + 3 orders
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
it('Test insert limit orders', () => {
|
|
697
|
+
const slot = 12;
|
|
698
|
+
const vAsk = new BN(11);
|
|
699
|
+
const vBid = new BN(10);
|
|
700
|
+
const oracle = {
|
|
701
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
702
|
+
slot: new BN(slot),
|
|
703
|
+
confidence: new BN(1),
|
|
704
|
+
hasSufficientNumberOfDataPoints: true,
|
|
705
|
+
};
|
|
706
|
+
const dlob = new DLOB(mockPerpMarkets, mockSpotMarkets, false);
|
|
707
|
+
const marketIndex = new BN(0);
|
|
708
|
+
insertOrderToDLOB(
|
|
709
|
+
dlob,
|
|
710
|
+
Keypair.generate().publicKey,
|
|
711
|
+
OrderType.LIMIT,
|
|
712
|
+
MarketType.PERP,
|
|
713
|
+
new BN(3),
|
|
714
|
+
marketIndex,
|
|
715
|
+
new BN(5),
|
|
716
|
+
BASE_PRECISION,
|
|
717
|
+
PositionDirection.LONG,
|
|
718
|
+
vBid,
|
|
719
|
+
vAsk
|
|
720
|
+
);
|
|
721
|
+
|
|
722
|
+
insertOrderToDLOB(
|
|
723
|
+
dlob,
|
|
724
|
+
Keypair.generate().publicKey,
|
|
725
|
+
OrderType.LIMIT,
|
|
726
|
+
MarketType.PERP,
|
|
727
|
+
new BN(2),
|
|
728
|
+
marketIndex,
|
|
729
|
+
new BN(6),
|
|
730
|
+
BASE_PRECISION,
|
|
731
|
+
PositionDirection.LONG,
|
|
732
|
+
vBid,
|
|
733
|
+
vAsk
|
|
734
|
+
);
|
|
735
|
+
|
|
736
|
+
insertOrderToDLOB(
|
|
737
|
+
dlob,
|
|
738
|
+
Keypair.generate().publicKey,
|
|
739
|
+
OrderType.LIMIT,
|
|
740
|
+
MarketType.PERP,
|
|
741
|
+
new BN(1),
|
|
742
|
+
marketIndex,
|
|
743
|
+
new BN(7),
|
|
744
|
+
BASE_PRECISION,
|
|
745
|
+
PositionDirection.LONG,
|
|
746
|
+
vBid,
|
|
747
|
+
vAsk
|
|
748
|
+
);
|
|
749
|
+
|
|
750
|
+
insertOrderToDLOB(
|
|
751
|
+
dlob,
|
|
752
|
+
Keypair.generate().publicKey,
|
|
753
|
+
OrderType.LIMIT,
|
|
754
|
+
MarketType.PERP,
|
|
755
|
+
new BN(1),
|
|
756
|
+
marketIndex,
|
|
757
|
+
new BN(12),
|
|
758
|
+
BASE_PRECISION,
|
|
759
|
+
PositionDirection.SHORT,
|
|
760
|
+
vBid,
|
|
761
|
+
vAsk
|
|
762
|
+
);
|
|
763
|
+
|
|
764
|
+
insertOrderToDLOB(
|
|
765
|
+
dlob,
|
|
766
|
+
Keypair.generate().publicKey,
|
|
767
|
+
OrderType.LIMIT,
|
|
768
|
+
MarketType.PERP,
|
|
769
|
+
new BN(2),
|
|
770
|
+
marketIndex,
|
|
771
|
+
new BN(13),
|
|
772
|
+
BASE_PRECISION,
|
|
773
|
+
PositionDirection.SHORT,
|
|
774
|
+
vBid,
|
|
775
|
+
vAsk
|
|
776
|
+
);
|
|
777
|
+
|
|
778
|
+
insertOrderToDLOB(
|
|
779
|
+
dlob,
|
|
780
|
+
Keypair.generate().publicKey,
|
|
781
|
+
OrderType.LIMIT,
|
|
782
|
+
MarketType.PERP,
|
|
783
|
+
new BN(3),
|
|
784
|
+
marketIndex,
|
|
785
|
+
new BN(14),
|
|
786
|
+
BASE_PRECISION,
|
|
787
|
+
PositionDirection.SHORT,
|
|
788
|
+
vBid,
|
|
789
|
+
vAsk
|
|
790
|
+
);
|
|
791
|
+
|
|
792
|
+
let asks = 0;
|
|
793
|
+
for (const ask of dlob.getAsks(
|
|
794
|
+
marketIndex,
|
|
795
|
+
vAsk,
|
|
796
|
+
2,
|
|
797
|
+
MarketType.PERP,
|
|
798
|
+
oracle
|
|
799
|
+
)) {
|
|
800
|
+
if (ask.order) {
|
|
801
|
+
// market orders
|
|
802
|
+
console.log(`ask price: ${ask.order.price.toString()}`);
|
|
803
|
+
expect(getVariant(ask.order?.status)).to.equal('open');
|
|
804
|
+
expect(getVariant(ask.order?.orderType)).to.equal('limit');
|
|
805
|
+
expect(getVariant(ask.order?.direction)).to.equal('short');
|
|
806
|
+
expect(ask.order?.orderId.toNumber()).to.equal(asks);
|
|
807
|
+
expect(ask.order?.price.gt(vAsk)).to.equal(true);
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
// vamm node is first for limit asks
|
|
811
|
+
asks++;
|
|
812
|
+
}
|
|
813
|
+
expect(asks).to.equal(4); // vamm ask + 3 orders
|
|
814
|
+
|
|
815
|
+
let bids = 0;
|
|
816
|
+
for (const bid of dlob.getBids(
|
|
817
|
+
marketIndex,
|
|
818
|
+
vBid,
|
|
819
|
+
2,
|
|
820
|
+
MarketType.PERP,
|
|
821
|
+
oracle
|
|
822
|
+
)) {
|
|
823
|
+
if (bids === 0) {
|
|
824
|
+
// vamm node
|
|
825
|
+
expect(bid.order).to.equal(undefined);
|
|
826
|
+
} else {
|
|
827
|
+
// market orders
|
|
828
|
+
console.log(`bid price: ${bid.order?.price.toString()}`);
|
|
829
|
+
expect(getVariant(bid.order?.status)).to.equal('open');
|
|
830
|
+
expect(getVariant(bid.order?.orderType)).to.equal('limit');
|
|
831
|
+
expect(getVariant(bid.order?.direction)).to.equal('long');
|
|
832
|
+
expect(bid.order?.orderId.toNumber()).to.equal(bids);
|
|
833
|
+
expect(bid.order?.price.lt(vBid)).to.equal(true);
|
|
834
|
+
}
|
|
835
|
+
bids++;
|
|
836
|
+
}
|
|
837
|
+
expect(bids).to.equal(4); // vamm bid + 3 orders
|
|
838
|
+
});
|
|
839
|
+
|
|
840
|
+
it('Test multiple market orders fill with multiple limit orders', () => {
|
|
841
|
+
const vAsk = new BN(15);
|
|
842
|
+
const vBid = new BN(10);
|
|
843
|
+
const dlob = new DLOB(mockPerpMarkets, mockSpotMarkets, false);
|
|
844
|
+
const marketIndex = new BN(0);
|
|
845
|
+
|
|
846
|
+
// insert some limit buys above vamm bid, below ask
|
|
847
|
+
insertOrderToDLOB(
|
|
848
|
+
dlob,
|
|
849
|
+
Keypair.generate().publicKey,
|
|
850
|
+
OrderType.LIMIT,
|
|
851
|
+
MarketType.PERP,
|
|
852
|
+
new BN(1), // orderId
|
|
853
|
+
marketIndex,
|
|
854
|
+
new BN(11), // price
|
|
855
|
+
BASE_PRECISION, // quantity
|
|
856
|
+
PositionDirection.LONG,
|
|
857
|
+
vBid,
|
|
858
|
+
vAsk
|
|
859
|
+
);
|
|
860
|
+
insertOrderToDLOB(
|
|
861
|
+
dlob,
|
|
862
|
+
Keypair.generate().publicKey,
|
|
863
|
+
OrderType.LIMIT,
|
|
864
|
+
MarketType.PERP,
|
|
865
|
+
new BN(2), // orderId
|
|
866
|
+
marketIndex,
|
|
867
|
+
new BN(12), // price
|
|
868
|
+
BASE_PRECISION, // quantity
|
|
869
|
+
PositionDirection.LONG,
|
|
870
|
+
vBid,
|
|
871
|
+
vAsk
|
|
872
|
+
);
|
|
873
|
+
insertOrderToDLOB(
|
|
874
|
+
dlob,
|
|
875
|
+
Keypair.generate().publicKey,
|
|
876
|
+
OrderType.LIMIT,
|
|
877
|
+
MarketType.PERP,
|
|
878
|
+
new BN(3), // orderId
|
|
879
|
+
marketIndex,
|
|
880
|
+
new BN(13), // price
|
|
881
|
+
BASE_PRECISION, // quantity
|
|
882
|
+
PositionDirection.LONG,
|
|
883
|
+
vBid,
|
|
884
|
+
vAsk
|
|
885
|
+
);
|
|
886
|
+
|
|
887
|
+
// should have no crossing orders
|
|
888
|
+
const nodesToFillBefore = dlob.findCrossingNodesToFill(
|
|
889
|
+
marketIndex,
|
|
890
|
+
vBid,
|
|
891
|
+
vAsk,
|
|
892
|
+
12, // auction over
|
|
893
|
+
MarketType.PERP,
|
|
894
|
+
{
|
|
895
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
896
|
+
slot: new BN(12),
|
|
897
|
+
confidence: new BN(1),
|
|
898
|
+
hasSufficientNumberOfDataPoints: true,
|
|
899
|
+
}
|
|
900
|
+
);
|
|
901
|
+
expect(nodesToFillBefore.length).to.equal(0);
|
|
902
|
+
|
|
903
|
+
// place two market sell order eating 2 of the limit orders
|
|
904
|
+
insertOrderToDLOB(
|
|
905
|
+
dlob,
|
|
906
|
+
Keypair.generate().publicKey,
|
|
907
|
+
OrderType.MARKET,
|
|
908
|
+
MarketType.PERP,
|
|
909
|
+
new BN(4), // orderId
|
|
910
|
+
marketIndex,
|
|
911
|
+
new BN(12), // price
|
|
912
|
+
new BN(1).mul(BASE_PRECISION), // quantity
|
|
913
|
+
PositionDirection.SHORT,
|
|
914
|
+
vBid,
|
|
915
|
+
vAsk
|
|
916
|
+
);
|
|
917
|
+
insertOrderToDLOB(
|
|
918
|
+
dlob,
|
|
919
|
+
Keypair.generate().publicKey,
|
|
920
|
+
OrderType.MARKET,
|
|
921
|
+
MarketType.PERP,
|
|
922
|
+
new BN(5), // orderId
|
|
923
|
+
marketIndex,
|
|
924
|
+
new BN(12), // price
|
|
925
|
+
new BN(1).mul(BASE_PRECISION), // quantity
|
|
926
|
+
PositionDirection.SHORT,
|
|
927
|
+
vBid,
|
|
928
|
+
vAsk
|
|
929
|
+
);
|
|
930
|
+
|
|
931
|
+
const nodesToFillAfter = dlob.findCrossingNodesToFill(
|
|
932
|
+
marketIndex,
|
|
933
|
+
vBid,
|
|
934
|
+
vAsk,
|
|
935
|
+
12, // auction over
|
|
936
|
+
MarketType.PERP,
|
|
937
|
+
{
|
|
938
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
939
|
+
slot: new BN(12),
|
|
940
|
+
confidence: new BN(1),
|
|
941
|
+
hasSufficientNumberOfDataPoints: true,
|
|
942
|
+
}
|
|
943
|
+
);
|
|
944
|
+
for (const n of nodesToFillAfter) {
|
|
945
|
+
console.log(
|
|
946
|
+
`cross found: taker orderId: ${n.node.order?.orderId.toString()}: BAA: ${n.node.order?.baseAssetAmount.toString()}, maker orderId: ${n.makerNode?.order?.orderId.toString()}: BAA: ${n.makerNode?.order?.baseAssetAmount.toString()}`
|
|
947
|
+
);
|
|
948
|
+
}
|
|
949
|
+
expect(nodesToFillAfter.length).to.equal(2);
|
|
950
|
+
|
|
951
|
+
// first taker should fill with best maker
|
|
952
|
+
expect(nodesToFillAfter[0].node.order?.orderId.toNumber()).to.equal(4);
|
|
953
|
+
expect(nodesToFillAfter[0].makerNode?.order?.orderId.toNumber()).to.equal(
|
|
954
|
+
3
|
|
955
|
+
);
|
|
956
|
+
|
|
957
|
+
// second taker should fill with second best maker
|
|
958
|
+
expect(nodesToFillAfter[1].node.order?.orderId.toNumber()).to.equal(5);
|
|
959
|
+
expect(nodesToFillAfter[1].makerNode?.order?.orderId.toNumber()).to.equal(
|
|
960
|
+
2
|
|
961
|
+
);
|
|
962
|
+
});
|
|
963
|
+
|
|
964
|
+
it('Test one market orders fills two limit orders', () => {
|
|
965
|
+
const vAsk = new BN(15);
|
|
966
|
+
const vBid = new BN(10);
|
|
967
|
+
const dlob = new DLOB(mockPerpMarkets, mockSpotMarkets, false);
|
|
968
|
+
const marketIndex = new BN(0);
|
|
969
|
+
|
|
970
|
+
// insert some limit sells below vAMM ask, above bid
|
|
971
|
+
insertOrderToDLOB(
|
|
972
|
+
dlob,
|
|
973
|
+
Keypair.generate().publicKey,
|
|
974
|
+
OrderType.LIMIT,
|
|
975
|
+
MarketType.PERP,
|
|
976
|
+
new BN(1), // orderId
|
|
977
|
+
marketIndex,
|
|
978
|
+
new BN(14), // price
|
|
979
|
+
BASE_PRECISION, // quantity
|
|
980
|
+
PositionDirection.SHORT,
|
|
981
|
+
vBid,
|
|
982
|
+
vAsk
|
|
983
|
+
);
|
|
984
|
+
insertOrderToDLOB(
|
|
985
|
+
dlob,
|
|
986
|
+
Keypair.generate().publicKey,
|
|
987
|
+
OrderType.LIMIT,
|
|
988
|
+
MarketType.PERP,
|
|
989
|
+
new BN(2), // orderId
|
|
990
|
+
marketIndex,
|
|
991
|
+
new BN(13), // price
|
|
992
|
+
BASE_PRECISION, // quantity
|
|
993
|
+
PositionDirection.SHORT,
|
|
994
|
+
vBid,
|
|
995
|
+
vAsk
|
|
996
|
+
);
|
|
997
|
+
insertOrderToDLOB(
|
|
998
|
+
dlob,
|
|
999
|
+
Keypair.generate().publicKey,
|
|
1000
|
+
OrderType.LIMIT,
|
|
1001
|
+
MarketType.PERP,
|
|
1002
|
+
new BN(3), // orderId
|
|
1003
|
+
marketIndex,
|
|
1004
|
+
new BN(12), // price
|
|
1005
|
+
BASE_PRECISION, // quantity
|
|
1006
|
+
PositionDirection.SHORT,
|
|
1007
|
+
vBid,
|
|
1008
|
+
vAsk
|
|
1009
|
+
);
|
|
1010
|
+
|
|
1011
|
+
// should have no crossing orders
|
|
1012
|
+
const nodesToFillBefore = dlob.findCrossingNodesToFill(
|
|
1013
|
+
marketIndex,
|
|
1014
|
+
vBid,
|
|
1015
|
+
vAsk,
|
|
1016
|
+
12, // auction over
|
|
1017
|
+
MarketType.PERP,
|
|
1018
|
+
{
|
|
1019
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
1020
|
+
slot: new BN(12),
|
|
1021
|
+
confidence: new BN(1),
|
|
1022
|
+
hasSufficientNumberOfDataPoints: true,
|
|
1023
|
+
}
|
|
1024
|
+
);
|
|
1025
|
+
expect(nodesToFillBefore.length).to.equal(0);
|
|
1026
|
+
|
|
1027
|
+
// place one market buy order eating 2 of the limit orders
|
|
1028
|
+
insertOrderToDLOB(
|
|
1029
|
+
dlob,
|
|
1030
|
+
Keypair.generate().publicKey,
|
|
1031
|
+
OrderType.MARKET,
|
|
1032
|
+
MarketType.PERP,
|
|
1033
|
+
new BN(4), // orderId
|
|
1034
|
+
marketIndex,
|
|
1035
|
+
new BN(13), // price
|
|
1036
|
+
new BN(2).mul(BASE_PRECISION), // quantity
|
|
1037
|
+
PositionDirection.LONG,
|
|
1038
|
+
vBid,
|
|
1039
|
+
vAsk
|
|
1040
|
+
);
|
|
1041
|
+
|
|
1042
|
+
const nodesToFillAfter = dlob.findCrossingNodesToFill(
|
|
1043
|
+
marketIndex,
|
|
1044
|
+
vBid,
|
|
1045
|
+
vAsk,
|
|
1046
|
+
12, // auction over
|
|
1047
|
+
MarketType.PERP,
|
|
1048
|
+
{
|
|
1049
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
1050
|
+
slot: new BN(12),
|
|
1051
|
+
confidence: new BN(1),
|
|
1052
|
+
hasSufficientNumberOfDataPoints: true,
|
|
1053
|
+
}
|
|
1054
|
+
);
|
|
1055
|
+
for (const n of nodesToFillAfter) {
|
|
1056
|
+
console.log(
|
|
1057
|
+
`cross found: taker orderId: ${n.node.order?.orderId.toString()}: BAA: ${n.node.order?.baseAssetAmountFilled.toString()}/${n.node.order?.baseAssetAmount.toString()}, maker orderId: ${n.makerNode?.order?.orderId.toString()}: BAA: ${n.makerNode?.order?.baseAssetAmountFilled.toString()}/${n.makerNode?.order?.baseAssetAmount.toString()}`
|
|
1058
|
+
);
|
|
1059
|
+
}
|
|
1060
|
+
expect(nodesToFillAfter.length).to.equal(2);
|
|
1061
|
+
|
|
1062
|
+
// taker should fill completely with best maker
|
|
1063
|
+
expect(nodesToFillAfter[0].node.order?.orderId.toNumber()).to.equal(4);
|
|
1064
|
+
expect(nodesToFillAfter[0].makerNode?.order?.orderId.toNumber()).to.equal(
|
|
1065
|
+
3
|
|
1066
|
+
);
|
|
1067
|
+
|
|
1068
|
+
// taker should fill completely with second best maker
|
|
1069
|
+
expect(nodesToFillAfter[1].node.order?.orderId.toNumber()).to.equal(4);
|
|
1070
|
+
expect(nodesToFillAfter[1].makerNode?.order?.orderId.toNumber()).to.equal(
|
|
1071
|
+
2
|
|
1072
|
+
);
|
|
1073
|
+
});
|
|
1074
|
+
|
|
1075
|
+
it('Test two market orders to fill one limit order', () => {
|
|
1076
|
+
const vAsk = new BN(15);
|
|
1077
|
+
const vBid = new BN(8);
|
|
1078
|
+
const dlob = new DLOB(mockPerpMarkets, mockSpotMarkets, false);
|
|
1079
|
+
const marketIndex = new BN(0);
|
|
1080
|
+
|
|
1081
|
+
const slot = 12;
|
|
1082
|
+
const oracle = {
|
|
1083
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
1084
|
+
slot: new BN(slot),
|
|
1085
|
+
confidence: new BN(1),
|
|
1086
|
+
hasSufficientNumberOfDataPoints: true,
|
|
1087
|
+
};
|
|
1088
|
+
|
|
1089
|
+
// insert some limit sells below vAMM ask, above bid
|
|
1090
|
+
insertOrderToDLOB(
|
|
1091
|
+
dlob,
|
|
1092
|
+
Keypair.generate().publicKey,
|
|
1093
|
+
OrderType.LIMIT,
|
|
1094
|
+
MarketType.PERP,
|
|
1095
|
+
new BN(1), // orderId
|
|
1096
|
+
marketIndex,
|
|
1097
|
+
new BN(14), // price
|
|
1098
|
+
BASE_PRECISION, // quantity
|
|
1099
|
+
PositionDirection.SHORT,
|
|
1100
|
+
vBid,
|
|
1101
|
+
vAsk
|
|
1102
|
+
);
|
|
1103
|
+
insertOrderToDLOB(
|
|
1104
|
+
dlob,
|
|
1105
|
+
Keypair.generate().publicKey,
|
|
1106
|
+
OrderType.LIMIT,
|
|
1107
|
+
MarketType.PERP,
|
|
1108
|
+
new BN(2), // orderId
|
|
1109
|
+
marketIndex,
|
|
1110
|
+
new BN(13), // price
|
|
1111
|
+
BASE_PRECISION, // quantity
|
|
1112
|
+
PositionDirection.SHORT,
|
|
1113
|
+
vBid,
|
|
1114
|
+
vAsk
|
|
1115
|
+
);
|
|
1116
|
+
insertOrderToDLOB(
|
|
1117
|
+
dlob,
|
|
1118
|
+
Keypair.generate().publicKey,
|
|
1119
|
+
OrderType.LIMIT,
|
|
1120
|
+
MarketType.PERP,
|
|
1121
|
+
new BN(3), // orderId
|
|
1122
|
+
marketIndex,
|
|
1123
|
+
new BN(9), // price <-- best price
|
|
1124
|
+
new BN(3).mul(BASE_PRECISION), // quantity
|
|
1125
|
+
PositionDirection.SHORT,
|
|
1126
|
+
vBid,
|
|
1127
|
+
vAsk
|
|
1128
|
+
);
|
|
1129
|
+
|
|
1130
|
+
// should have no crossing orders
|
|
1131
|
+
const nodesToFillBefore = dlob.findCrossingNodesToFill(
|
|
1132
|
+
marketIndex,
|
|
1133
|
+
vBid,
|
|
1134
|
+
vAsk,
|
|
1135
|
+
12, // auction over
|
|
1136
|
+
MarketType.PERP,
|
|
1137
|
+
oracle
|
|
1138
|
+
);
|
|
1139
|
+
expect(nodesToFillBefore.length).to.equal(0);
|
|
1140
|
+
|
|
1141
|
+
// place two market buy orders to eat the best ask
|
|
1142
|
+
insertOrderToDLOB(
|
|
1143
|
+
dlob,
|
|
1144
|
+
Keypair.generate().publicKey,
|
|
1145
|
+
OrderType.MARKET,
|
|
1146
|
+
MarketType.PERP,
|
|
1147
|
+
new BN(4), // orderId
|
|
1148
|
+
marketIndex,
|
|
1149
|
+
new BN(0), // price
|
|
1150
|
+
new BN(1).mul(BASE_PRECISION), // quantity
|
|
1151
|
+
PositionDirection.LONG,
|
|
1152
|
+
vBid,
|
|
1153
|
+
vAsk
|
|
1154
|
+
);
|
|
1155
|
+
insertOrderToDLOB(
|
|
1156
|
+
dlob,
|
|
1157
|
+
Keypair.generate().publicKey,
|
|
1158
|
+
OrderType.MARKET,
|
|
1159
|
+
MarketType.PERP,
|
|
1160
|
+
new BN(5), // orderId
|
|
1161
|
+
marketIndex,
|
|
1162
|
+
new BN(0), // price
|
|
1163
|
+
new BN(2).mul(BASE_PRECISION), // quantity
|
|
1164
|
+
PositionDirection.LONG,
|
|
1165
|
+
vBid,
|
|
1166
|
+
vAsk
|
|
1167
|
+
);
|
|
1168
|
+
|
|
1169
|
+
const nodesToFillAfter = dlob.findCrossingNodesToFill(
|
|
1170
|
+
marketIndex,
|
|
1171
|
+
vBid,
|
|
1172
|
+
vAsk,
|
|
1173
|
+
slot, // auction over
|
|
1174
|
+
MarketType.PERP,
|
|
1175
|
+
oracle
|
|
1176
|
+
);
|
|
1177
|
+
const mktNodes = dlob.findMarketNodesToFill(
|
|
1178
|
+
marketIndex,
|
|
1179
|
+
slot,
|
|
1180
|
+
MarketType.PERP
|
|
1181
|
+
);
|
|
1182
|
+
console.log(`market nodes: ${mktNodes.length}`);
|
|
1183
|
+
|
|
1184
|
+
const askNodes = dlob.getAsks(
|
|
1185
|
+
marketIndex,
|
|
1186
|
+
vAsk,
|
|
1187
|
+
slot,
|
|
1188
|
+
MarketType.PERP,
|
|
1189
|
+
oracle
|
|
1190
|
+
);
|
|
1191
|
+
let aa = 0;
|
|
1192
|
+
for (const b of askNodes) {
|
|
1193
|
+
console.log(
|
|
1194
|
+
` . ask: ${b.order?.orderId.toString()}: p1: ${b.order?.price.toString()} p2: ${b.getPrice(
|
|
1195
|
+
oracle,
|
|
1196
|
+
slot
|
|
1197
|
+
)}, ${JSON.stringify(
|
|
1198
|
+
b.order?.orderType
|
|
1199
|
+
)} BAA: ${b.order?.baseAssetAmountFilled.toString()}/${b.order?.baseAssetAmount.toString()}`
|
|
1200
|
+
);
|
|
1201
|
+
aa++;
|
|
1202
|
+
}
|
|
1203
|
+
expect(aa).to.equal(4);
|
|
1204
|
+
|
|
1205
|
+
const bidNodes = dlob.getBids(
|
|
1206
|
+
marketIndex,
|
|
1207
|
+
vBid,
|
|
1208
|
+
slot,
|
|
1209
|
+
MarketType.PERP,
|
|
1210
|
+
oracle
|
|
1211
|
+
);
|
|
1212
|
+
let bb = 0;
|
|
1213
|
+
for (const b of bidNodes) {
|
|
1214
|
+
console.log(
|
|
1215
|
+
` . bid: ${b.order?.orderId.toString()}: p1: ${b.order?.price.toString()} p2: ${b.getPrice(
|
|
1216
|
+
oracle,
|
|
1217
|
+
slot
|
|
1218
|
+
)}, ${JSON.stringify(
|
|
1219
|
+
b.order?.orderType
|
|
1220
|
+
)} BAA: ${b.order?.baseAssetAmountFilled.toString()}/${b.order?.baseAssetAmount.toString()}`
|
|
1221
|
+
);
|
|
1222
|
+
bb++;
|
|
1223
|
+
}
|
|
1224
|
+
expect(bb).to.equal(3);
|
|
1225
|
+
|
|
1226
|
+
console.log(`bids nodes: ${bb}`);
|
|
1227
|
+
for (const n of nodesToFillAfter) {
|
|
1228
|
+
console.log(
|
|
1229
|
+
`cross found: taker orderId: ${n.node.order?.orderId.toString()}: BAA: ${n.node.order?.baseAssetAmountFilled.toString()}/${n.node.order?.baseAssetAmount.toString()}, maker orderId: ${n.makerNode?.order?.orderId.toString()}: BAA: ${n.makerNode?.order?.baseAssetAmountFilled.toString()}/${n.makerNode?.order?.baseAssetAmount.toString()}`
|
|
1230
|
+
);
|
|
1231
|
+
}
|
|
1232
|
+
expect(nodesToFillAfter.length).to.equal(2);
|
|
1233
|
+
|
|
1234
|
+
// taker should fill completely with best maker
|
|
1235
|
+
expect(nodesToFillAfter[0].node.order?.orderId.toNumber()).to.equal(4);
|
|
1236
|
+
expect(nodesToFillAfter[0].makerNode?.order?.orderId.toNumber()).to.equal(
|
|
1237
|
+
3
|
|
1238
|
+
);
|
|
1239
|
+
|
|
1240
|
+
// taker should fill completely with second best maker
|
|
1241
|
+
expect(nodesToFillAfter[1].node.order?.orderId.toNumber()).to.equal(5);
|
|
1242
|
+
expect(nodesToFillAfter[1].makerNode?.order?.orderId.toNumber()).to.equal(
|
|
1243
|
+
3
|
|
1244
|
+
);
|
|
1245
|
+
});
|
|
1246
|
+
|
|
1247
|
+
it('Test trigger orders', () => {
|
|
1248
|
+
const vAsk = new BN(15);
|
|
1249
|
+
const vBid = new BN(8);
|
|
1250
|
+
const dlob = new DLOB(mockPerpMarkets, mockSpotMarkets, false);
|
|
1251
|
+
const marketIndex = new BN(0);
|
|
1252
|
+
|
|
1253
|
+
const slot = 20;
|
|
1254
|
+
const oracle = {
|
|
1255
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
1256
|
+
slot: new BN(slot),
|
|
1257
|
+
confidence: new BN(1),
|
|
1258
|
+
hasSufficientNumberOfDataPoints: true,
|
|
1259
|
+
};
|
|
1260
|
+
|
|
1261
|
+
const orderIdsToTrigger = [1, 2, 3, 4, 5, 6, 7, 8];
|
|
1262
|
+
// const orderIdsToNotTrigger = [9, 10, 11, 12];
|
|
1263
|
+
|
|
1264
|
+
// should trigger limit buy with above condition
|
|
1265
|
+
insertTriggerOrderToDLOB(
|
|
1266
|
+
dlob,
|
|
1267
|
+
Keypair.generate().publicKey,
|
|
1268
|
+
OrderType.TRIGGER_LIMIT,
|
|
1269
|
+
MarketType.PERP,
|
|
1270
|
+
new BN(1), //orderId
|
|
1271
|
+
marketIndex, // marketIndex
|
|
1272
|
+
vBid, // price
|
|
1273
|
+
BASE_PRECISION, // baseAssetAmount: BN,
|
|
1274
|
+
PositionDirection.LONG,
|
|
1275
|
+
oracle.price.sub(new BN(1)), // triggerPrice: BN,
|
|
1276
|
+
OrderTriggerCondition.ABOVE, // triggerCondition: OrderTriggerCondition,
|
|
1277
|
+
vBid,
|
|
1278
|
+
vAsk
|
|
1279
|
+
);
|
|
1280
|
+
// should trigger limit sell with above condition
|
|
1281
|
+
insertTriggerOrderToDLOB(
|
|
1282
|
+
dlob,
|
|
1283
|
+
Keypair.generate().publicKey,
|
|
1284
|
+
OrderType.TRIGGER_LIMIT,
|
|
1285
|
+
MarketType.PERP,
|
|
1286
|
+
new BN(2), //orderId
|
|
1287
|
+
marketIndex, // marketIndex
|
|
1288
|
+
vBid, // price
|
|
1289
|
+
BASE_PRECISION, // baseAssetAmount: BN,
|
|
1290
|
+
PositionDirection.SHORT,
|
|
1291
|
+
oracle.price.sub(new BN(1)), // triggerPrice: BN,
|
|
1292
|
+
OrderTriggerCondition.ABOVE, // triggerCondition: OrderTriggerCondition,
|
|
1293
|
+
vBid,
|
|
1294
|
+
vAsk
|
|
1295
|
+
);
|
|
1296
|
+
// should trigger market buy with above condition
|
|
1297
|
+
insertTriggerOrderToDLOB(
|
|
1298
|
+
dlob,
|
|
1299
|
+
Keypair.generate().publicKey,
|
|
1300
|
+
OrderType.TRIGGER_MARKET,
|
|
1301
|
+
MarketType.PERP,
|
|
1302
|
+
new BN(3), //orderId
|
|
1303
|
+
marketIndex, // marketIndex
|
|
1304
|
+
vAsk, // price
|
|
1305
|
+
BASE_PRECISION, // baseAssetAmount: BN,
|
|
1306
|
+
PositionDirection.LONG,
|
|
1307
|
+
oracle.price.sub(new BN(1)), // triggerPrice: BN,
|
|
1308
|
+
OrderTriggerCondition.ABOVE, // triggerCondition: OrderTriggerCondition,
|
|
1309
|
+
vBid,
|
|
1310
|
+
vAsk
|
|
1311
|
+
);
|
|
1312
|
+
// should trigger market sell with above condition
|
|
1313
|
+
insertTriggerOrderToDLOB(
|
|
1314
|
+
dlob,
|
|
1315
|
+
Keypair.generate().publicKey,
|
|
1316
|
+
OrderType.TRIGGER_MARKET,
|
|
1317
|
+
MarketType.PERP,
|
|
1318
|
+
new BN(4), //orderId
|
|
1319
|
+
marketIndex, // marketIndex
|
|
1320
|
+
vBid, // price
|
|
1321
|
+
BASE_PRECISION, // baseAssetAmount: BN,
|
|
1322
|
+
PositionDirection.SHORT,
|
|
1323
|
+
oracle.price.sub(new BN(1)), // triggerPrice: BN,
|
|
1324
|
+
OrderTriggerCondition.ABOVE, // triggerCondition: OrderTriggerCondition,
|
|
1325
|
+
vBid,
|
|
1326
|
+
vAsk
|
|
1327
|
+
);
|
|
1328
|
+
// should trigger limit buy with below condition
|
|
1329
|
+
insertTriggerOrderToDLOB(
|
|
1330
|
+
dlob,
|
|
1331
|
+
Keypair.generate().publicKey,
|
|
1332
|
+
OrderType.TRIGGER_LIMIT,
|
|
1333
|
+
MarketType.PERP,
|
|
1334
|
+
new BN(5), //orderId
|
|
1335
|
+
marketIndex, // marketIndex
|
|
1336
|
+
vBid, // price
|
|
1337
|
+
BASE_PRECISION, // baseAssetAmount: BN,
|
|
1338
|
+
PositionDirection.LONG,
|
|
1339
|
+
oracle.price.add(new BN(1)), // triggerPrice: BN,
|
|
1340
|
+
OrderTriggerCondition.BELOW, // triggerCondition: OrderTriggerCondition,
|
|
1341
|
+
vBid,
|
|
1342
|
+
vAsk
|
|
1343
|
+
);
|
|
1344
|
+
// should trigger limit sell with below condition
|
|
1345
|
+
insertTriggerOrderToDLOB(
|
|
1346
|
+
dlob,
|
|
1347
|
+
Keypair.generate().publicKey,
|
|
1348
|
+
OrderType.TRIGGER_LIMIT,
|
|
1349
|
+
MarketType.PERP,
|
|
1350
|
+
new BN(6), //orderId
|
|
1351
|
+
marketIndex, // marketIndex
|
|
1352
|
+
vBid, // price
|
|
1353
|
+
BASE_PRECISION, // baseAssetAmount: BN,
|
|
1354
|
+
PositionDirection.SHORT,
|
|
1355
|
+
oracle.price.add(new BN(1)), // triggerPrice: BN,
|
|
1356
|
+
OrderTriggerCondition.BELOW, // triggerCondition: OrderTriggerCondition,
|
|
1357
|
+
vBid,
|
|
1358
|
+
vAsk
|
|
1359
|
+
);
|
|
1360
|
+
// should trigger market buy with below condition
|
|
1361
|
+
insertTriggerOrderToDLOB(
|
|
1362
|
+
dlob,
|
|
1363
|
+
Keypair.generate().publicKey,
|
|
1364
|
+
OrderType.TRIGGER_MARKET,
|
|
1365
|
+
MarketType.PERP,
|
|
1366
|
+
new BN(7), //orderId
|
|
1367
|
+
marketIndex, // marketIndex
|
|
1368
|
+
vBid, // price
|
|
1369
|
+
BASE_PRECISION, // baseAssetAmount: BN,
|
|
1370
|
+
PositionDirection.LONG,
|
|
1371
|
+
oracle.price.add(new BN(1)), // triggerPrice: BN,
|
|
1372
|
+
OrderTriggerCondition.BELOW, // triggerCondition: OrderTriggerCondition,
|
|
1373
|
+
vBid,
|
|
1374
|
+
vAsk
|
|
1375
|
+
);
|
|
1376
|
+
// should trigger market sell with below condition
|
|
1377
|
+
insertTriggerOrderToDLOB(
|
|
1378
|
+
dlob,
|
|
1379
|
+
Keypair.generate().publicKey,
|
|
1380
|
+
OrderType.TRIGGER_MARKET,
|
|
1381
|
+
MarketType.PERP,
|
|
1382
|
+
new BN(8), //orderId
|
|
1383
|
+
marketIndex, // marketIndex
|
|
1384
|
+
vBid, // price
|
|
1385
|
+
BASE_PRECISION, // baseAssetAmount: BN,
|
|
1386
|
+
PositionDirection.LONG,
|
|
1387
|
+
oracle.price.add(new BN(1)), // triggerPrice: BN,
|
|
1388
|
+
OrderTriggerCondition.BELOW, // triggerCondition: OrderTriggerCondition,
|
|
1389
|
+
vBid,
|
|
1390
|
+
vAsk
|
|
1391
|
+
);
|
|
1392
|
+
|
|
1393
|
+
// should NOT trigger market sell with above condition
|
|
1394
|
+
insertTriggerOrderToDLOB(
|
|
1395
|
+
dlob,
|
|
1396
|
+
Keypair.generate().publicKey,
|
|
1397
|
+
OrderType.TRIGGER_MARKET,
|
|
1398
|
+
MarketType.PERP,
|
|
1399
|
+
new BN(9), //orderId
|
|
1400
|
+
marketIndex, // marketIndex
|
|
1401
|
+
vBid, // price
|
|
1402
|
+
BASE_PRECISION, // baseAssetAmount: BN,
|
|
1403
|
+
PositionDirection.SHORT,
|
|
1404
|
+
oracle.price.add(new BN(1)), // triggerPrice: BN,
|
|
1405
|
+
OrderTriggerCondition.ABOVE, // triggerCondition: OrderTriggerCondition,
|
|
1406
|
+
vBid,
|
|
1407
|
+
vAsk
|
|
1408
|
+
);
|
|
1409
|
+
// should NOT trigger market sell with below condition
|
|
1410
|
+
insertTriggerOrderToDLOB(
|
|
1411
|
+
dlob,
|
|
1412
|
+
Keypair.generate().publicKey,
|
|
1413
|
+
OrderType.TRIGGER_MARKET,
|
|
1414
|
+
MarketType.PERP,
|
|
1415
|
+
new BN(10), //orderId
|
|
1416
|
+
marketIndex, // marketIndex
|
|
1417
|
+
vBid, // price
|
|
1418
|
+
BASE_PRECISION, // baseAssetAmount: BN,
|
|
1419
|
+
PositionDirection.SHORT,
|
|
1420
|
+
oracle.price.sub(new BN(1)), // triggerPrice: BN,
|
|
1421
|
+
OrderTriggerCondition.BELOW, // triggerCondition: OrderTriggerCondition,
|
|
1422
|
+
vBid,
|
|
1423
|
+
vAsk
|
|
1424
|
+
);
|
|
1425
|
+
// should NOT trigger market buy with above condition
|
|
1426
|
+
insertTriggerOrderToDLOB(
|
|
1427
|
+
dlob,
|
|
1428
|
+
Keypair.generate().publicKey,
|
|
1429
|
+
OrderType.TRIGGER_MARKET,
|
|
1430
|
+
MarketType.PERP,
|
|
1431
|
+
new BN(11), //orderId
|
|
1432
|
+
marketIndex, // marketIndex
|
|
1433
|
+
vBid, // price
|
|
1434
|
+
BASE_PRECISION, // baseAssetAmount: BN,
|
|
1435
|
+
PositionDirection.LONG,
|
|
1436
|
+
oracle.price.add(new BN(1)), // triggerPrice: BN,
|
|
1437
|
+
OrderTriggerCondition.ABOVE, // triggerCondition: OrderTriggerCondition,
|
|
1438
|
+
vBid,
|
|
1439
|
+
vAsk
|
|
1440
|
+
);
|
|
1441
|
+
// should NOT trigger market buy with below condition
|
|
1442
|
+
insertTriggerOrderToDLOB(
|
|
1443
|
+
dlob,
|
|
1444
|
+
Keypair.generate().publicKey,
|
|
1445
|
+
OrderType.TRIGGER_MARKET,
|
|
1446
|
+
MarketType.PERP,
|
|
1447
|
+
new BN(12), //orderId
|
|
1448
|
+
marketIndex, // marketIndex
|
|
1449
|
+
vBid, // price
|
|
1450
|
+
BASE_PRECISION, // baseAssetAmount: BN,
|
|
1451
|
+
PositionDirection.LONG,
|
|
1452
|
+
oracle.price.sub(new BN(1)), // triggerPrice: BN,
|
|
1453
|
+
OrderTriggerCondition.BELOW, // triggerCondition: OrderTriggerCondition,
|
|
1454
|
+
vBid,
|
|
1455
|
+
vAsk
|
|
1456
|
+
);
|
|
1457
|
+
|
|
1458
|
+
const nodesToTrigger = dlob.findNodesToTrigger(
|
|
1459
|
+
marketIndex,
|
|
1460
|
+
slot,
|
|
1461
|
+
oracle.price,
|
|
1462
|
+
MarketType.PERP
|
|
1463
|
+
);
|
|
1464
|
+
console.log(`nodesToTriggeR: ${nodesToTrigger.length}`);
|
|
1465
|
+
for (const [idx, n] of nodesToTrigger.entries()) {
|
|
1466
|
+
expect(n.node.order?.orderId.toNumber()).to.equal(orderIdsToTrigger[idx]);
|
|
1467
|
+
console.log(`nodeToTrigger: ${n.node.order?.orderId.toString()}`);
|
|
1468
|
+
}
|
|
1469
|
+
});
|
|
1470
|
+
|
|
1471
|
+
it('Test will return expired market orders to fill', () => {
|
|
1472
|
+
const vAsk = new BN(15);
|
|
1473
|
+
const vBid = new BN(8);
|
|
1474
|
+
const dlob = new DLOB(mockPerpMarkets, mockSpotMarkets, false);
|
|
1475
|
+
const marketIndex = new BN(0);
|
|
1476
|
+
|
|
1477
|
+
const slot = 20;
|
|
1478
|
+
const timeInForce = 30;
|
|
1479
|
+
|
|
1480
|
+
// non crossing bid
|
|
1481
|
+
insertOrderToDLOB(
|
|
1482
|
+
dlob,
|
|
1483
|
+
Keypair.generate().publicKey,
|
|
1484
|
+
OrderType.MARKET,
|
|
1485
|
+
MarketType.PERP,
|
|
1486
|
+
new BN(255), // orderId
|
|
1487
|
+
marketIndex,
|
|
1488
|
+
new BN(2), // price, very low, don't cross vamm
|
|
1489
|
+
BASE_PRECISION, // quantity
|
|
1490
|
+
PositionDirection.LONG,
|
|
1491
|
+
vBid,
|
|
1492
|
+
vAsk,
|
|
1493
|
+
new BN(slot),
|
|
1494
|
+
timeInForce
|
|
1495
|
+
);
|
|
1496
|
+
insertOrderToDLOB(
|
|
1497
|
+
dlob,
|
|
1498
|
+
Keypair.generate().publicKey,
|
|
1499
|
+
OrderType.MARKET,
|
|
1500
|
+
MarketType.PERP,
|
|
1501
|
+
new BN(2), // orderId
|
|
1502
|
+
marketIndex,
|
|
1503
|
+
new BN(30), // price, very high, don't cross vamm
|
|
1504
|
+
BASE_PRECISION, // quantity
|
|
1505
|
+
PositionDirection.SHORT,
|
|
1506
|
+
vAsk,
|
|
1507
|
+
vBid,
|
|
1508
|
+
new BN(slot),
|
|
1509
|
+
timeInForce
|
|
1510
|
+
);
|
|
1511
|
+
|
|
1512
|
+
// order auction is not yet complete, and order is not expired.
|
|
1513
|
+
const slot0 = slot;
|
|
1514
|
+
const nodesToFillBefore = dlob.findNodesToFill(
|
|
1515
|
+
marketIndex,
|
|
1516
|
+
vBid,
|
|
1517
|
+
vAsk,
|
|
1518
|
+
slot0,
|
|
1519
|
+
MarketType.PERP,
|
|
1520
|
+
{
|
|
1521
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
1522
|
+
slot: new BN(slot0),
|
|
1523
|
+
confidence: new BN(1),
|
|
1524
|
+
hasSufficientNumberOfDataPoints: true,
|
|
1525
|
+
}
|
|
1526
|
+
);
|
|
1527
|
+
expect(nodesToFillBefore.length).to.equal(0);
|
|
1528
|
+
|
|
1529
|
+
// should get order to fill after timeInForce
|
|
1530
|
+
const slot1 = slot0 + timeInForce; // overshoots expiry
|
|
1531
|
+
const nodesToFillAfter = dlob.findNodesToFill(
|
|
1532
|
+
marketIndex,
|
|
1533
|
+
vBid,
|
|
1534
|
+
vAsk,
|
|
1535
|
+
slot1, // auction is over, and order ix expired
|
|
1536
|
+
MarketType.PERP,
|
|
1537
|
+
{
|
|
1538
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
1539
|
+
slot: new BN(slot1),
|
|
1540
|
+
confidence: new BN(1),
|
|
1541
|
+
hasSufficientNumberOfDataPoints: true,
|
|
1542
|
+
}
|
|
1543
|
+
);
|
|
1544
|
+
expect(nodesToFillAfter.length).to.equal(2);
|
|
1545
|
+
|
|
1546
|
+
// check that the nodes have no makers
|
|
1547
|
+
expect(nodesToFillAfter[0].makerNode).to.equal(undefined);
|
|
1548
|
+
expect(nodesToFillAfter[1].makerNode).to.equal(undefined);
|
|
1549
|
+
});
|
|
1550
|
+
});
|
|
1551
|
+
|
|
1552
|
+
describe('DLOB Spot Tests', () => {
|
|
1553
|
+
it('Test proper bids', () => {
|
|
1554
|
+
const vAsk = new BN(115);
|
|
1555
|
+
const vBid = new BN(100);
|
|
1556
|
+
const dlob = new DLOB(mockPerpMarkets, mockSpotMarkets, false);
|
|
1557
|
+
const marketIndex = new BN(0);
|
|
1558
|
+
|
|
1559
|
+
const slot = 12;
|
|
1560
|
+
const oracle = {
|
|
1561
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
1562
|
+
slot: new BN(slot),
|
|
1563
|
+
confidence: new BN(1),
|
|
1564
|
+
hasSufficientNumberOfDataPoints: true,
|
|
1565
|
+
};
|
|
1566
|
+
const testCases = [
|
|
1567
|
+
{
|
|
1568
|
+
expectedIdx: 3,
|
|
1569
|
+
orderId: new BN(5),
|
|
1570
|
+
price: new BN(0), // will calc 108
|
|
1571
|
+
direction: PositionDirection.LONG,
|
|
1572
|
+
orderType: OrderType.MARKET,
|
|
1573
|
+
},
|
|
1574
|
+
{
|
|
1575
|
+
expectedIdx: 4,
|
|
1576
|
+
orderId: new BN(6),
|
|
1577
|
+
price: new BN(0), // will calc 108
|
|
1578
|
+
direction: PositionDirection.LONG,
|
|
1579
|
+
orderType: OrderType.MARKET,
|
|
1580
|
+
},
|
|
1581
|
+
{
|
|
1582
|
+
expectedIdx: 5,
|
|
1583
|
+
orderId: new BN(7),
|
|
1584
|
+
price: new BN(0), // will calc 108
|
|
1585
|
+
direction: PositionDirection.LONG,
|
|
1586
|
+
orderType: OrderType.MARKET,
|
|
1587
|
+
},
|
|
1588
|
+
{
|
|
1589
|
+
expectedIdx: 0,
|
|
1590
|
+
orderId: new BN(1),
|
|
1591
|
+
price: new BN(110),
|
|
1592
|
+
direction: PositionDirection.LONG,
|
|
1593
|
+
orderType: OrderType.LIMIT,
|
|
1594
|
+
},
|
|
1595
|
+
{
|
|
1596
|
+
expectedIdx: 1,
|
|
1597
|
+
orderId: new BN(2),
|
|
1598
|
+
price: new BN(109),
|
|
1599
|
+
direction: PositionDirection.LONG,
|
|
1600
|
+
orderType: OrderType.LIMIT,
|
|
1601
|
+
},
|
|
1602
|
+
{
|
|
1603
|
+
expectedIdx: 6,
|
|
1604
|
+
orderId: new BN(3),
|
|
1605
|
+
price: new BN(107),
|
|
1606
|
+
direction: PositionDirection.LONG,
|
|
1607
|
+
orderType: OrderType.LIMIT,
|
|
1608
|
+
},
|
|
1609
|
+
{
|
|
1610
|
+
expectedIdx: 7,
|
|
1611
|
+
orderId: new BN(4),
|
|
1612
|
+
price: new BN(106),
|
|
1613
|
+
direction: PositionDirection.LONG,
|
|
1614
|
+
orderType: OrderType.LIMIT,
|
|
1615
|
+
},
|
|
1616
|
+
];
|
|
1617
|
+
|
|
1618
|
+
for (const t of testCases) {
|
|
1619
|
+
insertOrderToDLOB(
|
|
1620
|
+
dlob,
|
|
1621
|
+
Keypair.generate().publicKey,
|
|
1622
|
+
t.orderType || OrderType.LIMIT,
|
|
1623
|
+
MarketType.SPOT,
|
|
1624
|
+
t.orderId || new BN(0), // orderId
|
|
1625
|
+
marketIndex,
|
|
1626
|
+
t.price || new BN(0), // price
|
|
1627
|
+
BASE_PRECISION, // quantity
|
|
1628
|
+
t.direction || PositionDirection.LONG,
|
|
1629
|
+
vBid,
|
|
1630
|
+
vAsk
|
|
1631
|
+
);
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
const expectedTestCase = testCases.sort((a, b) => {
|
|
1635
|
+
// ascending order
|
|
1636
|
+
return a.expectedIdx - b.expectedIdx;
|
|
1637
|
+
});
|
|
1638
|
+
const bids = dlob.getBids(
|
|
1639
|
+
marketIndex,
|
|
1640
|
+
undefined,
|
|
1641
|
+
slot,
|
|
1642
|
+
MarketType.SPOT,
|
|
1643
|
+
oracle
|
|
1644
|
+
);
|
|
1645
|
+
|
|
1646
|
+
console.log('The Book Bids:');
|
|
1647
|
+
let countBids = 0;
|
|
1648
|
+
for (const bid of bids) {
|
|
1649
|
+
console.log(
|
|
1650
|
+
` . vAMMNode? ${bid.isVammNode()}, ${JSON.stringify(
|
|
1651
|
+
bid.order?.orderType
|
|
1652
|
+
)} , ${bid.order?.orderId.toString()} , vammTestgetPRice: ${bid.getPrice(
|
|
1653
|
+
oracle,
|
|
1654
|
+
slot
|
|
1655
|
+
)}, price: ${bid.order?.price.toString()}, quantity: ${bid.order?.baseAssetAmountFilled.toString()}/${bid.order?.baseAssetAmount.toString()}`
|
|
1656
|
+
);
|
|
1657
|
+
|
|
1658
|
+
expect(bid.order?.orderId.toNumber()).to.equal(
|
|
1659
|
+
expectedTestCase[countBids].orderId?.toNumber()
|
|
1660
|
+
);
|
|
1661
|
+
expect(bid.order?.price.toNumber()).to.equal(
|
|
1662
|
+
expectedTestCase[countBids].price?.toNumber()
|
|
1663
|
+
);
|
|
1664
|
+
expect(bid.order?.direction).to.equal(
|
|
1665
|
+
expectedTestCase[countBids].direction
|
|
1666
|
+
);
|
|
1667
|
+
expect(bid.order?.orderType).to.equal(
|
|
1668
|
+
expectedTestCase[countBids].orderType
|
|
1669
|
+
);
|
|
1670
|
+
countBids++;
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
expect(countBids).to.equal(testCases.length);
|
|
1674
|
+
});
|
|
1675
|
+
|
|
1676
|
+
it('Test proper bids on multiple markets', () => {
|
|
1677
|
+
const vAsk = new BN(15);
|
|
1678
|
+
const vBid = new BN(10);
|
|
1679
|
+
const dlob = new DLOB(mockPerpMarkets, mockSpotMarkets, false);
|
|
1680
|
+
const marketIndex0 = new BN(0);
|
|
1681
|
+
const marketIndex1 = new BN(1);
|
|
1682
|
+
|
|
1683
|
+
const slot = 12;
|
|
1684
|
+
const oracle = {
|
|
1685
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
1686
|
+
slot: new BN(slot),
|
|
1687
|
+
confidence: new BN(1),
|
|
1688
|
+
hasSufficientNumberOfDataPoints: true,
|
|
1689
|
+
};
|
|
1690
|
+
const testCases = [
|
|
1691
|
+
{
|
|
1692
|
+
expectedIdx: 3,
|
|
1693
|
+
orderId: new BN(5),
|
|
1694
|
+
price: new BN(0),
|
|
1695
|
+
direction: PositionDirection.LONG,
|
|
1696
|
+
orderType: OrderType.MARKET,
|
|
1697
|
+
marketIndex: marketIndex0,
|
|
1698
|
+
},
|
|
1699
|
+
{
|
|
1700
|
+
expectedIdx: 4,
|
|
1701
|
+
orderId: new BN(6),
|
|
1702
|
+
price: new BN(0),
|
|
1703
|
+
direction: PositionDirection.LONG,
|
|
1704
|
+
orderType: OrderType.MARKET,
|
|
1705
|
+
marketIndex: marketIndex0,
|
|
1706
|
+
},
|
|
1707
|
+
{
|
|
1708
|
+
expectedIdx: 5,
|
|
1709
|
+
orderId: new BN(7),
|
|
1710
|
+
price: new BN(0),
|
|
1711
|
+
direction: PositionDirection.LONG,
|
|
1712
|
+
orderType: OrderType.MARKET,
|
|
1713
|
+
marketIndex: marketIndex1,
|
|
1714
|
+
},
|
|
1715
|
+
{
|
|
1716
|
+
expectedIdx: 0,
|
|
1717
|
+
orderId: new BN(1),
|
|
1718
|
+
price: new BN(12),
|
|
1719
|
+
direction: PositionDirection.LONG,
|
|
1720
|
+
orderType: OrderType.LIMIT,
|
|
1721
|
+
marketIndex: marketIndex0,
|
|
1722
|
+
},
|
|
1723
|
+
{
|
|
1724
|
+
expectedIdx: 1,
|
|
1725
|
+
orderId: new BN(2),
|
|
1726
|
+
price: new BN(11),
|
|
1727
|
+
direction: PositionDirection.LONG,
|
|
1728
|
+
orderType: OrderType.LIMIT,
|
|
1729
|
+
marketIndex: marketIndex0,
|
|
1730
|
+
},
|
|
1731
|
+
{
|
|
1732
|
+
expectedIdx: 7,
|
|
1733
|
+
orderId: new BN(3),
|
|
1734
|
+
price: new BN(8),
|
|
1735
|
+
direction: PositionDirection.LONG,
|
|
1736
|
+
orderType: OrderType.LIMIT,
|
|
1737
|
+
marketIndex: marketIndex0,
|
|
1738
|
+
},
|
|
1739
|
+
{
|
|
1740
|
+
expectedIdx: 6,
|
|
1741
|
+
orderId: new BN(4),
|
|
1742
|
+
price: new BN(9),
|
|
1743
|
+
direction: PositionDirection.LONG,
|
|
1744
|
+
orderType: OrderType.LIMIT,
|
|
1745
|
+
marketIndex: marketIndex1,
|
|
1746
|
+
},
|
|
1747
|
+
];
|
|
1748
|
+
|
|
1749
|
+
for (const t of testCases) {
|
|
1750
|
+
insertOrderToDLOB(
|
|
1751
|
+
dlob,
|
|
1752
|
+
Keypair.generate().publicKey,
|
|
1753
|
+
t.orderType || OrderType.LIMIT,
|
|
1754
|
+
MarketType.SPOT,
|
|
1755
|
+
t.orderId || new BN(0), // orderId
|
|
1756
|
+
t.marketIndex,
|
|
1757
|
+
t.price || new BN(0), // price
|
|
1758
|
+
BASE_PRECISION, // quantity
|
|
1759
|
+
t.direction || PositionDirection.LONG,
|
|
1760
|
+
vBid,
|
|
1761
|
+
vAsk
|
|
1762
|
+
);
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
const bids0 = dlob.getBids(
|
|
1766
|
+
marketIndex0,
|
|
1767
|
+
vBid,
|
|
1768
|
+
slot,
|
|
1769
|
+
MarketType.SPOT,
|
|
1770
|
+
oracle
|
|
1771
|
+
);
|
|
1772
|
+
let countBids0 = 0;
|
|
1773
|
+
for (const bid of bids0) {
|
|
1774
|
+
console.log(
|
|
1775
|
+
` . vAMMNode? ${bid.isVammNode()}, ${JSON.stringify(
|
|
1776
|
+
bid.order?.orderType
|
|
1777
|
+
)} , ${bid.order?.orderId.toString()} , vammTestgetPRice: ${bid.getPrice(
|
|
1778
|
+
oracle,
|
|
1779
|
+
slot
|
|
1780
|
+
)}, price: ${bid.order?.price.toString()}, quantity: ${bid.order?.baseAssetAmountFilled.toString()}/${bid.order?.baseAssetAmount.toString()}`
|
|
1781
|
+
);
|
|
1782
|
+
countBids0++;
|
|
1783
|
+
}
|
|
1784
|
+
expect(countBids0).to.equal(5);
|
|
1785
|
+
|
|
1786
|
+
const bids1 = dlob.getBids(
|
|
1787
|
+
marketIndex1,
|
|
1788
|
+
vBid,
|
|
1789
|
+
slot,
|
|
1790
|
+
MarketType.SPOT,
|
|
1791
|
+
oracle
|
|
1792
|
+
);
|
|
1793
|
+
let countBids1 = 0;
|
|
1794
|
+
for (const bid of bids1) {
|
|
1795
|
+
console.log(
|
|
1796
|
+
` . vAMMNode? ${bid.isVammNode()}, ${JSON.stringify(
|
|
1797
|
+
bid.order?.orderType
|
|
1798
|
+
)} , ${bid.order?.orderId.toString()} , vammTestgetPRice: ${bid.getPrice(
|
|
1799
|
+
oracle,
|
|
1800
|
+
slot
|
|
1801
|
+
)}, price: ${bid.order?.price.toString()}, quantity: ${bid.order?.baseAssetAmountFilled.toString()}/${bid.order?.baseAssetAmount.toString()}`
|
|
1802
|
+
);
|
|
1803
|
+
|
|
1804
|
+
countBids1++;
|
|
1805
|
+
}
|
|
1806
|
+
expect(countBids1).to.equal(2);
|
|
1807
|
+
});
|
|
1808
|
+
|
|
1809
|
+
it('Test proper asks', () => {
|
|
1810
|
+
const vAsk = new BN(15);
|
|
1811
|
+
const vBid = new BN(10);
|
|
1812
|
+
const dlob = new DLOB(mockPerpMarkets, mockSpotMarkets, false);
|
|
1813
|
+
const marketIndex = new BN(0);
|
|
1814
|
+
|
|
1815
|
+
const slot = 12;
|
|
1816
|
+
const oracle = {
|
|
1817
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
1818
|
+
slot: new BN(slot),
|
|
1819
|
+
confidence: new BN(1),
|
|
1820
|
+
hasSufficientNumberOfDataPoints: true,
|
|
1821
|
+
};
|
|
1822
|
+
const testCases = [
|
|
1823
|
+
{
|
|
1824
|
+
expectedIdx: 0,
|
|
1825
|
+
orderId: new BN(3),
|
|
1826
|
+
price: new BN(0),
|
|
1827
|
+
direction: PositionDirection.SHORT,
|
|
1828
|
+
orderType: OrderType.MARKET,
|
|
1829
|
+
},
|
|
1830
|
+
{
|
|
1831
|
+
expectedIdx: 1,
|
|
1832
|
+
orderId: new BN(4),
|
|
1833
|
+
price: new BN(0),
|
|
1834
|
+
direction: PositionDirection.SHORT,
|
|
1835
|
+
orderType: OrderType.MARKET,
|
|
1836
|
+
},
|
|
1837
|
+
{
|
|
1838
|
+
expectedIdx: 2,
|
|
1839
|
+
orderId: new BN(5),
|
|
1840
|
+
price: new BN(0),
|
|
1841
|
+
direction: PositionDirection.SHORT,
|
|
1842
|
+
orderType: OrderType.MARKET,
|
|
1843
|
+
},
|
|
1844
|
+
{
|
|
1845
|
+
expectedIdx: 3,
|
|
1846
|
+
orderId: new BN(1),
|
|
1847
|
+
price: new BN(13),
|
|
1848
|
+
direction: PositionDirection.SHORT,
|
|
1849
|
+
orderType: OrderType.LIMIT,
|
|
1850
|
+
},
|
|
1851
|
+
{
|
|
1852
|
+
expectedIdx: 6,
|
|
1853
|
+
orderId: new BN(6),
|
|
1854
|
+
price: new BN(16),
|
|
1855
|
+
direction: PositionDirection.SHORT,
|
|
1856
|
+
orderType: OrderType.LIMIT,
|
|
1857
|
+
},
|
|
1858
|
+
{
|
|
1859
|
+
expectedIdx: 7,
|
|
1860
|
+
orderId: new BN(7),
|
|
1861
|
+
price: new BN(17),
|
|
1862
|
+
direction: PositionDirection.SHORT,
|
|
1863
|
+
orderType: OrderType.LIMIT,
|
|
1864
|
+
},
|
|
1865
|
+
{
|
|
1866
|
+
expectedIdx: 4,
|
|
1867
|
+
orderId: new BN(2),
|
|
1868
|
+
price: new BN(14),
|
|
1869
|
+
direction: PositionDirection.SHORT,
|
|
1870
|
+
orderType: OrderType.LIMIT,
|
|
1871
|
+
},
|
|
1872
|
+
];
|
|
1873
|
+
|
|
1874
|
+
for (const t of testCases) {
|
|
1875
|
+
insertOrderToDLOB(
|
|
1876
|
+
dlob,
|
|
1877
|
+
Keypair.generate().publicKey,
|
|
1878
|
+
t.orderType || OrderType.LIMIT,
|
|
1879
|
+
MarketType.SPOT,
|
|
1880
|
+
t.orderId || new BN(0), // orderId
|
|
1881
|
+
marketIndex,
|
|
1882
|
+
t.price || new BN(0), // price
|
|
1883
|
+
BASE_PRECISION, // quantity
|
|
1884
|
+
t.direction || PositionDirection.SHORT,
|
|
1885
|
+
vBid,
|
|
1886
|
+
vAsk
|
|
1887
|
+
);
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
const expectedTestCase = testCases.sort((a, b) => {
|
|
1891
|
+
// ascending order
|
|
1892
|
+
return a.expectedIdx - b.expectedIdx;
|
|
1893
|
+
});
|
|
1894
|
+
const asks = dlob.getAsks(marketIndex, vAsk, slot, MarketType.SPOT, oracle);
|
|
1895
|
+
|
|
1896
|
+
console.log('The Book Asks:');
|
|
1897
|
+
let countAsks = 0;
|
|
1898
|
+
for (const ask of asks) {
|
|
1899
|
+
console.log(
|
|
1900
|
+
` . vAMMNode? ${ask.isVammNode()}, ${JSON.stringify(
|
|
1901
|
+
ask.order?.orderType
|
|
1902
|
+
)} , ${ask.order?.orderId.toString()} , vammTestgetPRice: ${ask.getPrice(
|
|
1903
|
+
oracle,
|
|
1904
|
+
slot
|
|
1905
|
+
)}, price: ${ask.order?.price.toString()}, quantity: ${ask.order?.baseAssetAmountFilled.toString()}/${ask.order?.baseAssetAmount.toString()}`
|
|
1906
|
+
);
|
|
1907
|
+
|
|
1908
|
+
expect(ask.order?.orderId.toNumber()).to.equal(
|
|
1909
|
+
expectedTestCase[countAsks].orderId?.toNumber()
|
|
1910
|
+
);
|
|
1911
|
+
expect(ask.order?.price.toNumber()).to.equal(
|
|
1912
|
+
expectedTestCase[countAsks].price?.toNumber()
|
|
1913
|
+
);
|
|
1914
|
+
expect(ask.order?.direction).to.equal(
|
|
1915
|
+
expectedTestCase[countAsks].direction
|
|
1916
|
+
);
|
|
1917
|
+
expect(ask.order?.orderType).to.equal(
|
|
1918
|
+
expectedTestCase[countAsks].orderType
|
|
1919
|
+
);
|
|
1920
|
+
countAsks++;
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
expect(countAsks).to.equal(testCases.length);
|
|
1924
|
+
});
|
|
1925
|
+
|
|
1926
|
+
it('Test insert market orders', () => {
|
|
1927
|
+
const slot = 12;
|
|
1928
|
+
const vAsk = new BN(110);
|
|
1929
|
+
const vBid = new BN(100);
|
|
1930
|
+
const oracle = {
|
|
1931
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
1932
|
+
slot: new BN(slot),
|
|
1933
|
+
confidence: new BN(1),
|
|
1934
|
+
hasSufficientNumberOfDataPoints: true,
|
|
1935
|
+
};
|
|
1936
|
+
const dlob = new DLOB(mockPerpMarkets, mockSpotMarkets, false);
|
|
1937
|
+
const marketIndex = new BN(0);
|
|
1938
|
+
|
|
1939
|
+
// 3 mkt buys
|
|
1940
|
+
for (let i = 0; i < 3; i++) {
|
|
1941
|
+
insertOrderToDLOB(
|
|
1942
|
+
dlob,
|
|
1943
|
+
Keypair.generate().publicKey,
|
|
1944
|
+
OrderType.MARKET,
|
|
1945
|
+
MarketType.SPOT,
|
|
1946
|
+
new BN(i + 1),
|
|
1947
|
+
marketIndex,
|
|
1948
|
+
new BN(0),
|
|
1949
|
+
BASE_PRECISION,
|
|
1950
|
+
PositionDirection.LONG,
|
|
1951
|
+
vBid,
|
|
1952
|
+
vAsk
|
|
1953
|
+
);
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
// 3 mkt sells
|
|
1957
|
+
for (let i = 0; i < 3; i++) {
|
|
1958
|
+
insertOrderToDLOB(
|
|
1959
|
+
dlob,
|
|
1960
|
+
Keypair.generate().publicKey,
|
|
1961
|
+
OrderType.MARKET,
|
|
1962
|
+
MarketType.SPOT,
|
|
1963
|
+
new BN(i + 1),
|
|
1964
|
+
marketIndex,
|
|
1965
|
+
new BN(0),
|
|
1966
|
+
BASE_PRECISION,
|
|
1967
|
+
PositionDirection.SHORT,
|
|
1968
|
+
vBid,
|
|
1969
|
+
vAsk
|
|
1970
|
+
);
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
let asks = 0;
|
|
1974
|
+
for (const ask of dlob.getAsks(
|
|
1975
|
+
marketIndex,
|
|
1976
|
+
vAsk,
|
|
1977
|
+
2,
|
|
1978
|
+
MarketType.SPOT,
|
|
1979
|
+
oracle
|
|
1980
|
+
)) {
|
|
1981
|
+
// vamm node is last in asks
|
|
1982
|
+
asks++;
|
|
1983
|
+
|
|
1984
|
+
if (ask.order) {
|
|
1985
|
+
// market orders
|
|
1986
|
+
expect(getVariant(ask.order?.status)).to.equal('open');
|
|
1987
|
+
expect(getVariant(ask.order?.orderType)).to.equal('market');
|
|
1988
|
+
expect(getVariant(ask.order?.direction)).to.equal('short');
|
|
1989
|
+
expect(ask.order?.orderId.toNumber()).to.equal(asks);
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
expect(asks).to.equal(3);
|
|
1993
|
+
|
|
1994
|
+
let bids = 0;
|
|
1995
|
+
for (const bid of dlob.getBids(
|
|
1996
|
+
marketIndex,
|
|
1997
|
+
vBid,
|
|
1998
|
+
2,
|
|
1999
|
+
MarketType.SPOT,
|
|
2000
|
+
oracle
|
|
2001
|
+
)) {
|
|
2002
|
+
// market orders
|
|
2003
|
+
expect(getVariant(bid.order?.status)).to.equal('open');
|
|
2004
|
+
expect(getVariant(bid.order?.orderType)).to.equal('market');
|
|
2005
|
+
expect(getVariant(bid.order?.direction)).to.equal('long');
|
|
2006
|
+
expect(bid.order?.orderId.toNumber()).to.equal(bids + 1);
|
|
2007
|
+
bids++;
|
|
2008
|
+
}
|
|
2009
|
+
expect(bids).to.equal(3); // 3 orders
|
|
2010
|
+
});
|
|
2011
|
+
|
|
2012
|
+
it('Test insert limit orders', () => {
|
|
2013
|
+
const vAsk = new BN(110);
|
|
2014
|
+
const vBid = new BN(100);
|
|
2015
|
+
const slot = 12;
|
|
2016
|
+
const oracle = {
|
|
2017
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
2018
|
+
slot: new BN(slot),
|
|
2019
|
+
confidence: new BN(1),
|
|
2020
|
+
hasSufficientNumberOfDataPoints: true,
|
|
2021
|
+
};
|
|
2022
|
+
const dlob = new DLOB(mockPerpMarkets, mockSpotMarkets, false);
|
|
2023
|
+
const marketIndex = new BN(0);
|
|
2024
|
+
insertOrderToDLOB(
|
|
2025
|
+
dlob,
|
|
2026
|
+
Keypair.generate().publicKey,
|
|
2027
|
+
OrderType.LIMIT,
|
|
2028
|
+
MarketType.SPOT,
|
|
2029
|
+
new BN(3),
|
|
2030
|
+
marketIndex,
|
|
2031
|
+
new BN(50),
|
|
2032
|
+
BASE_PRECISION,
|
|
2033
|
+
PositionDirection.LONG,
|
|
2034
|
+
vBid,
|
|
2035
|
+
vAsk
|
|
2036
|
+
);
|
|
2037
|
+
|
|
2038
|
+
insertOrderToDLOB(
|
|
2039
|
+
dlob,
|
|
2040
|
+
Keypair.generate().publicKey,
|
|
2041
|
+
OrderType.LIMIT,
|
|
2042
|
+
MarketType.SPOT,
|
|
2043
|
+
new BN(2),
|
|
2044
|
+
marketIndex,
|
|
2045
|
+
new BN(60),
|
|
2046
|
+
BASE_PRECISION,
|
|
2047
|
+
PositionDirection.LONG,
|
|
2048
|
+
vBid,
|
|
2049
|
+
vAsk
|
|
2050
|
+
);
|
|
2051
|
+
|
|
2052
|
+
insertOrderToDLOB(
|
|
2053
|
+
dlob,
|
|
2054
|
+
Keypair.generate().publicKey,
|
|
2055
|
+
OrderType.LIMIT,
|
|
2056
|
+
MarketType.SPOT,
|
|
2057
|
+
new BN(1),
|
|
2058
|
+
marketIndex,
|
|
2059
|
+
new BN(70),
|
|
2060
|
+
BASE_PRECISION,
|
|
2061
|
+
PositionDirection.LONG,
|
|
2062
|
+
vBid,
|
|
2063
|
+
vAsk
|
|
2064
|
+
);
|
|
2065
|
+
|
|
2066
|
+
insertOrderToDLOB(
|
|
2067
|
+
dlob,
|
|
2068
|
+
Keypair.generate().publicKey,
|
|
2069
|
+
OrderType.LIMIT,
|
|
2070
|
+
MarketType.SPOT,
|
|
2071
|
+
new BN(1),
|
|
2072
|
+
marketIndex,
|
|
2073
|
+
new BN(120),
|
|
2074
|
+
BASE_PRECISION,
|
|
2075
|
+
PositionDirection.SHORT,
|
|
2076
|
+
vBid,
|
|
2077
|
+
vAsk
|
|
2078
|
+
);
|
|
2079
|
+
|
|
2080
|
+
insertOrderToDLOB(
|
|
2081
|
+
dlob,
|
|
2082
|
+
Keypair.generate().publicKey,
|
|
2083
|
+
OrderType.LIMIT,
|
|
2084
|
+
MarketType.SPOT,
|
|
2085
|
+
new BN(2),
|
|
2086
|
+
marketIndex,
|
|
2087
|
+
new BN(130),
|
|
2088
|
+
BASE_PRECISION,
|
|
2089
|
+
PositionDirection.SHORT,
|
|
2090
|
+
vBid,
|
|
2091
|
+
vAsk
|
|
2092
|
+
);
|
|
2093
|
+
|
|
2094
|
+
insertOrderToDLOB(
|
|
2095
|
+
dlob,
|
|
2096
|
+
Keypair.generate().publicKey,
|
|
2097
|
+
OrderType.LIMIT,
|
|
2098
|
+
MarketType.SPOT,
|
|
2099
|
+
new BN(3),
|
|
2100
|
+
marketIndex,
|
|
2101
|
+
new BN(140),
|
|
2102
|
+
BASE_PRECISION,
|
|
2103
|
+
PositionDirection.SHORT,
|
|
2104
|
+
vBid,
|
|
2105
|
+
vAsk
|
|
2106
|
+
);
|
|
2107
|
+
|
|
2108
|
+
let asks = 0;
|
|
2109
|
+
for (const ask of dlob.getAsks(
|
|
2110
|
+
marketIndex,
|
|
2111
|
+
vAsk,
|
|
2112
|
+
slot,
|
|
2113
|
+
MarketType.SPOT,
|
|
2114
|
+
oracle
|
|
2115
|
+
)) {
|
|
2116
|
+
if (!ask.order) {
|
|
2117
|
+
console.error('wtf ask vamm?');
|
|
2118
|
+
continue;
|
|
2119
|
+
}
|
|
2120
|
+
// market orders
|
|
2121
|
+
console.log(`ask price: ${ask.order?.price.toString()}`);
|
|
2122
|
+
expect(getVariant(ask.order?.status)).to.equal('open');
|
|
2123
|
+
expect(getVariant(ask.order?.orderType)).to.equal('limit');
|
|
2124
|
+
expect(getVariant(ask.order?.direction)).to.equal('short');
|
|
2125
|
+
expect(ask.order?.orderId.toNumber()).to.equal(asks + 1);
|
|
2126
|
+
expect(ask.order?.price.gt(vAsk)).to.equal(true);
|
|
2127
|
+
asks++;
|
|
2128
|
+
}
|
|
2129
|
+
expect(asks).to.equal(3);
|
|
2130
|
+
|
|
2131
|
+
let bids = 0;
|
|
2132
|
+
for (const bid of dlob.getBids(
|
|
2133
|
+
marketIndex,
|
|
2134
|
+
vBid,
|
|
2135
|
+
slot,
|
|
2136
|
+
MarketType.SPOT,
|
|
2137
|
+
oracle
|
|
2138
|
+
)) {
|
|
2139
|
+
if (!bid.order) {
|
|
2140
|
+
console.error('wtf bid vamm?');
|
|
2141
|
+
continue;
|
|
2142
|
+
}
|
|
2143
|
+
// market orders
|
|
2144
|
+
console.log(`bid price: ${bid.order?.price.toString()}`);
|
|
2145
|
+
expect(getVariant(bid.order?.status)).to.equal('open');
|
|
2146
|
+
expect(getVariant(bid.order?.orderType)).to.equal('limit');
|
|
2147
|
+
expect(getVariant(bid.order?.direction)).to.equal('long');
|
|
2148
|
+
expect(bid.order?.orderId.toNumber()).to.equal(bids + 1);
|
|
2149
|
+
expect(bid.order?.price.lt(vBid)).to.equal(true);
|
|
2150
|
+
bids++;
|
|
2151
|
+
}
|
|
2152
|
+
expect(bids).to.equal(3);
|
|
2153
|
+
});
|
|
2154
|
+
|
|
2155
|
+
it('Test multiple market orders fill with multiple limit orders', () => {
|
|
2156
|
+
const vAsk = new BN(15);
|
|
2157
|
+
const vBid = new BN(10);
|
|
2158
|
+
const dlob = new DLOB(mockPerpMarkets, mockSpotMarkets, false);
|
|
2159
|
+
const marketIndex = new BN(0);
|
|
2160
|
+
|
|
2161
|
+
// insert some limit buys above vamm bid, below ask
|
|
2162
|
+
insertOrderToDLOB(
|
|
2163
|
+
dlob,
|
|
2164
|
+
Keypair.generate().publicKey,
|
|
2165
|
+
OrderType.LIMIT,
|
|
2166
|
+
MarketType.SPOT,
|
|
2167
|
+
new BN(1), // orderId
|
|
2168
|
+
marketIndex,
|
|
2169
|
+
new BN(11), // price
|
|
2170
|
+
BASE_PRECISION, // quantity
|
|
2171
|
+
PositionDirection.LONG,
|
|
2172
|
+
vBid,
|
|
2173
|
+
vAsk
|
|
2174
|
+
);
|
|
2175
|
+
insertOrderToDLOB(
|
|
2176
|
+
dlob,
|
|
2177
|
+
Keypair.generate().publicKey,
|
|
2178
|
+
OrderType.LIMIT,
|
|
2179
|
+
MarketType.SPOT,
|
|
2180
|
+
new BN(2), // orderId
|
|
2181
|
+
marketIndex,
|
|
2182
|
+
new BN(12), // price
|
|
2183
|
+
BASE_PRECISION, // quantity
|
|
2184
|
+
PositionDirection.LONG,
|
|
2185
|
+
vBid,
|
|
2186
|
+
vAsk
|
|
2187
|
+
);
|
|
2188
|
+
insertOrderToDLOB(
|
|
2189
|
+
dlob,
|
|
2190
|
+
Keypair.generate().publicKey,
|
|
2191
|
+
OrderType.LIMIT,
|
|
2192
|
+
MarketType.SPOT,
|
|
2193
|
+
new BN(3), // orderId
|
|
2194
|
+
marketIndex,
|
|
2195
|
+
new BN(13), // price
|
|
2196
|
+
BASE_PRECISION, // quantity
|
|
2197
|
+
PositionDirection.LONG,
|
|
2198
|
+
vBid,
|
|
2199
|
+
vAsk
|
|
2200
|
+
);
|
|
2201
|
+
|
|
2202
|
+
// should have no crossing orders
|
|
2203
|
+
const nodesToFillBefore = dlob.findCrossingNodesToFill(
|
|
2204
|
+
marketIndex,
|
|
2205
|
+
vBid,
|
|
2206
|
+
vAsk,
|
|
2207
|
+
12, // auction over
|
|
2208
|
+
MarketType.SPOT,
|
|
2209
|
+
{
|
|
2210
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
2211
|
+
slot: new BN(12),
|
|
2212
|
+
confidence: new BN(1),
|
|
2213
|
+
hasSufficientNumberOfDataPoints: true,
|
|
2214
|
+
}
|
|
2215
|
+
);
|
|
2216
|
+
expect(nodesToFillBefore.length).to.equal(0);
|
|
2217
|
+
|
|
2218
|
+
// place two market sell order eating 2 of the limit orders
|
|
2219
|
+
insertOrderToDLOB(
|
|
2220
|
+
dlob,
|
|
2221
|
+
Keypair.generate().publicKey,
|
|
2222
|
+
OrderType.MARKET,
|
|
2223
|
+
MarketType.SPOT,
|
|
2224
|
+
new BN(4), // orderId
|
|
2225
|
+
marketIndex,
|
|
2226
|
+
new BN(12), // price
|
|
2227
|
+
new BN(1).mul(BASE_PRECISION), // quantity
|
|
2228
|
+
PositionDirection.SHORT,
|
|
2229
|
+
vBid,
|
|
2230
|
+
vAsk
|
|
2231
|
+
);
|
|
2232
|
+
insertOrderToDLOB(
|
|
2233
|
+
dlob,
|
|
2234
|
+
Keypair.generate().publicKey,
|
|
2235
|
+
OrderType.MARKET,
|
|
2236
|
+
MarketType.SPOT,
|
|
2237
|
+
new BN(5), // orderId
|
|
2238
|
+
marketIndex,
|
|
2239
|
+
new BN(12), // price
|
|
2240
|
+
new BN(1).mul(BASE_PRECISION), // quantity
|
|
2241
|
+
PositionDirection.SHORT,
|
|
2242
|
+
vBid,
|
|
2243
|
+
vAsk
|
|
2244
|
+
);
|
|
2245
|
+
|
|
2246
|
+
const nodesToFillAfter = dlob.findCrossingNodesToFill(
|
|
2247
|
+
marketIndex,
|
|
2248
|
+
vBid,
|
|
2249
|
+
vAsk,
|
|
2250
|
+
12, // auction over
|
|
2251
|
+
MarketType.SPOT,
|
|
2252
|
+
{
|
|
2253
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
2254
|
+
slot: new BN(12),
|
|
2255
|
+
confidence: new BN(1),
|
|
2256
|
+
hasSufficientNumberOfDataPoints: true,
|
|
2257
|
+
}
|
|
2258
|
+
);
|
|
2259
|
+
for (const n of nodesToFillAfter) {
|
|
2260
|
+
console.log(
|
|
2261
|
+
`cross found: taker orderId: ${n.node.order?.orderId.toString()}: BAA: ${n.node.order?.baseAssetAmount.toString()}, maker orderId: ${n.makerNode?.order?.orderId.toString()}: BAA: ${n.makerNode?.order?.baseAssetAmount.toString()}`
|
|
2262
|
+
);
|
|
2263
|
+
}
|
|
2264
|
+
expect(nodesToFillAfter.length).to.equal(2);
|
|
2265
|
+
|
|
2266
|
+
// first taker should fill with best maker
|
|
2267
|
+
expect(nodesToFillAfter[0].node.order?.orderId.toNumber()).to.equal(4);
|
|
2268
|
+
expect(nodesToFillAfter[0].makerNode?.order?.orderId.toNumber()).to.equal(
|
|
2269
|
+
3
|
|
2270
|
+
);
|
|
2271
|
+
|
|
2272
|
+
// second taker should fill with second best maker
|
|
2273
|
+
expect(nodesToFillAfter[1].node.order?.orderId.toNumber()).to.equal(5);
|
|
2274
|
+
expect(nodesToFillAfter[1].makerNode?.order?.orderId.toNumber()).to.equal(
|
|
2275
|
+
2
|
|
2276
|
+
);
|
|
2277
|
+
});
|
|
2278
|
+
|
|
2279
|
+
it('Test one market order fills two limit orders', () => {
|
|
2280
|
+
const vAsk = new BN(15);
|
|
2281
|
+
const vBid = new BN(10);
|
|
2282
|
+
const dlob = new DLOB(mockPerpMarkets, mockSpotMarkets, false);
|
|
2283
|
+
const marketIndex = new BN(0);
|
|
2284
|
+
|
|
2285
|
+
// insert some limit sells below vAMM ask, above bid
|
|
2286
|
+
insertOrderToDLOB(
|
|
2287
|
+
dlob,
|
|
2288
|
+
Keypair.generate().publicKey,
|
|
2289
|
+
OrderType.LIMIT,
|
|
2290
|
+
MarketType.SPOT,
|
|
2291
|
+
new BN(1), // orderId
|
|
2292
|
+
marketIndex,
|
|
2293
|
+
new BN(14), // price
|
|
2294
|
+
BASE_PRECISION, // quantity
|
|
2295
|
+
PositionDirection.SHORT,
|
|
2296
|
+
vBid,
|
|
2297
|
+
vAsk
|
|
2298
|
+
);
|
|
2299
|
+
insertOrderToDLOB(
|
|
2300
|
+
dlob,
|
|
2301
|
+
Keypair.generate().publicKey,
|
|
2302
|
+
OrderType.LIMIT,
|
|
2303
|
+
MarketType.SPOT,
|
|
2304
|
+
new BN(2), // orderId
|
|
2305
|
+
marketIndex,
|
|
2306
|
+
new BN(12), // price
|
|
2307
|
+
BASE_PRECISION, // quantity
|
|
2308
|
+
PositionDirection.SHORT,
|
|
2309
|
+
vBid,
|
|
2310
|
+
vAsk
|
|
2311
|
+
);
|
|
2312
|
+
insertOrderToDLOB(
|
|
2313
|
+
dlob,
|
|
2314
|
+
Keypair.generate().publicKey,
|
|
2315
|
+
OrderType.LIMIT,
|
|
2316
|
+
MarketType.SPOT,
|
|
2317
|
+
new BN(3), // orderId
|
|
2318
|
+
marketIndex,
|
|
2319
|
+
new BN(11), // price
|
|
2320
|
+
BASE_PRECISION, // quantity
|
|
2321
|
+
PositionDirection.SHORT,
|
|
2322
|
+
vBid,
|
|
2323
|
+
vAsk
|
|
2324
|
+
);
|
|
2325
|
+
|
|
2326
|
+
// should have no crossing orders
|
|
2327
|
+
const nodesToFillBefore = dlob.findCrossingNodesToFill(
|
|
2328
|
+
marketIndex,
|
|
2329
|
+
vBid,
|
|
2330
|
+
vAsk,
|
|
2331
|
+
12, // auction over
|
|
2332
|
+
MarketType.SPOT,
|
|
2333
|
+
{
|
|
2334
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
2335
|
+
slot: new BN(12),
|
|
2336
|
+
confidence: new BN(1),
|
|
2337
|
+
hasSufficientNumberOfDataPoints: true,
|
|
2338
|
+
}
|
|
2339
|
+
);
|
|
2340
|
+
expect(nodesToFillBefore.length).to.equal(0);
|
|
2341
|
+
|
|
2342
|
+
// place one market buy order eating 2 of the limit orders
|
|
2343
|
+
insertOrderToDLOB(
|
|
2344
|
+
dlob,
|
|
2345
|
+
Keypair.generate().publicKey,
|
|
2346
|
+
OrderType.MARKET,
|
|
2347
|
+
MarketType.SPOT,
|
|
2348
|
+
new BN(4), // orderId
|
|
2349
|
+
marketIndex,
|
|
2350
|
+
new BN(12), // price
|
|
2351
|
+
new BN(2).mul(BASE_PRECISION), // quantity
|
|
2352
|
+
PositionDirection.LONG,
|
|
2353
|
+
vBid,
|
|
2354
|
+
vAsk
|
|
2355
|
+
);
|
|
2356
|
+
|
|
2357
|
+
const nodesToFillAfter = dlob.findCrossingNodesToFill(
|
|
2358
|
+
marketIndex,
|
|
2359
|
+
vBid,
|
|
2360
|
+
vAsk,
|
|
2361
|
+
12, // auction over
|
|
2362
|
+
MarketType.SPOT,
|
|
2363
|
+
{
|
|
2364
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
2365
|
+
slot: new BN(12),
|
|
2366
|
+
confidence: new BN(1),
|
|
2367
|
+
hasSufficientNumberOfDataPoints: true,
|
|
2368
|
+
}
|
|
2369
|
+
);
|
|
2370
|
+
for (const n of nodesToFillAfter) {
|
|
2371
|
+
console.log(
|
|
2372
|
+
`cross found: taker orderId: ${n.node.order?.orderId.toString()}: BAA: ${n.node.order?.baseAssetAmountFilled.toString()}/${n.node.order?.baseAssetAmount.toString()}, maker orderId: ${n.makerNode?.order?.orderId.toString()}: BAA: ${n.makerNode?.order?.baseAssetAmountFilled.toString()}/${n.makerNode?.order?.baseAssetAmount.toString()}`
|
|
2373
|
+
);
|
|
2374
|
+
}
|
|
2375
|
+
expect(nodesToFillAfter.length).to.equal(2);
|
|
2376
|
+
|
|
2377
|
+
// taker should fill completely with best maker
|
|
2378
|
+
expect(nodesToFillAfter[0].node.order?.orderId.toNumber()).to.equal(4);
|
|
2379
|
+
expect(nodesToFillAfter[0].makerNode?.order?.orderId.toNumber()).to.equal(
|
|
2380
|
+
3
|
|
2381
|
+
);
|
|
2382
|
+
|
|
2383
|
+
// taker should fill completely with second best maker
|
|
2384
|
+
expect(nodesToFillAfter[1].node.order?.orderId.toNumber()).to.equal(4);
|
|
2385
|
+
expect(nodesToFillAfter[1].makerNode?.order?.orderId.toNumber()).to.equal(
|
|
2386
|
+
2
|
|
2387
|
+
);
|
|
2388
|
+
});
|
|
2389
|
+
|
|
2390
|
+
it('Test two market orders to fill one limit order', () => {
|
|
2391
|
+
const vAsk = new BN(15);
|
|
2392
|
+
const vBid = new BN(8);
|
|
2393
|
+
const dlob = new DLOB(mockPerpMarkets, mockSpotMarkets, false);
|
|
2394
|
+
const marketIndex = new BN(0);
|
|
2395
|
+
|
|
2396
|
+
const slot = 12;
|
|
2397
|
+
const oracle = {
|
|
2398
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
2399
|
+
slot: new BN(slot),
|
|
2400
|
+
confidence: new BN(1),
|
|
2401
|
+
hasSufficientNumberOfDataPoints: true,
|
|
2402
|
+
};
|
|
2403
|
+
|
|
2404
|
+
// insert some limit sells below vAMM ask, above bid
|
|
2405
|
+
insertOrderToDLOB(
|
|
2406
|
+
dlob,
|
|
2407
|
+
Keypair.generate().publicKey,
|
|
2408
|
+
OrderType.LIMIT,
|
|
2409
|
+
MarketType.SPOT,
|
|
2410
|
+
new BN(1), // orderId
|
|
2411
|
+
marketIndex,
|
|
2412
|
+
new BN(14), // price
|
|
2413
|
+
BASE_PRECISION, // quantity
|
|
2414
|
+
PositionDirection.SHORT,
|
|
2415
|
+
vBid,
|
|
2416
|
+
vAsk
|
|
2417
|
+
);
|
|
2418
|
+
insertOrderToDLOB(
|
|
2419
|
+
dlob,
|
|
2420
|
+
Keypair.generate().publicKey,
|
|
2421
|
+
OrderType.LIMIT,
|
|
2422
|
+
MarketType.SPOT,
|
|
2423
|
+
new BN(2), // orderId
|
|
2424
|
+
marketIndex,
|
|
2425
|
+
new BN(13), // price
|
|
2426
|
+
BASE_PRECISION, // quantity
|
|
2427
|
+
PositionDirection.SHORT,
|
|
2428
|
+
vBid,
|
|
2429
|
+
vAsk
|
|
2430
|
+
);
|
|
2431
|
+
insertOrderToDLOB(
|
|
2432
|
+
dlob,
|
|
2433
|
+
Keypair.generate().publicKey,
|
|
2434
|
+
OrderType.LIMIT,
|
|
2435
|
+
MarketType.SPOT,
|
|
2436
|
+
new BN(3), // orderId
|
|
2437
|
+
marketIndex,
|
|
2438
|
+
new BN(8), // price <-- best price
|
|
2439
|
+
new BN(3).mul(BASE_PRECISION), // quantity
|
|
2440
|
+
PositionDirection.SHORT,
|
|
2441
|
+
vBid,
|
|
2442
|
+
vAsk
|
|
2443
|
+
);
|
|
2444
|
+
|
|
2445
|
+
// should have no crossing orders
|
|
2446
|
+
const nodesToFillBefore = dlob.findCrossingNodesToFill(
|
|
2447
|
+
marketIndex,
|
|
2448
|
+
vBid,
|
|
2449
|
+
vAsk,
|
|
2450
|
+
12, // auction over
|
|
2451
|
+
MarketType.SPOT,
|
|
2452
|
+
oracle
|
|
2453
|
+
);
|
|
2454
|
+
expect(nodesToFillBefore.length).to.equal(0);
|
|
2455
|
+
|
|
2456
|
+
// place two market buy orders to eat the best ask
|
|
2457
|
+
insertOrderToDLOB(
|
|
2458
|
+
dlob,
|
|
2459
|
+
Keypair.generate().publicKey,
|
|
2460
|
+
OrderType.MARKET,
|
|
2461
|
+
MarketType.SPOT,
|
|
2462
|
+
new BN(4), // orderId
|
|
2463
|
+
marketIndex,
|
|
2464
|
+
new BN(0), // price
|
|
2465
|
+
new BN(1).mul(BASE_PRECISION), // quantity
|
|
2466
|
+
PositionDirection.LONG,
|
|
2467
|
+
vBid,
|
|
2468
|
+
vAsk
|
|
2469
|
+
);
|
|
2470
|
+
insertOrderToDLOB(
|
|
2471
|
+
dlob,
|
|
2472
|
+
Keypair.generate().publicKey,
|
|
2473
|
+
OrderType.MARKET,
|
|
2474
|
+
MarketType.SPOT,
|
|
2475
|
+
new BN(5), // orderId
|
|
2476
|
+
marketIndex,
|
|
2477
|
+
new BN(0), // price
|
|
2478
|
+
new BN(2).mul(BASE_PRECISION), // quantity
|
|
2479
|
+
PositionDirection.LONG,
|
|
2480
|
+
vBid,
|
|
2481
|
+
vAsk
|
|
2482
|
+
);
|
|
2483
|
+
|
|
2484
|
+
const nodesToFillAfter = dlob.findCrossingNodesToFill(
|
|
2485
|
+
marketIndex,
|
|
2486
|
+
vBid,
|
|
2487
|
+
vAsk,
|
|
2488
|
+
slot, // auction over
|
|
2489
|
+
MarketType.SPOT,
|
|
2490
|
+
oracle
|
|
2491
|
+
);
|
|
2492
|
+
const mktNodes = dlob.findMarketNodesToFill(
|
|
2493
|
+
marketIndex,
|
|
2494
|
+
slot,
|
|
2495
|
+
MarketType.SPOT
|
|
2496
|
+
);
|
|
2497
|
+
console.log(`market nodes: ${mktNodes.length}`);
|
|
2498
|
+
|
|
2499
|
+
const askNodes = dlob.getAsks(
|
|
2500
|
+
marketIndex,
|
|
2501
|
+
vAsk,
|
|
2502
|
+
slot,
|
|
2503
|
+
MarketType.SPOT,
|
|
2504
|
+
oracle
|
|
2505
|
+
);
|
|
2506
|
+
let aa = 0;
|
|
2507
|
+
for (const b of askNodes) {
|
|
2508
|
+
console.log(
|
|
2509
|
+
` . ask: ${b.order?.orderId.toString()}: p1: ${b.order?.price.toString()} p2: ${b.getPrice(
|
|
2510
|
+
oracle,
|
|
2511
|
+
slot
|
|
2512
|
+
)}, ${JSON.stringify(
|
|
2513
|
+
b.order?.orderType
|
|
2514
|
+
)} BAA: ${b.order?.baseAssetAmountFilled.toString()}/${b.order?.baseAssetAmount.toString()}`
|
|
2515
|
+
);
|
|
2516
|
+
aa++;
|
|
2517
|
+
}
|
|
2518
|
+
expect(aa).to.equal(3);
|
|
2519
|
+
|
|
2520
|
+
const bidNodes = dlob.getBids(
|
|
2521
|
+
marketIndex,
|
|
2522
|
+
vBid,
|
|
2523
|
+
slot,
|
|
2524
|
+
MarketType.SPOT,
|
|
2525
|
+
oracle
|
|
2526
|
+
);
|
|
2527
|
+
let bb = 0;
|
|
2528
|
+
for (const b of bidNodes) {
|
|
2529
|
+
console.log(
|
|
2530
|
+
` . bid: ${b.order?.orderId.toString()}: p1: ${b.order?.price.toString()} p2: ${b.getPrice(
|
|
2531
|
+
oracle,
|
|
2532
|
+
slot
|
|
2533
|
+
)}, ${JSON.stringify(
|
|
2534
|
+
b.order?.orderType
|
|
2535
|
+
)} BAA: ${b.order?.baseAssetAmountFilled.toString()}/${b.order?.baseAssetAmount.toString()}`
|
|
2536
|
+
);
|
|
2537
|
+
bb++;
|
|
2538
|
+
}
|
|
2539
|
+
expect(bb).to.equal(2);
|
|
2540
|
+
|
|
2541
|
+
console.log(`bids nodes: ${bb}`);
|
|
2542
|
+
for (const n of nodesToFillAfter) {
|
|
2543
|
+
console.log(
|
|
2544
|
+
`cross found: taker orderId: ${n.node.order?.orderId.toString()}: BAA: ${n.node.order?.baseAssetAmountFilled.toString()}/${n.node.order?.baseAssetAmount.toString()}, maker orderId: ${n.makerNode?.order?.orderId.toString()}: BAA: ${n.makerNode?.order?.baseAssetAmountFilled.toString()}/${n.makerNode?.order?.baseAssetAmount.toString()}`
|
|
2545
|
+
);
|
|
2546
|
+
}
|
|
2547
|
+
expect(nodesToFillAfter.length).to.equal(2);
|
|
2548
|
+
|
|
2549
|
+
// taker should fill completely with best maker
|
|
2550
|
+
expect(nodesToFillAfter[0].node.order?.orderId.toNumber()).to.equal(4);
|
|
2551
|
+
expect(nodesToFillAfter[0].makerNode?.order?.orderId.toNumber()).to.equal(
|
|
2552
|
+
3
|
|
2553
|
+
);
|
|
2554
|
+
|
|
2555
|
+
// taker should fill completely with second best maker
|
|
2556
|
+
expect(nodesToFillAfter[1].node.order?.orderId.toNumber()).to.equal(5);
|
|
2557
|
+
expect(nodesToFillAfter[1].makerNode?.order?.orderId.toNumber()).to.equal(
|
|
2558
|
+
3
|
|
2559
|
+
);
|
|
2560
|
+
});
|
|
2561
|
+
|
|
2562
|
+
it('Test trigger orders', () => {
|
|
2563
|
+
const vAsk = new BN(15);
|
|
2564
|
+
const vBid = new BN(8);
|
|
2565
|
+
const dlob = new DLOB(mockPerpMarkets, mockSpotMarkets, false);
|
|
2566
|
+
const marketIndex = new BN(0);
|
|
2567
|
+
|
|
2568
|
+
const slot = 20;
|
|
2569
|
+
const oracle = {
|
|
2570
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
2571
|
+
slot: new BN(slot),
|
|
2572
|
+
confidence: new BN(1),
|
|
2573
|
+
hasSufficientNumberOfDataPoints: true,
|
|
2574
|
+
};
|
|
2575
|
+
|
|
2576
|
+
const orderIdsToTrigger = [1, 2, 3, 4, 5, 6, 7, 8];
|
|
2577
|
+
// const orderIdsToNotTrigger = [9, 10, 11, 12];
|
|
2578
|
+
|
|
2579
|
+
// should trigger limit buy with above condition
|
|
2580
|
+
insertTriggerOrderToDLOB(
|
|
2581
|
+
dlob,
|
|
2582
|
+
Keypair.generate().publicKey,
|
|
2583
|
+
OrderType.TRIGGER_LIMIT,
|
|
2584
|
+
MarketType.SPOT,
|
|
2585
|
+
new BN(1), //orderId
|
|
2586
|
+
marketIndex, // marketIndex
|
|
2587
|
+
vBid, // price
|
|
2588
|
+
BASE_PRECISION, // baseAssetAmount: BN,
|
|
2589
|
+
PositionDirection.LONG,
|
|
2590
|
+
oracle.price.sub(new BN(1)), // triggerPrice: BN,
|
|
2591
|
+
OrderTriggerCondition.ABOVE, // triggerCondition: OrderTriggerCondition,
|
|
2592
|
+
vBid,
|
|
2593
|
+
vAsk
|
|
2594
|
+
);
|
|
2595
|
+
// should trigger limit sell with above condition
|
|
2596
|
+
insertTriggerOrderToDLOB(
|
|
2597
|
+
dlob,
|
|
2598
|
+
Keypair.generate().publicKey,
|
|
2599
|
+
OrderType.TRIGGER_LIMIT,
|
|
2600
|
+
MarketType.SPOT,
|
|
2601
|
+
new BN(2), //orderId
|
|
2602
|
+
marketIndex, // marketIndex
|
|
2603
|
+
vBid, // price
|
|
2604
|
+
BASE_PRECISION, // baseAssetAmount: BN,
|
|
2605
|
+
PositionDirection.SHORT,
|
|
2606
|
+
oracle.price.sub(new BN(1)), // triggerPrice: BN,
|
|
2607
|
+
OrderTriggerCondition.ABOVE, // triggerCondition: OrderTriggerCondition,
|
|
2608
|
+
vBid,
|
|
2609
|
+
vAsk
|
|
2610
|
+
);
|
|
2611
|
+
// should trigger market buy with above condition
|
|
2612
|
+
insertTriggerOrderToDLOB(
|
|
2613
|
+
dlob,
|
|
2614
|
+
Keypair.generate().publicKey,
|
|
2615
|
+
OrderType.TRIGGER_MARKET,
|
|
2616
|
+
MarketType.SPOT,
|
|
2617
|
+
new BN(3), //orderId
|
|
2618
|
+
marketIndex, // marketIndex
|
|
2619
|
+
vAsk, // price
|
|
2620
|
+
BASE_PRECISION, // baseAssetAmount: BN,
|
|
2621
|
+
PositionDirection.LONG,
|
|
2622
|
+
oracle.price.sub(new BN(1)), // triggerPrice: BN,
|
|
2623
|
+
OrderTriggerCondition.ABOVE, // triggerCondition: OrderTriggerCondition,
|
|
2624
|
+
vBid,
|
|
2625
|
+
vAsk
|
|
2626
|
+
);
|
|
2627
|
+
// should trigger market sell with above condition
|
|
2628
|
+
insertTriggerOrderToDLOB(
|
|
2629
|
+
dlob,
|
|
2630
|
+
Keypair.generate().publicKey,
|
|
2631
|
+
OrderType.TRIGGER_MARKET,
|
|
2632
|
+
MarketType.SPOT,
|
|
2633
|
+
new BN(4), //orderId
|
|
2634
|
+
marketIndex, // marketIndex
|
|
2635
|
+
vBid, // price
|
|
2636
|
+
BASE_PRECISION, // baseAssetAmount: BN,
|
|
2637
|
+
PositionDirection.SHORT,
|
|
2638
|
+
oracle.price.sub(new BN(1)), // triggerPrice: BN,
|
|
2639
|
+
OrderTriggerCondition.ABOVE, // triggerCondition: OrderTriggerCondition,
|
|
2640
|
+
vBid,
|
|
2641
|
+
vAsk
|
|
2642
|
+
);
|
|
2643
|
+
// should trigger limit buy with below condition
|
|
2644
|
+
insertTriggerOrderToDLOB(
|
|
2645
|
+
dlob,
|
|
2646
|
+
Keypair.generate().publicKey,
|
|
2647
|
+
OrderType.TRIGGER_LIMIT,
|
|
2648
|
+
MarketType.SPOT,
|
|
2649
|
+
new BN(5), //orderId
|
|
2650
|
+
marketIndex, // marketIndex
|
|
2651
|
+
vBid, // price
|
|
2652
|
+
BASE_PRECISION, // baseAssetAmount: BN,
|
|
2653
|
+
PositionDirection.LONG,
|
|
2654
|
+
oracle.price.add(new BN(1)), // triggerPrice: BN,
|
|
2655
|
+
OrderTriggerCondition.BELOW, // triggerCondition: OrderTriggerCondition,
|
|
2656
|
+
vBid,
|
|
2657
|
+
vAsk
|
|
2658
|
+
);
|
|
2659
|
+
// should trigger limit sell with below condition
|
|
2660
|
+
insertTriggerOrderToDLOB(
|
|
2661
|
+
dlob,
|
|
2662
|
+
Keypair.generate().publicKey,
|
|
2663
|
+
OrderType.TRIGGER_LIMIT,
|
|
2664
|
+
MarketType.SPOT,
|
|
2665
|
+
new BN(6), //orderId
|
|
2666
|
+
marketIndex, // marketIndex
|
|
2667
|
+
vBid, // price
|
|
2668
|
+
BASE_PRECISION, // baseAssetAmount: BN,
|
|
2669
|
+
PositionDirection.SHORT,
|
|
2670
|
+
oracle.price.add(new BN(1)), // triggerPrice: BN,
|
|
2671
|
+
OrderTriggerCondition.BELOW, // triggerCondition: OrderTriggerCondition,
|
|
2672
|
+
vBid,
|
|
2673
|
+
vAsk
|
|
2674
|
+
);
|
|
2675
|
+
// should trigger market buy with below condition
|
|
2676
|
+
insertTriggerOrderToDLOB(
|
|
2677
|
+
dlob,
|
|
2678
|
+
Keypair.generate().publicKey,
|
|
2679
|
+
OrderType.TRIGGER_MARKET,
|
|
2680
|
+
MarketType.SPOT,
|
|
2681
|
+
new BN(7), //orderId
|
|
2682
|
+
marketIndex, // marketIndex
|
|
2683
|
+
vBid, // price
|
|
2684
|
+
BASE_PRECISION, // baseAssetAmount: BN,
|
|
2685
|
+
PositionDirection.LONG,
|
|
2686
|
+
oracle.price.add(new BN(1)), // triggerPrice: BN,
|
|
2687
|
+
OrderTriggerCondition.BELOW, // triggerCondition: OrderTriggerCondition,
|
|
2688
|
+
vBid,
|
|
2689
|
+
vAsk
|
|
2690
|
+
);
|
|
2691
|
+
// should trigger market sell with below condition
|
|
2692
|
+
insertTriggerOrderToDLOB(
|
|
2693
|
+
dlob,
|
|
2694
|
+
Keypair.generate().publicKey,
|
|
2695
|
+
OrderType.TRIGGER_MARKET,
|
|
2696
|
+
MarketType.SPOT,
|
|
2697
|
+
new BN(8), //orderId
|
|
2698
|
+
marketIndex, // marketIndex
|
|
2699
|
+
vBid, // price
|
|
2700
|
+
BASE_PRECISION, // baseAssetAmount: BN,
|
|
2701
|
+
PositionDirection.LONG,
|
|
2702
|
+
oracle.price.add(new BN(1)), // triggerPrice: BN,
|
|
2703
|
+
OrderTriggerCondition.BELOW, // triggerCondition: OrderTriggerCondition,
|
|
2704
|
+
vBid,
|
|
2705
|
+
vAsk
|
|
2706
|
+
);
|
|
2707
|
+
|
|
2708
|
+
// should NOT trigger market sell with above condition
|
|
2709
|
+
insertTriggerOrderToDLOB(
|
|
2710
|
+
dlob,
|
|
2711
|
+
Keypair.generate().publicKey,
|
|
2712
|
+
OrderType.TRIGGER_MARKET,
|
|
2713
|
+
MarketType.SPOT,
|
|
2714
|
+
new BN(9), //orderId
|
|
2715
|
+
marketIndex, // marketIndex
|
|
2716
|
+
vBid, // price
|
|
2717
|
+
BASE_PRECISION, // baseAssetAmount: BN,
|
|
2718
|
+
PositionDirection.SHORT,
|
|
2719
|
+
oracle.price.add(new BN(1)), // triggerPrice: BN,
|
|
2720
|
+
OrderTriggerCondition.ABOVE, // triggerCondition: OrderTriggerCondition,
|
|
2721
|
+
vBid,
|
|
2722
|
+
vAsk
|
|
2723
|
+
);
|
|
2724
|
+
// should NOT trigger market sell with below condition
|
|
2725
|
+
insertTriggerOrderToDLOB(
|
|
2726
|
+
dlob,
|
|
2727
|
+
Keypair.generate().publicKey,
|
|
2728
|
+
OrderType.TRIGGER_MARKET,
|
|
2729
|
+
MarketType.SPOT,
|
|
2730
|
+
new BN(10), //orderId
|
|
2731
|
+
marketIndex, // marketIndex
|
|
2732
|
+
vBid, // price
|
|
2733
|
+
BASE_PRECISION, // baseAssetAmount: BN,
|
|
2734
|
+
PositionDirection.SHORT,
|
|
2735
|
+
oracle.price.sub(new BN(1)), // triggerPrice: BN,
|
|
2736
|
+
OrderTriggerCondition.BELOW, // triggerCondition: OrderTriggerCondition,
|
|
2737
|
+
vBid,
|
|
2738
|
+
vAsk
|
|
2739
|
+
);
|
|
2740
|
+
// should NOT trigger market buy with above condition
|
|
2741
|
+
insertTriggerOrderToDLOB(
|
|
2742
|
+
dlob,
|
|
2743
|
+
Keypair.generate().publicKey,
|
|
2744
|
+
OrderType.TRIGGER_MARKET,
|
|
2745
|
+
MarketType.SPOT,
|
|
2746
|
+
new BN(11), //orderId
|
|
2747
|
+
marketIndex, // marketIndex
|
|
2748
|
+
vBid, // price
|
|
2749
|
+
BASE_PRECISION, // baseAssetAmount: BN,
|
|
2750
|
+
PositionDirection.LONG,
|
|
2751
|
+
oracle.price.add(new BN(1)), // triggerPrice: BN,
|
|
2752
|
+
OrderTriggerCondition.ABOVE, // triggerCondition: OrderTriggerCondition,
|
|
2753
|
+
vBid,
|
|
2754
|
+
vAsk
|
|
2755
|
+
);
|
|
2756
|
+
// should NOT trigger market buy with below condition
|
|
2757
|
+
insertTriggerOrderToDLOB(
|
|
2758
|
+
dlob,
|
|
2759
|
+
Keypair.generate().publicKey,
|
|
2760
|
+
OrderType.TRIGGER_MARKET,
|
|
2761
|
+
MarketType.SPOT,
|
|
2762
|
+
new BN(12), //orderId
|
|
2763
|
+
marketIndex, // marketIndex
|
|
2764
|
+
vBid, // price
|
|
2765
|
+
BASE_PRECISION, // baseAssetAmount: BN,
|
|
2766
|
+
PositionDirection.LONG,
|
|
2767
|
+
oracle.price.sub(new BN(1)), // triggerPrice: BN,
|
|
2768
|
+
OrderTriggerCondition.BELOW, // triggerCondition: OrderTriggerCondition,
|
|
2769
|
+
vBid,
|
|
2770
|
+
vAsk
|
|
2771
|
+
);
|
|
2772
|
+
|
|
2773
|
+
const nodesToTrigger = dlob.findNodesToTrigger(
|
|
2774
|
+
marketIndex,
|
|
2775
|
+
slot,
|
|
2776
|
+
oracle.price,
|
|
2777
|
+
MarketType.SPOT
|
|
2778
|
+
);
|
|
2779
|
+
console.log(`nodesToTriggeR: ${nodesToTrigger.length}`);
|
|
2780
|
+
for (const [idx, n] of nodesToTrigger.entries()) {
|
|
2781
|
+
expect(n.node.order?.orderId.toNumber()).to.equal(orderIdsToTrigger[idx]);
|
|
2782
|
+
console.log(`nodeToTrigger: ${n.node.order?.orderId.toString()}`);
|
|
2783
|
+
}
|
|
2784
|
+
});
|
|
2785
|
+
|
|
2786
|
+
it('Test will return expired market orders to fill', () => {
|
|
2787
|
+
const vAsk = new BN(15);
|
|
2788
|
+
const vBid = new BN(8);
|
|
2789
|
+
const dlob = new DLOB(mockPerpMarkets, mockSpotMarkets, false);
|
|
2790
|
+
const marketIndex = new BN(0);
|
|
2791
|
+
|
|
2792
|
+
const slot = 20;
|
|
2793
|
+
const timeInForce = 30;
|
|
2794
|
+
|
|
2795
|
+
// non crossing bid
|
|
2796
|
+
insertOrderToDLOB(
|
|
2797
|
+
dlob,
|
|
2798
|
+
Keypair.generate().publicKey,
|
|
2799
|
+
OrderType.MARKET,
|
|
2800
|
+
MarketType.SPOT,
|
|
2801
|
+
new BN(255), // orderId
|
|
2802
|
+
marketIndex,
|
|
2803
|
+
new BN(2), // price, very low, don't cross vamm
|
|
2804
|
+
BASE_PRECISION, // quantity
|
|
2805
|
+
PositionDirection.LONG,
|
|
2806
|
+
vBid,
|
|
2807
|
+
vAsk,
|
|
2808
|
+
new BN(slot),
|
|
2809
|
+
timeInForce
|
|
2810
|
+
);
|
|
2811
|
+
insertOrderToDLOB(
|
|
2812
|
+
dlob,
|
|
2813
|
+
Keypair.generate().publicKey,
|
|
2814
|
+
OrderType.MARKET,
|
|
2815
|
+
MarketType.SPOT,
|
|
2816
|
+
new BN(2), // orderId
|
|
2817
|
+
marketIndex,
|
|
2818
|
+
new BN(30), // price, very high, don't cross vamm
|
|
2819
|
+
BASE_PRECISION, // quantity
|
|
2820
|
+
PositionDirection.SHORT,
|
|
2821
|
+
vAsk,
|
|
2822
|
+
vBid,
|
|
2823
|
+
new BN(slot),
|
|
2824
|
+
timeInForce
|
|
2825
|
+
);
|
|
2826
|
+
|
|
2827
|
+
// order auction is not yet complete, and order is not expired.
|
|
2828
|
+
const slot0 = slot;
|
|
2829
|
+
const nodesToFillBefore = dlob.findNodesToFill(
|
|
2830
|
+
marketIndex,
|
|
2831
|
+
vBid,
|
|
2832
|
+
vAsk,
|
|
2833
|
+
slot0,
|
|
2834
|
+
MarketType.SPOT,
|
|
2835
|
+
{
|
|
2836
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
2837
|
+
slot: new BN(slot0),
|
|
2838
|
+
confidence: new BN(1),
|
|
2839
|
+
hasSufficientNumberOfDataPoints: true,
|
|
2840
|
+
}
|
|
2841
|
+
);
|
|
2842
|
+
expect(nodesToFillBefore.length).to.equal(0);
|
|
2843
|
+
|
|
2844
|
+
// should get order to fill after timeInForce
|
|
2845
|
+
const slot1 = slot0 + timeInForce; // overshoots expiry
|
|
2846
|
+
const nodesToFillAfter = dlob.findNodesToFill(
|
|
2847
|
+
marketIndex,
|
|
2848
|
+
vBid,
|
|
2849
|
+
vAsk,
|
|
2850
|
+
slot1,
|
|
2851
|
+
MarketType.SPOT,
|
|
2852
|
+
{
|
|
2853
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
2854
|
+
slot: new BN(slot1),
|
|
2855
|
+
confidence: new BN(1),
|
|
2856
|
+
hasSufficientNumberOfDataPoints: true,
|
|
2857
|
+
}
|
|
2858
|
+
);
|
|
2859
|
+
expect(nodesToFillAfter.length).to.equal(2);
|
|
2860
|
+
|
|
2861
|
+
// check that the nodes have no makers
|
|
2862
|
+
expect(nodesToFillAfter[0].makerNode).to.equal(undefined);
|
|
2863
|
+
expect(nodesToFillAfter[1].makerNode).to.equal(undefined);
|
|
2864
|
+
});
|
|
2865
|
+
});
|