@drift-labs/sdk 0.1.12 → 0.1.13
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 +0 -21
- package/lib/accounts/types.d.ts.map +1 -1
- package/lib/clearingHouseUser.d.ts +27 -3
- package/lib/clearingHouseUser.d.ts.map +1 -1
- package/lib/clearingHouseUser.js +195 -47
- package/lib/constants/markets.d.ts.map +1 -1
- package/lib/constants/markets.js +7 -0
- package/lib/constants/numericConstants.d.ts +1 -0
- package/lib/constants/numericConstants.d.ts.map +1 -1
- package/lib/constants/numericConstants.js +2 -1
- package/lib/examples/makeTradeExample.d.ts.map +1 -1
- package/lib/examples/makeTradeExample.js +14 -13
- package/lib/idl/clearing_house.json +94 -42
- package/lib/index.d.ts +2 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -1
- package/lib/math/amm.d.ts +26 -1
- package/lib/math/amm.d.ts.map +1 -1
- package/lib/math/amm.js +84 -10
- package/lib/math/funding.d.ts +6 -6
- package/lib/math/funding.d.ts.map +1 -1
- package/lib/math/funding.js +41 -22
- package/lib/math/insuranceFund.d.ts +14 -0
- package/lib/math/insuranceFund.d.ts.map +1 -0
- package/lib/math/insuranceFund.js +35 -0
- package/lib/math/position.d.ts +1 -1
- package/lib/math/position.d.ts.map +1 -1
- package/lib/math/position.js +15 -23
- package/lib/math/trade.d.ts +1 -1
- package/lib/math/trade.d.ts.map +1 -1
- package/lib/math/trade.js +9 -4
- package/lib/types.d.ts +0 -13
- package/lib/types.d.ts.map +1 -1
- package/lib/wallet.d.ts +10 -0
- package/lib/wallet.d.ts.map +1 -0
- package/lib/wallet.js +35 -0
- package/package.json +2 -2
- package/src/accounts/types.ts +0 -27
- package/src/clearingHouse.ts +2 -2
- package/src/clearingHouseUser.ts +282 -65
- package/src/constants/markets.ts +7 -0
- package/src/constants/numericConstants.ts +3 -0
- package/src/examples/makeTradeExample.ts +2 -1
- package/src/idl/clearing_house.json +94 -42
- package/src/index.ts +2 -1
- package/src/math/amm.ts +119 -12
- package/src/math/funding.ts +47 -25
- package/src/math/insuranceFund.ts +22 -0
- package/src/math/position.ts +15 -28
- package/src/math/trade.ts +9 -5
- package/src/types.ts +0 -14
- package/src/wallet.ts +22 -0
- package/lib/accounts/defaultHistoryAccountSubscriber.d.ts +0 -29
- package/lib/accounts/defaultHistoryAccountSubscriber.d.ts.map +0 -1
- package/lib/accounts/defaultHistoryAccountSubscriber.js +0 -110
- package/src/accounts/defaultHistoryAccountSubscriber.ts +0 -179
package/src/clearingHouseUser.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { EventEmitter } from 'events';
|
|
|
4
4
|
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
5
5
|
import { ClearingHouse } from './clearingHouse';
|
|
6
6
|
import { UserAccount, UserPosition, UserPositionsAccount } from './types';
|
|
7
|
+
import { calculateEntryPrice } from './math/position';
|
|
7
8
|
import {
|
|
8
9
|
MARK_PRICE_PRECISION,
|
|
9
10
|
AMM_TO_QUOTE_PRECISION_RATIO,
|
|
@@ -13,6 +14,8 @@ import {
|
|
|
13
14
|
PARTIAL_LIQUIDATION_RATIO,
|
|
14
15
|
FULL_LIQUIDATION_RATIO,
|
|
15
16
|
QUOTE_PRECISION,
|
|
17
|
+
AMM_RESERVE_PRECISION,
|
|
18
|
+
PRICE_TO_QUOTE_PRECISION,
|
|
16
19
|
} from './constants/numericConstants';
|
|
17
20
|
import { UserAccountSubscriber, UserAccountEvents } from './accounts/types';
|
|
18
21
|
import { DefaultUserAccountSubscriber } from './accounts/defaultUserAccountSubscriber';
|
|
@@ -81,23 +84,25 @@ export class ClearingHouseUser {
|
|
|
81
84
|
}
|
|
82
85
|
|
|
83
86
|
/**
|
|
84
|
-
* Gets the user's current position for a given market
|
|
87
|
+
* Gets the user's current position for a given market. If the user has no position returns undefined
|
|
85
88
|
* @param marketIndex
|
|
86
89
|
* @returns userPosition
|
|
87
90
|
*/
|
|
88
|
-
public getUserPosition(marketIndex: BN): UserPosition {
|
|
89
|
-
return (
|
|
90
|
-
|
|
91
|
-
position.marketIndex.eq(marketIndex)
|
|
92
|
-
) ?? {
|
|
93
|
-
baseAssetAmount: ZERO,
|
|
94
|
-
lastCumulativeFundingRate: ZERO,
|
|
95
|
-
marketIndex,
|
|
96
|
-
quoteAssetAmount: ZERO,
|
|
97
|
-
}
|
|
91
|
+
public getUserPosition(marketIndex: BN): UserPosition | undefined {
|
|
92
|
+
return this.getUserPositionsAccount().positions.find((position) =>
|
|
93
|
+
position.marketIndex.eq(marketIndex)
|
|
98
94
|
);
|
|
99
95
|
}
|
|
100
96
|
|
|
97
|
+
public getEmptyPosition(marketIndex: BN): UserPosition {
|
|
98
|
+
return {
|
|
99
|
+
baseAssetAmount: ZERO,
|
|
100
|
+
lastCumulativeFundingRate: ZERO,
|
|
101
|
+
marketIndex,
|
|
102
|
+
quoteAssetAmount: ZERO,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
101
106
|
public async getUserAccountPublicKey(): Promise<PublicKey> {
|
|
102
107
|
if (this.userAccountPublicKey) {
|
|
103
108
|
return this.userAccountPublicKey;
|
|
@@ -205,7 +210,8 @@ export class ClearingHouseUser {
|
|
|
205
210
|
* @returns : Precision QUOTE_PRECISION
|
|
206
211
|
*/
|
|
207
212
|
public getPositionValue(marketIndex: BN): BN {
|
|
208
|
-
const userPosition =
|
|
213
|
+
const userPosition =
|
|
214
|
+
this.getUserPosition(marketIndex) || this.getEmptyPosition(marketIndex);
|
|
209
215
|
const market = this.clearingHouse.getMarket(userPosition.marketIndex);
|
|
210
216
|
return calculateBaseAssetValue(market, userPosition);
|
|
211
217
|
}
|
|
@@ -226,15 +232,17 @@ export class ClearingHouseUser {
|
|
|
226
232
|
* calculates average exit price for closing 100% of position
|
|
227
233
|
* @returns : Precision MARK_PRICE_PRECISION
|
|
228
234
|
*/
|
|
229
|
-
public
|
|
235
|
+
public getPositionEstimatedExitPriceAndPnl(
|
|
230
236
|
position: UserPosition,
|
|
231
237
|
amountToClose?: BN
|
|
232
|
-
): BN {
|
|
238
|
+
): [BN, BN] {
|
|
233
239
|
const market = this.clearingHouse.getMarket(position.marketIndex);
|
|
234
240
|
|
|
241
|
+
const entryPrice = calculateEntryPrice(position);
|
|
242
|
+
|
|
235
243
|
if (amountToClose) {
|
|
236
244
|
if (amountToClose.eq(ZERO)) {
|
|
237
|
-
return calculateMarkPrice(market);
|
|
245
|
+
return [calculateMarkPrice(market), ZERO];
|
|
238
246
|
}
|
|
239
247
|
position = {
|
|
240
248
|
baseAssetAmount: amountToClose,
|
|
@@ -246,12 +254,21 @@ export class ClearingHouseUser {
|
|
|
246
254
|
|
|
247
255
|
const baseAssetValue = calculateBaseAssetValue(market, position);
|
|
248
256
|
if (position.baseAssetAmount.eq(ZERO)) {
|
|
249
|
-
return ZERO;
|
|
257
|
+
return [ZERO, ZERO];
|
|
250
258
|
}
|
|
251
|
-
|
|
259
|
+
|
|
260
|
+
const exitPrice = baseAssetValue
|
|
252
261
|
.mul(AMM_TO_QUOTE_PRECISION_RATIO)
|
|
253
262
|
.mul(MARK_PRICE_PRECISION)
|
|
254
263
|
.div(position.baseAssetAmount.abs());
|
|
264
|
+
|
|
265
|
+
const pnlPerBase = exitPrice.sub(entryPrice);
|
|
266
|
+
const pnl = pnlPerBase
|
|
267
|
+
.mul(position.baseAssetAmount)
|
|
268
|
+
.div(MARK_PRICE_PRECISION)
|
|
269
|
+
.div(AMM_TO_QUOTE_PRECISION_RATIO);
|
|
270
|
+
|
|
271
|
+
return [exitPrice, pnl];
|
|
255
272
|
}
|
|
256
273
|
|
|
257
274
|
/**
|
|
@@ -350,7 +367,7 @@ export class ClearingHouseUser {
|
|
|
350
367
|
* @param partial
|
|
351
368
|
* @returns Precision : MARK_PRICE_PRECISION
|
|
352
369
|
*/
|
|
353
|
-
public
|
|
370
|
+
public liquidationPriceOld(
|
|
354
371
|
targetMarket: Pick<UserPosition, 'marketIndex'>,
|
|
355
372
|
positionBaseSizeChange: BN = ZERO,
|
|
356
373
|
partial = false
|
|
@@ -379,13 +396,11 @@ export class ClearingHouseUser {
|
|
|
379
396
|
const totalCurrentPositionValueIgnoringTargetUSDC =
|
|
380
397
|
this.getTotalPositionValueExcludingMarket(targetMarket.marketIndex);
|
|
381
398
|
|
|
382
|
-
const currentMarketPosition =
|
|
383
|
-
targetMarket.marketIndex
|
|
384
|
-
|
|
399
|
+
const currentMarketPosition =
|
|
400
|
+
this.getUserPosition(targetMarket.marketIndex) ||
|
|
401
|
+
this.getEmptyPosition(targetMarket.marketIndex);
|
|
385
402
|
|
|
386
|
-
const currentMarketPositionBaseSize = currentMarketPosition
|
|
387
|
-
? currentMarketPosition.baseAssetAmount
|
|
388
|
-
: ZERO;
|
|
403
|
+
const currentMarketPositionBaseSize = currentMarketPosition.baseAssetAmount;
|
|
389
404
|
|
|
390
405
|
// calculate position for current market after trade
|
|
391
406
|
const proposedMarketPosition: UserPosition = {
|
|
@@ -412,9 +427,23 @@ export class ClearingHouseUser {
|
|
|
412
427
|
proposedMarketPositionValueUSDC
|
|
413
428
|
);
|
|
414
429
|
|
|
430
|
+
let totalFreeCollateralUSDC = this.getTotalCollateral().sub(
|
|
431
|
+
this.getTotalPositionValue()
|
|
432
|
+
.mul(TEN_THOUSAND)
|
|
433
|
+
.div(this.getMaxLeverage('Maintenance'))
|
|
434
|
+
);
|
|
435
|
+
|
|
436
|
+
if (partial) {
|
|
437
|
+
totalFreeCollateralUSDC = this.getTotalCollateral().sub(
|
|
438
|
+
this.getTotalPositionValue()
|
|
439
|
+
.mul(TEN_THOUSAND)
|
|
440
|
+
.div(this.getMaxLeverage('Partial'))
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
|
|
415
444
|
// if the position value after the trade is less than total collateral, there is no liq price
|
|
416
445
|
if (
|
|
417
|
-
targetTotalPositionValueUSDC.lte(
|
|
446
|
+
targetTotalPositionValueUSDC.lte(totalFreeCollateralUSDC) &&
|
|
418
447
|
proposedMarketPosition.baseAssetAmount.gt(ZERO)
|
|
419
448
|
) {
|
|
420
449
|
return new BN(-1);
|
|
@@ -456,6 +485,127 @@ export class ClearingHouseUser {
|
|
|
456
485
|
return liqPrice;
|
|
457
486
|
}
|
|
458
487
|
|
|
488
|
+
/**
|
|
489
|
+
* Calculate the liquidation price of a position, with optional parameter to calculate the liquidation price after a trade
|
|
490
|
+
* @param targetMarket
|
|
491
|
+
* @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^13
|
|
492
|
+
* @param partial
|
|
493
|
+
* @returns Precision : MARK_PRICE_PRECISION
|
|
494
|
+
*/
|
|
495
|
+
public liquidationPrice(
|
|
496
|
+
targetMarket: Pick<UserPosition, 'marketIndex'>,
|
|
497
|
+
positionBaseSizeChange: BN = ZERO,
|
|
498
|
+
partial = false
|
|
499
|
+
): BN {
|
|
500
|
+
// solves formula for example calc below
|
|
501
|
+
|
|
502
|
+
/* example: assume BTC price is $40k (examine 10% up/down)
|
|
503
|
+
|
|
504
|
+
if 10k deposit and levered 10x short BTC => BTC up $400 means:
|
|
505
|
+
1. higher base_asset_value (+$4k)
|
|
506
|
+
2. lower collateral (-$4k)
|
|
507
|
+
3. (10k - 4k)/(100k + 4k) => 6k/104k => .0576
|
|
508
|
+
|
|
509
|
+
for 10x long, BTC down $400:
|
|
510
|
+
3. (10k - 4k) / (100k - 4k) = 6k/96k => .0625 */
|
|
511
|
+
|
|
512
|
+
const tc = this.getTotalCollateral();
|
|
513
|
+
const tpv = this.getTotalPositionValue();
|
|
514
|
+
|
|
515
|
+
const partialLev = 16;
|
|
516
|
+
const maintLev = 20;
|
|
517
|
+
|
|
518
|
+
const thisLev = partial ? new BN(partialLev) : new BN(maintLev);
|
|
519
|
+
|
|
520
|
+
// calculate the total position value ignoring any value from the target market of the trade
|
|
521
|
+
const totalCurrentPositionValueIgnoringTargetUSDC =
|
|
522
|
+
this.getTotalPositionValueExcludingMarket(targetMarket.marketIndex);
|
|
523
|
+
|
|
524
|
+
const currentMarketPosition =
|
|
525
|
+
this.getUserPosition(targetMarket.marketIndex) ||
|
|
526
|
+
this.getEmptyPosition(targetMarket.marketIndex);
|
|
527
|
+
|
|
528
|
+
const currentMarketPositionBaseSize = currentMarketPosition.baseAssetAmount;
|
|
529
|
+
|
|
530
|
+
const proposedBaseAssetAmount = currentMarketPositionBaseSize.add(
|
|
531
|
+
positionBaseSizeChange
|
|
532
|
+
);
|
|
533
|
+
|
|
534
|
+
// calculate position for current market after trade
|
|
535
|
+
const proposedMarketPosition: UserPosition = {
|
|
536
|
+
marketIndex: targetMarket.marketIndex,
|
|
537
|
+
baseAssetAmount: proposedBaseAssetAmount,
|
|
538
|
+
lastCumulativeFundingRate:
|
|
539
|
+
currentMarketPosition.lastCumulativeFundingRate,
|
|
540
|
+
quoteAssetAmount: new BN(0),
|
|
541
|
+
};
|
|
542
|
+
|
|
543
|
+
const market = this.clearingHouse.getMarket(
|
|
544
|
+
proposedMarketPosition.marketIndex
|
|
545
|
+
);
|
|
546
|
+
|
|
547
|
+
const proposedMarketPositionValueUSDC = calculateBaseAssetValue(
|
|
548
|
+
market,
|
|
549
|
+
proposedMarketPosition
|
|
550
|
+
);
|
|
551
|
+
|
|
552
|
+
// total position value after trade
|
|
553
|
+
const targetTotalPositionValueUSDC =
|
|
554
|
+
totalCurrentPositionValueIgnoringTargetUSDC.add(
|
|
555
|
+
proposedMarketPositionValueUSDC
|
|
556
|
+
);
|
|
557
|
+
|
|
558
|
+
let totalFreeCollateralUSDC = tc.sub(
|
|
559
|
+
totalCurrentPositionValueIgnoringTargetUSDC
|
|
560
|
+
.mul(TEN_THOUSAND)
|
|
561
|
+
.div(this.getMaxLeverage('Maintenance'))
|
|
562
|
+
);
|
|
563
|
+
|
|
564
|
+
if (partial) {
|
|
565
|
+
totalFreeCollateralUSDC = tc.sub(
|
|
566
|
+
totalCurrentPositionValueIgnoringTargetUSDC
|
|
567
|
+
.mul(TEN_THOUSAND)
|
|
568
|
+
.div(this.getMaxLeverage('Partial'))
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
let priceDelt;
|
|
573
|
+
if (currentMarketPositionBaseSize.lt(ZERO)) {
|
|
574
|
+
priceDelt = tc
|
|
575
|
+
.mul(thisLev)
|
|
576
|
+
.sub(tpv)
|
|
577
|
+
.mul(PRICE_TO_QUOTE_PRECISION)
|
|
578
|
+
.div(thisLev.add(new BN(1)));
|
|
579
|
+
} else {
|
|
580
|
+
priceDelt = tc
|
|
581
|
+
.mul(thisLev)
|
|
582
|
+
.sub(tpv)
|
|
583
|
+
.mul(PRICE_TO_QUOTE_PRECISION)
|
|
584
|
+
.div(thisLev.sub(new BN(1)));
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
const currentPrice = calculateMarkPrice(
|
|
588
|
+
this.clearingHouse.getMarket(targetMarket.marketIndex)
|
|
589
|
+
);
|
|
590
|
+
|
|
591
|
+
// if the position value after the trade is less than total collateral, there is no liq price
|
|
592
|
+
if (
|
|
593
|
+
targetTotalPositionValueUSDC.lte(totalFreeCollateralUSDC) &&
|
|
594
|
+
proposedMarketPosition.baseAssetAmount.gt(ZERO)
|
|
595
|
+
) {
|
|
596
|
+
return new BN(-1);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
if (proposedBaseAssetAmount.eq(ZERO)) return new BN(-1);
|
|
600
|
+
|
|
601
|
+
const eatMargin2 = priceDelt
|
|
602
|
+
.mul(AMM_RESERVE_PRECISION)
|
|
603
|
+
.div(proposedBaseAssetAmount);
|
|
604
|
+
|
|
605
|
+
const liqPrice = currentPrice.sub(eatMargin2);
|
|
606
|
+
return liqPrice;
|
|
607
|
+
}
|
|
608
|
+
|
|
459
609
|
/**
|
|
460
610
|
* Calculates the estimated liquidation price for a position after closing a quote amount of the position.
|
|
461
611
|
* @param positionMarketIndex
|
|
@@ -466,7 +616,9 @@ export class ClearingHouseUser {
|
|
|
466
616
|
positionMarketIndex: BN,
|
|
467
617
|
closeQuoteAmount: BN
|
|
468
618
|
): BN {
|
|
469
|
-
const currentPosition =
|
|
619
|
+
const currentPosition =
|
|
620
|
+
this.getUserPosition(positionMarketIndex) ||
|
|
621
|
+
this.getEmptyPosition(positionMarketIndex);
|
|
470
622
|
|
|
471
623
|
const closeBaseAmount = currentPosition.baseAssetAmount
|
|
472
624
|
.mul(closeQuoteAmount)
|
|
@@ -488,6 +640,21 @@ export class ClearingHouseUser {
|
|
|
488
640
|
|
|
489
641
|
/**
|
|
490
642
|
* Get the maximum trade size for a given market, taking into account the user's current leverage, positions, collateral, etc.
|
|
643
|
+
*
|
|
644
|
+
* To Calculate Max Quote Available:
|
|
645
|
+
*
|
|
646
|
+
* Case 1: SameSide
|
|
647
|
+
* => Remaining quote to get to maxLeverage
|
|
648
|
+
*
|
|
649
|
+
* Case 2: NOT SameSide && currentLeverage <= maxLeverage
|
|
650
|
+
* => Current opposite position x2 + remaining to get to maxLeverage
|
|
651
|
+
*
|
|
652
|
+
* Case 3: NOT SameSide && currentLeverage > maxLeverage && otherPositions - currentPosition > maxLeverage
|
|
653
|
+
* => strictly reduce current position size
|
|
654
|
+
*
|
|
655
|
+
* Case 4: NOT SameSide && currentLeverage > maxLeverage && otherPositions - currentPosition < maxLeverage
|
|
656
|
+
* => current position + remaining to get to maxLeverage
|
|
657
|
+
*
|
|
491
658
|
* @param marketIndex
|
|
492
659
|
* @param tradeSide
|
|
493
660
|
* @param userMaxLeverageSetting - leverage : Precision TEN_THOUSAND
|
|
@@ -498,32 +665,28 @@ export class ClearingHouseUser {
|
|
|
498
665
|
tradeSide: PositionDirection,
|
|
499
666
|
userMaxLeverageSetting: BN
|
|
500
667
|
): BN {
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
668
|
+
const currentPosition =
|
|
669
|
+
this.getUserPosition(targetMarketIndex) ||
|
|
670
|
+
this.getEmptyPosition(targetMarketIndex);
|
|
504
671
|
|
|
505
|
-
|
|
672
|
+
const targetSide = tradeSide === PositionDirection.SHORT ? 'short' : 'long';
|
|
506
673
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
side === 'short' &&
|
|
511
|
-
!currentPosition?.baseAssetAmount.isNeg()
|
|
512
|
-
) {
|
|
513
|
-
return this.getPositionValue(targetMarketIndex);
|
|
514
|
-
}
|
|
674
|
+
const currentPositionSide = currentPosition?.baseAssetAmount.isNeg()
|
|
675
|
+
? 'short'
|
|
676
|
+
: 'long';
|
|
515
677
|
|
|
516
|
-
|
|
517
|
-
|
|
678
|
+
const targettingSameSide = !currentPosition
|
|
679
|
+
? true
|
|
680
|
+
: targetSide === currentPositionSide;
|
|
518
681
|
|
|
519
|
-
|
|
682
|
+
// add any position we have on the opposite side of the current trade, because we can "flip" the size of this position without taking any extra leverage.
|
|
683
|
+
const oppositeSizeValueUSDC = targettingSameSide
|
|
684
|
+
? ZERO
|
|
685
|
+
: this.getPositionValue(targetMarketIndex);
|
|
520
686
|
|
|
521
687
|
// get current leverage
|
|
522
688
|
const currentLeverage = this.getLeverage();
|
|
523
689
|
|
|
524
|
-
// remaining leverage
|
|
525
|
-
// let remainingLeverage = userMaxLeverageSetting;
|
|
526
|
-
|
|
527
690
|
const remainingLeverage = BN.max(
|
|
528
691
|
userMaxLeverageSetting.sub(currentLeverage),
|
|
529
692
|
ZERO
|
|
@@ -537,10 +700,57 @@ export class ClearingHouseUser {
|
|
|
537
700
|
.mul(totalCollateral)
|
|
538
701
|
.div(TEN_THOUSAND);
|
|
539
702
|
|
|
540
|
-
|
|
541
|
-
|
|
703
|
+
if (userMaxLeverageSetting.sub(currentLeverage).gte(ZERO)) {
|
|
704
|
+
if (oppositeSizeValueUSDC.eq(ZERO)) {
|
|
705
|
+
// case 1 : Regular trade where current total position less than max, and no opposite position to account for
|
|
706
|
+
// do nothing
|
|
707
|
+
} else {
|
|
708
|
+
// case 2 : trade where current total position less than max, but need to account for flipping the current position over to the other side
|
|
709
|
+
maxPositionSize = maxPositionSize.add(
|
|
710
|
+
oppositeSizeValueUSDC.mul(new BN(2))
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
} else {
|
|
714
|
+
// current leverage is greater than max leverage - can only reduce position size
|
|
542
715
|
|
|
543
|
-
|
|
716
|
+
if (!targettingSameSide) {
|
|
717
|
+
const currentPositionQuoteSize =
|
|
718
|
+
this.getPositionValue(targetMarketIndex);
|
|
719
|
+
|
|
720
|
+
const currentTotalQuoteSize = currentLeverage
|
|
721
|
+
.mul(totalCollateral)
|
|
722
|
+
.div(TEN_THOUSAND);
|
|
723
|
+
|
|
724
|
+
const otherPositionsTotalQuoteSize = currentTotalQuoteSize.sub(
|
|
725
|
+
currentPositionQuoteSize
|
|
726
|
+
);
|
|
727
|
+
|
|
728
|
+
const quoteValueOfMaxLeverage = userMaxLeverageSetting
|
|
729
|
+
.mul(totalCollateral)
|
|
730
|
+
.div(TEN_THOUSAND);
|
|
731
|
+
|
|
732
|
+
if (
|
|
733
|
+
otherPositionsTotalQuoteSize
|
|
734
|
+
.sub(currentPositionQuoteSize)
|
|
735
|
+
.gte(quoteValueOfMaxLeverage)
|
|
736
|
+
) {
|
|
737
|
+
// case 3: Can only reduce the current position because it will still be greater than max leverage
|
|
738
|
+
|
|
739
|
+
maxPositionSize = currentPositionQuoteSize;
|
|
740
|
+
} else {
|
|
741
|
+
// case 4: Can reduce the position, and then take extra remaining quote to get to max leverage
|
|
742
|
+
|
|
743
|
+
const allowedQuoteSizeAfterClosingCurrentPosition =
|
|
744
|
+
quoteValueOfMaxLeverage.sub(otherPositionsTotalQuoteSize);
|
|
745
|
+
|
|
746
|
+
maxPositionSize = currentPositionQuoteSize.add(
|
|
747
|
+
allowedQuoteSizeAfterClosingCurrentPosition
|
|
748
|
+
);
|
|
749
|
+
}
|
|
750
|
+
} else {
|
|
751
|
+
// do nothing if targetting same side
|
|
752
|
+
}
|
|
753
|
+
}
|
|
544
754
|
|
|
545
755
|
// subtract oneMillionth of maxPositionSize
|
|
546
756
|
// => to avoid rounding errors when taking max leverage
|
|
@@ -562,12 +772,16 @@ export class ClearingHouseUser {
|
|
|
562
772
|
tradeQuoteAmount: BN,
|
|
563
773
|
tradeSide: PositionDirection
|
|
564
774
|
): BN {
|
|
565
|
-
const currentPosition =
|
|
566
|
-
|
|
775
|
+
const currentPosition =
|
|
776
|
+
this.getUserPosition(targetMarketIndex) ||
|
|
777
|
+
this.getEmptyPosition(targetMarketIndex);
|
|
778
|
+
|
|
779
|
+
let currentPositionQuoteAmount = this.getPositionValue(targetMarketIndex);
|
|
567
780
|
|
|
568
|
-
const currentSide =
|
|
569
|
-
|
|
570
|
-
|
|
781
|
+
const currentSide =
|
|
782
|
+
currentPosition && currentPosition.baseAssetAmount.isNeg()
|
|
783
|
+
? PositionDirection.SHORT
|
|
784
|
+
: PositionDirection.LONG;
|
|
571
785
|
|
|
572
786
|
if (currentSide === PositionDirection.SHORT)
|
|
573
787
|
currentPositionQuoteAmount = currentPositionQuoteAmount.neg();
|
|
@@ -582,11 +796,18 @@ export class ClearingHouseUser {
|
|
|
582
796
|
const totalPositionAfterTradeExcludingTargetMarket =
|
|
583
797
|
this.getTotalPositionValueExcludingMarket(targetMarketIndex);
|
|
584
798
|
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
799
|
+
const totalCollateral = this.getTotalCollateral();
|
|
800
|
+
|
|
801
|
+
if (totalCollateral.gt(ZERO)) {
|
|
802
|
+
const newLeverage = currentMarketPositionAfterTrade
|
|
803
|
+
.add(totalPositionAfterTradeExcludingTargetMarket)
|
|
804
|
+
.abs()
|
|
805
|
+
.mul(TEN_THOUSAND)
|
|
806
|
+
.div(totalCollateral);
|
|
807
|
+
return newLeverage;
|
|
808
|
+
} else {
|
|
809
|
+
return new BN(0);
|
|
810
|
+
}
|
|
590
811
|
}
|
|
591
812
|
|
|
592
813
|
/**
|
|
@@ -608,17 +829,13 @@ export class ClearingHouseUser {
|
|
|
608
829
|
* @returns positionValue : Precision QUOTE_PRECISION
|
|
609
830
|
*/
|
|
610
831
|
private getTotalPositionValueExcludingMarket(marketToIgnore: BN): BN {
|
|
611
|
-
const currentMarketPosition =
|
|
832
|
+
const currentMarketPosition =
|
|
833
|
+
this.getUserPosition(marketToIgnore) ||
|
|
834
|
+
this.getEmptyPosition(marketToIgnore);
|
|
612
835
|
|
|
613
836
|
let currentMarketPositionValueUSDC = ZERO;
|
|
614
837
|
if (currentMarketPosition) {
|
|
615
|
-
|
|
616
|
-
currentMarketPosition.marketIndex
|
|
617
|
-
);
|
|
618
|
-
currentMarketPositionValueUSDC = calculateBaseAssetValue(
|
|
619
|
-
market,
|
|
620
|
-
currentMarketPosition
|
|
621
|
-
);
|
|
838
|
+
currentMarketPositionValueUSDC = this.getPositionValue(marketToIgnore);
|
|
622
839
|
}
|
|
623
840
|
|
|
624
841
|
return this.getTotalPositionValue().sub(currentMarketPositionValueUSDC);
|
package/src/constants/markets.ts
CHANGED
|
@@ -51,4 +51,11 @@ export const Markets: Market[] = [
|
|
|
51
51
|
devnetPythOracle: 'GwzBgrXb4PG59zjce24SF2b9JXbLEjJJTBkmytuEZj1b',
|
|
52
52
|
mainnetPythOracle: '4CkQJBxhU8EZ2UjhigbtdaPbpTe6mqf811fipYBFbSYN',
|
|
53
53
|
},
|
|
54
|
+
{
|
|
55
|
+
symbol: 'MATIC-PERP',
|
|
56
|
+
baseAssetSymbol: 'MATIC',
|
|
57
|
+
marketIndex: new BN(6),
|
|
58
|
+
devnetPythOracle: 'FBirwuDFuRAu4iSGc7RGxN5koHB7EJM1wbCmyPuQoGur',
|
|
59
|
+
mainnetPythOracle: '7KVswB9vkCgeM3SHP7aGDijvdRAHK8P5wi9JXViCrtYh',
|
|
60
|
+
},
|
|
54
61
|
];
|
|
@@ -19,3 +19,6 @@ export const AMM_TO_QUOTE_PRECISION_RATIO =
|
|
|
19
19
|
AMM_RESERVE_PRECISION.div(QUOTE_PRECISION); // 10^7
|
|
20
20
|
export const PRICE_TO_QUOTE_PRECISION =
|
|
21
21
|
MARK_PRICE_PRECISION.div(QUOTE_PRECISION);
|
|
22
|
+
export const AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO =
|
|
23
|
+
AMM_RESERVE_PRECISION.mul(PEG_PRECISION).div(QUOTE_PRECISION); // 10^10
|
|
24
|
+
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { BN, Provider
|
|
1
|
+
import { BN, Provider } from '@project-serum/anchor';
|
|
2
|
+
import {Wallet} from "..";
|
|
2
3
|
import { Token, TOKEN_PROGRAM_ID } from '@solana/spl-token';
|
|
3
4
|
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
|
|
4
5
|
import {
|