@drift-labs/sdk 0.2.0-master.1 → 0.2.0-master.4
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/types.d.ts +1 -0
- package/lib/admin.d.ts +4 -1
- package/lib/admin.js +29 -2
- package/lib/clearingHouse.d.ts +11 -14
- package/lib/clearingHouse.js +73 -73
- package/lib/config.js +1 -1
- package/lib/constants/numericConstants.d.ts +1 -0
- package/lib/constants/numericConstants.js +2 -1
- package/lib/factory/bigNum.d.ts +8 -2
- package/lib/factory/bigNum.js +14 -6
- package/lib/idl/clearing_house.json +189 -52
- package/lib/index.d.ts +2 -1
- package/lib/index.js +6 -1
- package/lib/math/amm.d.ts +6 -1
- package/lib/math/amm.js +124 -41
- package/lib/math/auction.js +4 -1
- package/lib/math/orders.d.ts +2 -2
- package/lib/math/orders.js +18 -11
- package/lib/math/repeg.js +1 -1
- package/lib/math/trade.d.ts +1 -1
- package/lib/math/trade.js +7 -10
- package/lib/orderParams.d.ts +14 -5
- package/lib/orderParams.js +8 -96
- package/lib/orders.d.ts +1 -2
- package/lib/orders.js +6 -85
- package/lib/types.d.ts +62 -1
- package/lib/types.js +37 -1
- package/package.json +3 -3
- package/src/admin.ts +48 -4
- package/src/clearingHouse.ts +102 -151
- package/src/config.ts +1 -1
- package/src/constants/numericConstants.ts +1 -0
- package/src/factory/bigNum.ts +26 -9
- package/src/idl/clearing_house.json +189 -52
- package/src/index.ts +2 -1
- package/src/math/amm.ts +207 -52
- package/src/math/auction.ts +5 -1
- package/src/math/orders.ts +17 -13
- package/src/math/repeg.ts +2 -1
- package/src/math/trade.ts +23 -25
- package/src/orderParams.ts +20 -141
- package/src/orders.ts +7 -131
- package/src/types.ts +58 -3
package/src/math/amm.ts
CHANGED
|
@@ -6,8 +6,10 @@ import {
|
|
|
6
6
|
ZERO,
|
|
7
7
|
BID_ASK_SPREAD_PRECISION,
|
|
8
8
|
ONE,
|
|
9
|
-
// QUOTE_PRECISION,
|
|
10
9
|
AMM_TO_QUOTE_PRECISION_RATIO,
|
|
10
|
+
QUOTE_PRECISION,
|
|
11
|
+
MARGIN_PRECISION,
|
|
12
|
+
PRICE_DIV_PEG,
|
|
11
13
|
} from '../constants/numericConstants';
|
|
12
14
|
import {
|
|
13
15
|
AMM,
|
|
@@ -25,6 +27,71 @@ import {
|
|
|
25
27
|
calculateAdjustKCost,
|
|
26
28
|
calculateBudgetedPeg,
|
|
27
29
|
} from './repeg';
|
|
30
|
+
|
|
31
|
+
export function calculatePegFromTargetPrice(
|
|
32
|
+
targetPrice: BN,
|
|
33
|
+
baseAssetReserve: BN,
|
|
34
|
+
quoteAssetReserve: BN
|
|
35
|
+
): BN {
|
|
36
|
+
return targetPrice
|
|
37
|
+
.mul(baseAssetReserve)
|
|
38
|
+
.div(quoteAssetReserve)
|
|
39
|
+
.add(PRICE_DIV_PEG.div(new BN(2)))
|
|
40
|
+
.div(PRICE_DIV_PEG);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function calculateOptimalPegAndBudget(
|
|
44
|
+
amm: AMM,
|
|
45
|
+
oraclePriceData: OraclePriceData
|
|
46
|
+
): [BN, BN, BN, boolean] {
|
|
47
|
+
const markPriceBefore = calculatePrice(
|
|
48
|
+
amm.baseAssetReserve,
|
|
49
|
+
amm.quoteAssetReserve,
|
|
50
|
+
amm.pegMultiplier
|
|
51
|
+
);
|
|
52
|
+
const targetPrice = oraclePriceData.price;
|
|
53
|
+
const newPeg = calculatePegFromTargetPrice(
|
|
54
|
+
targetPrice,
|
|
55
|
+
amm.baseAssetReserve,
|
|
56
|
+
amm.quoteAssetReserve
|
|
57
|
+
);
|
|
58
|
+
const prePegCost = calculateRepegCost(amm, newPeg);
|
|
59
|
+
|
|
60
|
+
const totalFeeLB = amm.totalExchangeFee.div(new BN(2));
|
|
61
|
+
const budget = BN.max(ZERO, amm.totalFeeMinusDistributions.sub(totalFeeLB));
|
|
62
|
+
if (budget.lt(prePegCost)) {
|
|
63
|
+
const maxPriceSpread = new BN(amm.maxSpread)
|
|
64
|
+
.mul(targetPrice)
|
|
65
|
+
.div(BID_ASK_SPREAD_PRECISION);
|
|
66
|
+
|
|
67
|
+
let newTargetPrice: BN;
|
|
68
|
+
let newOptimalPeg: BN;
|
|
69
|
+
let newBudget: BN;
|
|
70
|
+
const targetPriceGap = markPriceBefore.sub(targetPrice);
|
|
71
|
+
|
|
72
|
+
if (targetPriceGap.abs().gt(maxPriceSpread)) {
|
|
73
|
+
const markAdj = targetPriceGap.abs().sub(maxPriceSpread);
|
|
74
|
+
|
|
75
|
+
if (targetPriceGap.lt(new BN(0))) {
|
|
76
|
+
newTargetPrice = markPriceBefore.add(markAdj);
|
|
77
|
+
} else {
|
|
78
|
+
newTargetPrice = markPriceBefore.sub(markAdj);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
newOptimalPeg = calculatePegFromTargetPrice(
|
|
82
|
+
newTargetPrice,
|
|
83
|
+
amm.baseAssetReserve,
|
|
84
|
+
amm.quoteAssetReserve
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
newBudget = calculateRepegCost(amm, newOptimalPeg);
|
|
88
|
+
return [newTargetPrice, newOptimalPeg, newBudget, false];
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return [targetPrice, newPeg, budget, true];
|
|
93
|
+
}
|
|
94
|
+
|
|
28
95
|
export function calculateNewAmm(
|
|
29
96
|
amm: AMM,
|
|
30
97
|
oraclePriceData: OraclePriceData
|
|
@@ -32,18 +99,12 @@ export function calculateNewAmm(
|
|
|
32
99
|
let pKNumer = new BN(1);
|
|
33
100
|
let pKDenom = new BN(1);
|
|
34
101
|
|
|
35
|
-
const targetPrice =
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
.add(MARK_PRICE_PRECISION.div(PEG_PRECISION).div(new BN(2)))
|
|
40
|
-
.div(MARK_PRICE_PRECISION.div(PEG_PRECISION));
|
|
41
|
-
let prePegCost = calculateRepegCost(amm, newPeg);
|
|
42
|
-
|
|
43
|
-
const totalFeeLB = amm.totalExchangeFee.div(new BN(2));
|
|
44
|
-
const budget = BN.max(ZERO, amm.totalFeeMinusDistributions.sub(totalFeeLB));
|
|
102
|
+
const [targetPrice, _newPeg, budget, checkLowerBound] =
|
|
103
|
+
calculateOptimalPegAndBudget(amm, oraclePriceData);
|
|
104
|
+
let prePegCost = calculateRepegCost(amm, _newPeg);
|
|
105
|
+
let newPeg = _newPeg;
|
|
45
106
|
|
|
46
|
-
if (prePegCost.gt(budget)) {
|
|
107
|
+
if (prePegCost.gt(budget) && checkLowerBound) {
|
|
47
108
|
[pKNumer, pKDenom] = [new BN(999), new BN(1000)];
|
|
48
109
|
const deficitMadeup = calculateAdjustKCost(amm, pKNumer, pKDenom);
|
|
49
110
|
assert(deficitMadeup.lte(new BN(0)));
|
|
@@ -136,9 +197,16 @@ export function calculateUpdatedAMMSpreadReserves(
|
|
|
136
197
|
|
|
137
198
|
export function calculateBidAskPrice(
|
|
138
199
|
amm: AMM,
|
|
139
|
-
oraclePriceData: OraclePriceData
|
|
200
|
+
oraclePriceData: OraclePriceData,
|
|
201
|
+
withUpdate = true
|
|
140
202
|
): [BN, BN] {
|
|
141
|
-
|
|
203
|
+
let newAmm: AMM;
|
|
204
|
+
if (withUpdate) {
|
|
205
|
+
newAmm = calculateUpdatedAMM(amm, oraclePriceData);
|
|
206
|
+
} else {
|
|
207
|
+
newAmm = amm;
|
|
208
|
+
}
|
|
209
|
+
|
|
142
210
|
const askReserves = calculateSpreadReserves(
|
|
143
211
|
newAmm,
|
|
144
212
|
PositionDirection.LONG,
|
|
@@ -237,15 +305,115 @@ export function calculateAmmReservesAfterSwap(
|
|
|
237
305
|
return [newQuoteAssetReserve, newBaseAssetReserve];
|
|
238
306
|
}
|
|
239
307
|
|
|
308
|
+
export function calculateEffectiveLeverage(
|
|
309
|
+
baseSpread: number,
|
|
310
|
+
quoteAssetReserve: BN,
|
|
311
|
+
terminalQuoteAssetReserve: BN,
|
|
312
|
+
pegMultiplier: BN,
|
|
313
|
+
netBaseAssetAmount: BN,
|
|
314
|
+
markPrice: BN,
|
|
315
|
+
totalFeeMinusDistributions: BN
|
|
316
|
+
): number {
|
|
317
|
+
// inventory skew
|
|
318
|
+
const netBaseAssetValue = quoteAssetReserve
|
|
319
|
+
.sub(terminalQuoteAssetReserve)
|
|
320
|
+
.mul(pegMultiplier)
|
|
321
|
+
.div(AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO);
|
|
322
|
+
|
|
323
|
+
const localBaseAssetValue = netBaseAssetAmount
|
|
324
|
+
.mul(markPrice)
|
|
325
|
+
.div(AMM_TO_QUOTE_PRECISION_RATIO.mul(MARK_PRICE_PRECISION));
|
|
326
|
+
|
|
327
|
+
const effectiveLeverage =
|
|
328
|
+
localBaseAssetValue.sub(netBaseAssetValue).toNumber() /
|
|
329
|
+
(Math.max(0, totalFeeMinusDistributions.toNumber()) + 1) +
|
|
330
|
+
1 / QUOTE_PRECISION.toNumber();
|
|
331
|
+
|
|
332
|
+
return effectiveLeverage;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
export function calculateMaxSpread(marginRatioInitial: number): number {
|
|
336
|
+
const maxTargetSpread: number = new BN(marginRatioInitial)
|
|
337
|
+
.mul(BID_ASK_SPREAD_PRECISION.div(MARGIN_PRECISION))
|
|
338
|
+
.toNumber();
|
|
339
|
+
|
|
340
|
+
return maxTargetSpread;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
export function calculateSpreadBN(
|
|
344
|
+
baseSpread: number,
|
|
345
|
+
lastOracleMarkSpreadPct: BN,
|
|
346
|
+
lastOracleConfPct: BN,
|
|
347
|
+
maxSpread: number,
|
|
348
|
+
quoteAssetReserve: BN,
|
|
349
|
+
terminalQuoteAssetReserve: BN,
|
|
350
|
+
pegMultiplier: BN,
|
|
351
|
+
netBaseAssetAmount: BN,
|
|
352
|
+
markPrice: BN,
|
|
353
|
+
totalFeeMinusDistributions: BN
|
|
354
|
+
): [number, number] {
|
|
355
|
+
let longSpread = baseSpread / 2;
|
|
356
|
+
let shortSpread = baseSpread / 2;
|
|
357
|
+
|
|
358
|
+
if (lastOracleMarkSpreadPct.gt(ZERO)) {
|
|
359
|
+
shortSpread = Math.max(
|
|
360
|
+
shortSpread,
|
|
361
|
+
lastOracleMarkSpreadPct.abs().toNumber() + lastOracleConfPct.toNumber()
|
|
362
|
+
);
|
|
363
|
+
} else if (lastOracleMarkSpreadPct.lt(ZERO)) {
|
|
364
|
+
longSpread = Math.max(
|
|
365
|
+
longSpread,
|
|
366
|
+
lastOracleMarkSpreadPct.abs().toNumber() + lastOracleConfPct.toNumber()
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
const maxTargetSpread: number = maxSpread;
|
|
371
|
+
|
|
372
|
+
const MAX_INVENTORY_SKEW = 5;
|
|
373
|
+
|
|
374
|
+
const effectiveLeverage = calculateEffectiveLeverage(
|
|
375
|
+
baseSpread,
|
|
376
|
+
quoteAssetReserve,
|
|
377
|
+
terminalQuoteAssetReserve,
|
|
378
|
+
pegMultiplier,
|
|
379
|
+
netBaseAssetAmount,
|
|
380
|
+
markPrice,
|
|
381
|
+
totalFeeMinusDistributions
|
|
382
|
+
);
|
|
383
|
+
|
|
384
|
+
if (totalFeeMinusDistributions.gt(ZERO)) {
|
|
385
|
+
const spreadScale = Math.min(MAX_INVENTORY_SKEW, 1 + effectiveLeverage);
|
|
386
|
+
if (netBaseAssetAmount.gt(ZERO)) {
|
|
387
|
+
longSpread *= spreadScale;
|
|
388
|
+
} else {
|
|
389
|
+
shortSpread *= spreadScale;
|
|
390
|
+
}
|
|
391
|
+
} else {
|
|
392
|
+
longSpread *= MAX_INVENTORY_SKEW;
|
|
393
|
+
shortSpread *= MAX_INVENTORY_SKEW;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const totalSpread = longSpread + shortSpread;
|
|
397
|
+
if (totalSpread > maxTargetSpread) {
|
|
398
|
+
if (longSpread > shortSpread) {
|
|
399
|
+
longSpread = Math.min(longSpread, maxTargetSpread);
|
|
400
|
+
shortSpread = maxTargetSpread - longSpread;
|
|
401
|
+
} else {
|
|
402
|
+
shortSpread = Math.min(shortSpread, maxTargetSpread);
|
|
403
|
+
longSpread = maxTargetSpread - shortSpread;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return [longSpread, shortSpread];
|
|
408
|
+
}
|
|
409
|
+
|
|
240
410
|
export function calculateSpread(
|
|
241
411
|
amm: AMM,
|
|
242
412
|
direction: PositionDirection,
|
|
243
413
|
oraclePriceData: OraclePriceData
|
|
244
414
|
): number {
|
|
245
|
-
let spread = amm.baseSpread / 2;
|
|
246
|
-
|
|
247
415
|
if (amm.baseSpread == 0 || amm.curveUpdateIntensity == 0) {
|
|
248
|
-
return
|
|
416
|
+
return amm.baseSpread / 2;
|
|
249
417
|
}
|
|
250
418
|
|
|
251
419
|
const markPrice = calculatePrice(
|
|
@@ -255,49 +423,36 @@ export function calculateSpread(
|
|
|
255
423
|
);
|
|
256
424
|
|
|
257
425
|
const targetPrice = oraclePriceData?.price || markPrice;
|
|
426
|
+
const confInterval = oraclePriceData.confidence || ZERO;
|
|
258
427
|
|
|
259
428
|
const targetMarkSpreadPct = markPrice
|
|
260
429
|
.sub(targetPrice)
|
|
261
430
|
.mul(BID_ASK_SPREAD_PRECISION)
|
|
262
431
|
.div(markPrice);
|
|
263
432
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
(isVariant(direction, 'short') && targetMarkSpreadPct.gt(ZERO))
|
|
268
|
-
) {
|
|
269
|
-
spread = Math.max(spread, targetMarkSpreadPct.abs().toNumber());
|
|
270
|
-
}
|
|
433
|
+
const confIntervalPct = confInterval
|
|
434
|
+
.mul(BID_ASK_SPREAD_PRECISION)
|
|
435
|
+
.div(markPrice);
|
|
271
436
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
amm.
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
const localBaseAssetValue = amm.netBaseAssetAmount
|
|
288
|
-
.mul(markPrice)
|
|
289
|
-
.div(AMM_TO_QUOTE_PRECISION_RATIO.mul(MARK_PRICE_PRECISION));
|
|
290
|
-
const netPnl = netBaseAssetValue.sub(netCostBasis);
|
|
291
|
-
const localPnl = localBaseAssetValue.sub(netCostBasis);
|
|
292
|
-
|
|
293
|
-
let effectiveLeverage = MAX_INVENTORY_SKEW;
|
|
294
|
-
if (amm.totalFeeMinusDistributions.gt(ZERO)) {
|
|
295
|
-
effectiveLeverage =
|
|
296
|
-
localPnl.sub(netPnl).toNumber() /
|
|
297
|
-
amm.totalFeeMinusDistributions.toNumber();
|
|
298
|
-
}
|
|
437
|
+
const [longSpread, shortSpread] = calculateSpreadBN(
|
|
438
|
+
amm.baseSpread,
|
|
439
|
+
targetMarkSpreadPct,
|
|
440
|
+
confIntervalPct,
|
|
441
|
+
amm.maxSpread,
|
|
442
|
+
amm.quoteAssetReserve,
|
|
443
|
+
amm.terminalQuoteAssetReserve,
|
|
444
|
+
amm.pegMultiplier,
|
|
445
|
+
amm.netBaseAssetAmount,
|
|
446
|
+
markPrice,
|
|
447
|
+
amm.totalFeeMinusDistributions
|
|
448
|
+
);
|
|
449
|
+
|
|
450
|
+
let spread: number;
|
|
299
451
|
|
|
300
|
-
|
|
452
|
+
if (isVariant(direction, 'long')) {
|
|
453
|
+
spread = longSpread;
|
|
454
|
+
} else {
|
|
455
|
+
spread = shortSpread;
|
|
301
456
|
}
|
|
302
457
|
|
|
303
458
|
return spread;
|
package/src/math/auction.ts
CHANGED
|
@@ -2,7 +2,11 @@ import { isVariant, Order } from '../types';
|
|
|
2
2
|
import { BN, ZERO } from '../.';
|
|
3
3
|
|
|
4
4
|
export function isAuctionComplete(order: Order, slot: number): boolean {
|
|
5
|
-
|
|
5
|
+
if (order.auctionDuration === 0) {
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
return new BN(slot).sub(order.slot).gt(new BN(order.auctionDuration));
|
|
6
10
|
}
|
|
7
11
|
|
|
8
12
|
export function getAuctionPrice(order: Order, slot: number): BN {
|
package/src/math/orders.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { ClearingHouseUser } from '../clearingHouseUser';
|
|
2
|
-
import { isVariant, Order } from '../types';
|
|
2
|
+
import { isOneOfVariant, isVariant, MarketAccount, Order } from '../types';
|
|
3
3
|
import { ZERO, TWO } from '../constants/numericConstants';
|
|
4
4
|
import { BN } from '@project-serum/anchor';
|
|
5
5
|
import { OraclePriceData } from '../oracles/types';
|
|
6
|
-
import { getAuctionPrice } from './auction';
|
|
6
|
+
import { getAuctionPrice, isAuctionComplete } from './auction';
|
|
7
|
+
import { calculateAskPrice, calculateBidPrice } from './market';
|
|
7
8
|
|
|
8
9
|
export function isOrderRiskIncreasing(
|
|
9
10
|
user: ClearingHouseUser,
|
|
@@ -120,24 +121,27 @@ export function standardizeBaseAssetAmount(
|
|
|
120
121
|
|
|
121
122
|
export function getLimitPrice(
|
|
122
123
|
order: Order,
|
|
124
|
+
market: MarketAccount,
|
|
123
125
|
oraclePriceData: OraclePriceData,
|
|
124
126
|
slot: number
|
|
125
127
|
): BN {
|
|
126
128
|
let limitPrice;
|
|
127
129
|
if (!order.oraclePriceOffset.eq(ZERO)) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
130
|
+
limitPrice = oraclePriceData.price.add(order.oraclePriceOffset);
|
|
131
|
+
} else if (isOneOfVariant(order.orderType, ['market', 'triggerMarket'])) {
|
|
132
|
+
if (isAuctionComplete(order, slot)) {
|
|
133
|
+
limitPrice = getAuctionPrice(order, slot);
|
|
134
|
+
} else if (!order.price.eq(ZERO)) {
|
|
135
|
+
limitPrice = order.price;
|
|
136
|
+
} else if (isVariant(order.direction, 'long')) {
|
|
137
|
+
const askPrice = calculateAskPrice(market, oraclePriceData);
|
|
138
|
+
const delta = askPrice.div(new BN(market.amm.maxSlippageRatio));
|
|
139
|
+
limitPrice = askPrice.add(delta);
|
|
133
140
|
} else {
|
|
134
|
-
|
|
141
|
+
const bidPrice = calculateBidPrice(market, oraclePriceData);
|
|
142
|
+
const delta = bidPrice.div(new BN(market.amm.maxSlippageRatio));
|
|
143
|
+
limitPrice = bidPrice.sub(delta);
|
|
135
144
|
}
|
|
136
|
-
} else if (
|
|
137
|
-
isVariant(order.orderType, 'market') ||
|
|
138
|
-
isVariant(order.orderType, 'triggerMarket')
|
|
139
|
-
) {
|
|
140
|
-
limitPrice = getAuctionPrice(order, slot);
|
|
141
145
|
} else {
|
|
142
146
|
limitPrice = order.price;
|
|
143
147
|
}
|
package/src/math/repeg.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
AMM_RESERVE_PRECISION,
|
|
6
6
|
PEG_PRECISION,
|
|
7
7
|
AMM_TO_QUOTE_PRECISION_RATIO,
|
|
8
|
+
PRICE_DIV_PEG,
|
|
8
9
|
QUOTE_PRECISION,
|
|
9
10
|
ZERO,
|
|
10
11
|
} from '../constants/numericConstants';
|
|
@@ -142,7 +143,7 @@ export function calculateBudgetedPeg(amm: AMM, cost: BN, targetPrice: BN): BN {
|
|
|
142
143
|
const targetPeg = targetPrice
|
|
143
144
|
.mul(amm.baseAssetReserve)
|
|
144
145
|
.div(amm.quoteAssetReserve)
|
|
145
|
-
.div(
|
|
146
|
+
.div(PRICE_DIV_PEG);
|
|
146
147
|
|
|
147
148
|
const k = amm.sqrtK.mul(amm.sqrtK);
|
|
148
149
|
const x = amm.baseAssetReserve;
|
package/src/math/trade.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MarketAccount, PositionDirection
|
|
1
|
+
import { MarketAccount, PositionDirection } from '../types';
|
|
2
2
|
import { BN } from '@project-serum/anchor';
|
|
3
3
|
import { assert } from '../assert/assert';
|
|
4
4
|
import {
|
|
@@ -78,28 +78,20 @@ export function calculateTradeSlippage(
|
|
|
78
78
|
if (amount.eq(ZERO)) {
|
|
79
79
|
return [ZERO, ZERO, oldPrice, oldPrice];
|
|
80
80
|
}
|
|
81
|
-
const [
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const swapDirection = isVariant(direction, 'long')
|
|
91
|
-
? SwapDirection.REMOVE
|
|
92
|
-
: SwapDirection.ADD;
|
|
93
|
-
const quoteAssetAmountAcquired = calculateQuoteAssetAmountSwapped(
|
|
94
|
-
acquiredQuote.abs(),
|
|
95
|
-
market.amm.pegMultiplier,
|
|
96
|
-
swapDirection
|
|
97
|
-
);
|
|
81
|
+
const [acquiredBaseReserve, acquiredQuoteReserve, acquiredQuoteAssetAmount] =
|
|
82
|
+
calculateTradeAcquiredAmounts(
|
|
83
|
+
direction,
|
|
84
|
+
amount,
|
|
85
|
+
market,
|
|
86
|
+
inputAssetType,
|
|
87
|
+
oraclePriceData,
|
|
88
|
+
useSpread
|
|
89
|
+
);
|
|
98
90
|
|
|
99
|
-
const entryPrice =
|
|
91
|
+
const entryPrice = acquiredQuoteAssetAmount
|
|
100
92
|
.mul(AMM_TO_QUOTE_PRECISION_RATIO)
|
|
101
93
|
.mul(MARK_PRICE_PRECISION)
|
|
102
|
-
.div(
|
|
94
|
+
.div(acquiredBaseReserve.abs());
|
|
103
95
|
|
|
104
96
|
let amm: Parameters<typeof calculateAmmReservesAfterSwap>[0];
|
|
105
97
|
if (useSpread && market.amm.baseSpread > 0) {
|
|
@@ -116,8 +108,8 @@ export function calculateTradeSlippage(
|
|
|
116
108
|
}
|
|
117
109
|
|
|
118
110
|
const newPrice = calculatePrice(
|
|
119
|
-
amm.baseAssetReserve.sub(
|
|
120
|
-
amm.quoteAssetReserve.sub(
|
|
111
|
+
amm.baseAssetReserve.sub(acquiredBaseReserve),
|
|
112
|
+
amm.quoteAssetReserve.sub(acquiredQuoteReserve),
|
|
121
113
|
amm.pegMultiplier
|
|
122
114
|
);
|
|
123
115
|
|
|
@@ -159,9 +151,9 @@ export function calculateTradeAcquiredAmounts(
|
|
|
159
151
|
inputAssetType: AssetType = 'quote',
|
|
160
152
|
oraclePriceData: OraclePriceData,
|
|
161
153
|
useSpread = true
|
|
162
|
-
): [BN, BN] {
|
|
154
|
+
): [BN, BN, BN] {
|
|
163
155
|
if (amount.eq(ZERO)) {
|
|
164
|
-
return [ZERO, ZERO];
|
|
156
|
+
return [ZERO, ZERO, ZERO];
|
|
165
157
|
}
|
|
166
158
|
|
|
167
159
|
const swapDirection = getSwapDirection(inputAssetType, direction);
|
|
@@ -185,7 +177,13 @@ export function calculateTradeAcquiredAmounts(
|
|
|
185
177
|
|
|
186
178
|
const acquiredBase = amm.baseAssetReserve.sub(newBaseAssetReserve);
|
|
187
179
|
const acquiredQuote = amm.quoteAssetReserve.sub(newQuoteAssetReserve);
|
|
188
|
-
|
|
180
|
+
const acquiredQuoteAssetamount = calculateQuoteAssetAmountSwapped(
|
|
181
|
+
acquiredQuote.abs(),
|
|
182
|
+
amm.pegMultiplier,
|
|
183
|
+
swapDirection
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
return [acquiredBase, acquiredQuote, acquiredQuoteAssetamount];
|
|
189
187
|
}
|
|
190
188
|
|
|
191
189
|
/**
|
package/src/orderParams.ts
CHANGED
|
@@ -1,154 +1,33 @@
|
|
|
1
|
-
import {
|
|
2
|
-
OrderParams,
|
|
3
|
-
OrderTriggerCondition,
|
|
4
|
-
OrderType,
|
|
5
|
-
PositionDirection,
|
|
6
|
-
} from './types';
|
|
1
|
+
import { OptionalOrderParams, OrderTriggerCondition, OrderType } from './types';
|
|
7
2
|
import { BN } from '@project-serum/anchor';
|
|
8
|
-
import { ZERO } from './constants/numericConstants';
|
|
9
3
|
|
|
10
4
|
export function getLimitOrderParams(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
price: BN,
|
|
15
|
-
reduceOnly: boolean,
|
|
16
|
-
discountToken = false,
|
|
17
|
-
referrer = false,
|
|
18
|
-
userOrderId = 0,
|
|
19
|
-
postOnly = false,
|
|
20
|
-
oraclePriceOffset = ZERO,
|
|
21
|
-
immediateOrCancel = false
|
|
22
|
-
): OrderParams {
|
|
23
|
-
return {
|
|
24
|
-
orderType: OrderType.LIMIT,
|
|
25
|
-
userOrderId,
|
|
26
|
-
marketIndex,
|
|
27
|
-
direction,
|
|
28
|
-
quoteAssetAmount: ZERO,
|
|
29
|
-
baseAssetAmount,
|
|
30
|
-
price,
|
|
31
|
-
reduceOnly,
|
|
32
|
-
postOnly,
|
|
33
|
-
immediateOrCancel,
|
|
34
|
-
positionLimit: ZERO,
|
|
35
|
-
padding0: true,
|
|
36
|
-
padding1: ZERO,
|
|
37
|
-
optionalAccounts: {
|
|
38
|
-
discountToken,
|
|
39
|
-
referrer,
|
|
40
|
-
},
|
|
41
|
-
triggerCondition: OrderTriggerCondition.ABOVE,
|
|
42
|
-
triggerPrice: ZERO,
|
|
43
|
-
oraclePriceOffset,
|
|
44
|
-
};
|
|
5
|
+
params: Omit<OptionalOrderParams, 'orderType'> & { price: BN }
|
|
6
|
+
): OptionalOrderParams {
|
|
7
|
+
return Object.assign({}, params, { orderType: OrderType.LIMIT });
|
|
45
8
|
}
|
|
46
9
|
|
|
47
10
|
export function getTriggerMarketOrderParams(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
discountToken = false,
|
|
55
|
-
referrer = false,
|
|
56
|
-
userOrderId = 0
|
|
57
|
-
): OrderParams {
|
|
58
|
-
return {
|
|
59
|
-
orderType: OrderType.TRIGGER_MARKET,
|
|
60
|
-
userOrderId,
|
|
61
|
-
marketIndex,
|
|
62
|
-
direction,
|
|
63
|
-
quoteAssetAmount: ZERO,
|
|
64
|
-
baseAssetAmount,
|
|
65
|
-
price: ZERO,
|
|
66
|
-
reduceOnly,
|
|
67
|
-
postOnly: false,
|
|
68
|
-
immediateOrCancel: false,
|
|
69
|
-
positionLimit: ZERO,
|
|
70
|
-
padding0: true,
|
|
71
|
-
padding1: ZERO,
|
|
72
|
-
optionalAccounts: {
|
|
73
|
-
discountToken,
|
|
74
|
-
referrer,
|
|
75
|
-
},
|
|
76
|
-
triggerCondition,
|
|
77
|
-
triggerPrice,
|
|
78
|
-
oraclePriceOffset: ZERO,
|
|
79
|
-
};
|
|
11
|
+
params: Omit<OptionalOrderParams, 'orderType'> & {
|
|
12
|
+
triggerCondition: OrderTriggerCondition;
|
|
13
|
+
triggerPrice: BN;
|
|
14
|
+
}
|
|
15
|
+
): OptionalOrderParams {
|
|
16
|
+
return Object.assign({}, params, { orderType: OrderType.TRIGGER_MARKET });
|
|
80
17
|
}
|
|
81
18
|
|
|
82
19
|
export function getTriggerLimitOrderParams(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
discountToken = false,
|
|
91
|
-
referrer = false,
|
|
92
|
-
userOrderId = 0
|
|
93
|
-
): OrderParams {
|
|
94
|
-
return {
|
|
95
|
-
orderType: OrderType.TRIGGER_LIMIT,
|
|
96
|
-
userOrderId,
|
|
97
|
-
marketIndex,
|
|
98
|
-
direction,
|
|
99
|
-
quoteAssetAmount: ZERO,
|
|
100
|
-
baseAssetAmount,
|
|
101
|
-
price,
|
|
102
|
-
reduceOnly,
|
|
103
|
-
postOnly: false,
|
|
104
|
-
immediateOrCancel: false,
|
|
105
|
-
positionLimit: ZERO,
|
|
106
|
-
padding0: true,
|
|
107
|
-
padding1: ZERO,
|
|
108
|
-
optionalAccounts: {
|
|
109
|
-
discountToken,
|
|
110
|
-
referrer,
|
|
111
|
-
},
|
|
112
|
-
triggerCondition,
|
|
113
|
-
triggerPrice,
|
|
114
|
-
oraclePriceOffset: ZERO,
|
|
115
|
-
};
|
|
20
|
+
params: Omit<OptionalOrderParams, 'orderType'> & {
|
|
21
|
+
triggerCondition: OrderTriggerCondition;
|
|
22
|
+
triggerPrice: BN;
|
|
23
|
+
price: BN;
|
|
24
|
+
}
|
|
25
|
+
): OptionalOrderParams {
|
|
26
|
+
return Object.assign({}, params, { orderType: OrderType.TRIGGER_LIMIT });
|
|
116
27
|
}
|
|
117
28
|
|
|
118
29
|
export function getMarketOrderParams(
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
baseAssetAmount: BN,
|
|
123
|
-
reduceOnly: boolean,
|
|
124
|
-
price = ZERO,
|
|
125
|
-
discountToken = false,
|
|
126
|
-
referrer = false
|
|
127
|
-
): OrderParams {
|
|
128
|
-
if (baseAssetAmount.eq(ZERO) && quoteAssetAmount.eq(ZERO)) {
|
|
129
|
-
throw Error('baseAssetAmount or quoteAssetAmount must be zero');
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return {
|
|
133
|
-
orderType: OrderType.MARKET,
|
|
134
|
-
userOrderId: 0,
|
|
135
|
-
marketIndex,
|
|
136
|
-
direction,
|
|
137
|
-
quoteAssetAmount,
|
|
138
|
-
baseAssetAmount,
|
|
139
|
-
price,
|
|
140
|
-
reduceOnly,
|
|
141
|
-
postOnly: false,
|
|
142
|
-
immediateOrCancel: false,
|
|
143
|
-
positionLimit: ZERO,
|
|
144
|
-
padding0: true,
|
|
145
|
-
padding1: ZERO,
|
|
146
|
-
optionalAccounts: {
|
|
147
|
-
discountToken,
|
|
148
|
-
referrer,
|
|
149
|
-
},
|
|
150
|
-
triggerCondition: OrderTriggerCondition.ABOVE,
|
|
151
|
-
triggerPrice: ZERO,
|
|
152
|
-
oraclePriceOffset: ZERO,
|
|
153
|
-
};
|
|
30
|
+
params: Omit<OptionalOrderParams, 'orderType'>
|
|
31
|
+
): OptionalOrderParams {
|
|
32
|
+
return Object.assign({}, params, { orderType: OrderType.MARKET });
|
|
154
33
|
}
|