@drift-labs/sdk 2.15.0-beta.0 → 2.16.0-beta.0
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/constants/perpMarkets.js +10 -0
- package/lib/events/fetchLogs.js +4 -4
- package/lib/idl/drift.json +1 -1
- package/lib/math/market.d.ts +1 -0
- package/lib/math/market.js +14 -3
- package/lib/math/spotBalance.d.ts +1 -1
- package/lib/math/spotBalance.js +8 -8
- package/lib/math/spotMarket.d.ts +2 -1
- package/lib/math/spotMarket.js +15 -1
- package/lib/math/spotPosition.js +3 -3
- package/lib/user.d.ts +41 -10
- package/lib/user.js +229 -95
- package/package.json +1 -1
- package/src/constants/perpMarkets.ts +10 -0
- package/src/events/fetchLogs.ts +4 -4
- package/src/idl/drift.json +1 -1
- package/src/math/market.ts +25 -2
- package/src/math/spotBalance.ts +8 -8
- package/src/math/spotMarket.ts +27 -1
- package/src/math/spotPosition.ts +3 -3
- package/src/user.ts +544 -234
package/src/user.ts
CHANGED
|
@@ -45,8 +45,11 @@ import {
|
|
|
45
45
|
BN,
|
|
46
46
|
SpotMarketAccount,
|
|
47
47
|
getTokenValue,
|
|
48
|
+
MarketType,
|
|
48
49
|
getStrictTokenValue,
|
|
50
|
+
calculateSpotMarketMarginRatio,
|
|
49
51
|
getSignedTokenAmount,
|
|
52
|
+
SpotBalanceType,
|
|
50
53
|
} from '.';
|
|
51
54
|
import {
|
|
52
55
|
getTokenAmount,
|
|
@@ -370,7 +373,7 @@ export class User {
|
|
|
370
373
|
* calculates Buying Power = free collateral / initial margin ratio
|
|
371
374
|
* @returns : Precision QUOTE_PRECISION
|
|
372
375
|
*/
|
|
373
|
-
public
|
|
376
|
+
public getPerpBuyingPower(marketIndex: number): BN {
|
|
374
377
|
const perpPosition = this.getPerpPosition(marketIndex);
|
|
375
378
|
const worstCaseBaseAssetAmount = perpPosition
|
|
376
379
|
? calculateWorstCaseBaseAssetAmount(perpPosition)
|
|
@@ -378,14 +381,14 @@ export class User {
|
|
|
378
381
|
|
|
379
382
|
const freeCollateral = this.getFreeCollateral();
|
|
380
383
|
|
|
381
|
-
return this.
|
|
384
|
+
return this.getPerpBuyingPowerFromFreeCollateralAndBaseAssetAmount(
|
|
382
385
|
marketIndex,
|
|
383
386
|
freeCollateral,
|
|
384
387
|
worstCaseBaseAssetAmount
|
|
385
388
|
);
|
|
386
389
|
}
|
|
387
390
|
|
|
388
|
-
|
|
391
|
+
getPerpBuyingPowerFromFreeCollateralAndBaseAssetAmount(
|
|
389
392
|
marketIndex: number,
|
|
390
393
|
freeCollateral: BN,
|
|
391
394
|
baseAssetAmount: BN
|
|
@@ -525,91 +528,88 @@ export class User {
|
|
|
525
528
|
}, ZERO);
|
|
526
529
|
}
|
|
527
530
|
|
|
528
|
-
public
|
|
531
|
+
public getSpotMarketAssetAndLiabilityValue(
|
|
529
532
|
marketIndex?: number,
|
|
530
533
|
marginCategory?: MarginCategory,
|
|
531
534
|
liquidationBuffer?: BN,
|
|
532
535
|
includeOpenOrders?: boolean,
|
|
533
536
|
strict = false,
|
|
534
537
|
now?: BN
|
|
535
|
-
): BN {
|
|
538
|
+
): { totalAssetValue: BN; totalLiabilityValue: BN } {
|
|
536
539
|
now = now || new BN(new Date().getTime() / 1000);
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
540
|
+
let netQuoteValue = ZERO;
|
|
541
|
+
let totalAssetValue = ZERO;
|
|
542
|
+
let totalLiabilityValue = ZERO;
|
|
543
|
+
for (const spotPosition of this.getUserAccount().spotPositions) {
|
|
544
|
+
const countForBase =
|
|
545
|
+
marketIndex === undefined || spotPosition.marketIndex === marketIndex;
|
|
546
|
+
|
|
547
|
+
const countForQuote =
|
|
548
|
+
marketIndex === undefined ||
|
|
549
|
+
marketIndex === QUOTE_SPOT_MARKET_INDEX ||
|
|
550
|
+
(includeOpenOrders && spotPosition.openOrders !== 0);
|
|
551
|
+
if (
|
|
552
|
+
isSpotPositionAvailable(spotPosition) ||
|
|
553
|
+
(!countForBase && !countForQuote)
|
|
554
|
+
) {
|
|
555
|
+
continue;
|
|
556
|
+
}
|
|
546
557
|
|
|
547
|
-
|
|
548
|
-
|
|
558
|
+
const spotMarketAccount: SpotMarketAccount =
|
|
559
|
+
this.driftClient.getSpotMarketAccount(spotPosition.marketIndex);
|
|
549
560
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
561
|
+
if (
|
|
562
|
+
spotPosition.marketIndex === QUOTE_SPOT_MARKET_INDEX &&
|
|
563
|
+
countForQuote
|
|
564
|
+
) {
|
|
565
|
+
if (isVariant(spotPosition.balanceType, 'borrow')) {
|
|
566
|
+
const tokenAmount = getTokenAmount(
|
|
567
|
+
spotPosition.scaledBalance,
|
|
568
|
+
spotMarketAccount,
|
|
569
|
+
spotPosition.balanceType
|
|
570
|
+
);
|
|
557
571
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
const weightedTokenValue = tokenAmount
|
|
567
|
-
.mul(weight)
|
|
568
|
-
.div(SPOT_MARKET_WEIGHT_PRECISION);
|
|
569
|
-
|
|
570
|
-
return totalLiabilityValue.add(weightedTokenValue);
|
|
571
|
-
} else {
|
|
572
|
-
return totalLiabilityValue;
|
|
572
|
+
let weight = SPOT_MARKET_WEIGHT_PRECISION;
|
|
573
|
+
if (marginCategory === 'Initial') {
|
|
574
|
+
weight = BN.max(
|
|
575
|
+
weight,
|
|
576
|
+
new BN(this.getUserAccount().maxMarginRatio)
|
|
577
|
+
);
|
|
573
578
|
}
|
|
574
|
-
}
|
|
575
579
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
580
|
+
const weightedTokenValue = tokenAmount
|
|
581
|
+
.mul(weight)
|
|
582
|
+
.div(SPOT_MARKET_WEIGHT_PRECISION);
|
|
579
583
|
|
|
580
|
-
|
|
581
|
-
if (isVariant(spotPosition.balanceType, 'borrow')) {
|
|
582
|
-
const tokenAmount = getTokenAmount(
|
|
583
|
-
spotPosition.scaledBalance,
|
|
584
|
-
spotMarketAccount,
|
|
585
|
-
spotPosition.balanceType
|
|
586
|
-
);
|
|
587
|
-
const liabilityValue = this.getSpotLiabilityValue(
|
|
588
|
-
tokenAmount,
|
|
589
|
-
oraclePriceData,
|
|
590
|
-
spotMarketAccount,
|
|
591
|
-
marginCategory,
|
|
592
|
-
liquidationBuffer,
|
|
593
|
-
strict,
|
|
594
|
-
now
|
|
595
|
-
);
|
|
596
|
-
return totalLiabilityValue.add(liabilityValue);
|
|
597
|
-
} else {
|
|
598
|
-
return totalLiabilityValue;
|
|
599
|
-
}
|
|
600
|
-
}
|
|
584
|
+
netQuoteValue = netQuoteValue.sub(weightedTokenValue);
|
|
601
585
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
586
|
+
continue;
|
|
587
|
+
} else {
|
|
588
|
+
const tokenAmount = getTokenAmount(
|
|
589
|
+
spotPosition.scaledBalance,
|
|
605
590
|
spotMarketAccount,
|
|
606
|
-
|
|
591
|
+
spotPosition.balanceType
|
|
607
592
|
);
|
|
608
593
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
594
|
+
netQuoteValue = netQuoteValue.add(tokenAmount);
|
|
595
|
+
|
|
596
|
+
continue;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
const oraclePriceData = this.getOracleDataForSpotMarket(
|
|
601
|
+
spotPosition.marketIndex
|
|
602
|
+
);
|
|
603
|
+
|
|
604
|
+
if (!includeOpenOrders && countForBase) {
|
|
605
|
+
if (isVariant(spotPosition.balanceType, 'borrow')) {
|
|
606
|
+
const tokenAmount = getTokenAmount(
|
|
607
|
+
spotPosition.scaledBalance,
|
|
608
|
+
spotMarketAccount,
|
|
609
|
+
spotPosition.balanceType
|
|
610
|
+
);
|
|
611
|
+
const liabilityValue = this.getSpotLiabilityValue(
|
|
612
|
+
tokenAmount,
|
|
613
613
|
oraclePriceData,
|
|
614
614
|
spotMarketAccount,
|
|
615
615
|
marginCategory,
|
|
@@ -617,37 +617,112 @@ export class User {
|
|
|
617
617
|
strict,
|
|
618
618
|
now
|
|
619
619
|
);
|
|
620
|
+
totalLiabilityValue = totalLiabilityValue.add(liabilityValue);
|
|
621
|
+
|
|
622
|
+
continue;
|
|
623
|
+
} else {
|
|
624
|
+
const tokenAmount = getTokenAmount(
|
|
625
|
+
spotPosition.scaledBalance,
|
|
626
|
+
spotMarketAccount,
|
|
627
|
+
spotPosition.balanceType
|
|
628
|
+
);
|
|
629
|
+
const assetValue = this.getSpotAssetValue(
|
|
630
|
+
tokenAmount,
|
|
631
|
+
oraclePriceData,
|
|
632
|
+
spotMarketAccount,
|
|
633
|
+
marginCategory,
|
|
634
|
+
strict,
|
|
635
|
+
now
|
|
636
|
+
);
|
|
637
|
+
totalAssetValue = totalAssetValue.add(assetValue);
|
|
620
638
|
|
|
621
|
-
|
|
622
|
-
newTotalLiabilityValue.add(baseLiabilityValue);
|
|
639
|
+
continue;
|
|
623
640
|
}
|
|
641
|
+
}
|
|
624
642
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
);
|
|
632
|
-
}
|
|
643
|
+
const [worstCaseTokenAmount, worstCaseQuoteTokenAmount] =
|
|
644
|
+
getWorstCaseTokenAmounts(
|
|
645
|
+
spotPosition,
|
|
646
|
+
spotMarketAccount,
|
|
647
|
+
this.getOracleDataForSpotMarket(spotPosition.marketIndex)
|
|
648
|
+
);
|
|
633
649
|
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
650
|
+
if (worstCaseTokenAmount.gt(ZERO) && countForBase) {
|
|
651
|
+
const baseAssetValue = this.getSpotAssetValue(
|
|
652
|
+
worstCaseTokenAmount,
|
|
653
|
+
oraclePriceData,
|
|
654
|
+
spotMarketAccount,
|
|
655
|
+
marginCategory,
|
|
656
|
+
strict,
|
|
657
|
+
now
|
|
658
|
+
);
|
|
638
659
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
}
|
|
660
|
+
totalAssetValue = totalAssetValue.add(baseAssetValue);
|
|
661
|
+
}
|
|
642
662
|
|
|
643
|
-
|
|
644
|
-
|
|
663
|
+
if (worstCaseTokenAmount.lt(ZERO) && countForBase) {
|
|
664
|
+
const baseLiabilityValue = this.getSpotLiabilityValue(
|
|
665
|
+
worstCaseTokenAmount.abs(),
|
|
666
|
+
oraclePriceData,
|
|
667
|
+
spotMarketAccount,
|
|
668
|
+
marginCategory,
|
|
669
|
+
liquidationBuffer,
|
|
670
|
+
strict,
|
|
671
|
+
now
|
|
645
672
|
);
|
|
646
673
|
|
|
647
|
-
|
|
648
|
-
}
|
|
649
|
-
|
|
674
|
+
totalLiabilityValue = totalLiabilityValue.add(baseLiabilityValue);
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
if (worstCaseQuoteTokenAmount.gt(ZERO) && countForQuote) {
|
|
678
|
+
netQuoteValue = netQuoteValue.add(worstCaseQuoteTokenAmount);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
if (worstCaseQuoteTokenAmount.lt(ZERO) && countForQuote) {
|
|
682
|
+
let weight = SPOT_MARKET_WEIGHT_PRECISION;
|
|
683
|
+
if (marginCategory === 'Initial') {
|
|
684
|
+
weight = BN.max(weight, new BN(this.getUserAccount().maxMarginRatio));
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
const weightedTokenValue = worstCaseQuoteTokenAmount
|
|
688
|
+
.abs()
|
|
689
|
+
.mul(weight)
|
|
690
|
+
.div(SPOT_MARKET_WEIGHT_PRECISION);
|
|
691
|
+
|
|
692
|
+
netQuoteValue = netQuoteValue.sub(weightedTokenValue);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
totalLiabilityValue = totalLiabilityValue.add(
|
|
696
|
+
new BN(spotPosition.openOrders).mul(OPEN_ORDER_MARGIN_REQUIREMENT)
|
|
697
|
+
);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
if (netQuoteValue.gt(ZERO)) {
|
|
701
|
+
totalAssetValue = totalAssetValue.add(netQuoteValue);
|
|
702
|
+
} else {
|
|
703
|
+
totalLiabilityValue = totalLiabilityValue.add(netQuoteValue.abs());
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
return { totalAssetValue, totalLiabilityValue };
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
public getSpotMarketLiabilityValue(
|
|
710
|
+
marketIndex?: number,
|
|
711
|
+
marginCategory?: MarginCategory,
|
|
712
|
+
liquidationBuffer?: BN,
|
|
713
|
+
includeOpenOrders?: boolean,
|
|
714
|
+
strict = false,
|
|
715
|
+
now?: BN
|
|
716
|
+
): BN {
|
|
717
|
+
const { totalLiabilityValue } = this.getSpotMarketAssetAndLiabilityValue(
|
|
718
|
+
marketIndex,
|
|
719
|
+
marginCategory,
|
|
720
|
+
liquidationBuffer,
|
|
721
|
+
includeOpenOrders,
|
|
722
|
+
strict,
|
|
723
|
+
now
|
|
650
724
|
);
|
|
725
|
+
return totalLiabilityValue;
|
|
651
726
|
}
|
|
652
727
|
|
|
653
728
|
getSpotLiabilityValue(
|
|
@@ -712,91 +787,15 @@ export class User {
|
|
|
712
787
|
strict = false,
|
|
713
788
|
now?: BN
|
|
714
789
|
): BN {
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
) {
|
|
723
|
-
return totalAssetValue;
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
// Todo this needs to account for whether it's based on initial or maintenance requirements
|
|
727
|
-
const spotMarketAccount: SpotMarketAccount =
|
|
728
|
-
this.driftClient.getSpotMarketAccount(spotPosition.marketIndex);
|
|
729
|
-
|
|
730
|
-
if (spotPosition.marketIndex === QUOTE_SPOT_MARKET_INDEX) {
|
|
731
|
-
if (isVariant(spotPosition.balanceType, 'deposit')) {
|
|
732
|
-
const tokenAmount = getTokenAmount(
|
|
733
|
-
spotPosition.scaledBalance,
|
|
734
|
-
spotMarketAccount,
|
|
735
|
-
spotPosition.balanceType
|
|
736
|
-
);
|
|
737
|
-
|
|
738
|
-
return totalAssetValue.add(tokenAmount);
|
|
739
|
-
} else {
|
|
740
|
-
return totalAssetValue;
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
const oraclePriceData = this.getOracleDataForSpotMarket(
|
|
745
|
-
spotPosition.marketIndex
|
|
746
|
-
);
|
|
747
|
-
|
|
748
|
-
if (!includeOpenOrders) {
|
|
749
|
-
if (isVariant(spotPosition.balanceType, 'deposit')) {
|
|
750
|
-
const tokenAmount = getTokenAmount(
|
|
751
|
-
spotPosition.scaledBalance,
|
|
752
|
-
spotMarketAccount,
|
|
753
|
-
spotPosition.balanceType
|
|
754
|
-
);
|
|
755
|
-
const assetValue = this.getSpotAssetValue(
|
|
756
|
-
tokenAmount,
|
|
757
|
-
oraclePriceData,
|
|
758
|
-
spotMarketAccount,
|
|
759
|
-
marginCategory,
|
|
760
|
-
strict,
|
|
761
|
-
now
|
|
762
|
-
);
|
|
763
|
-
return totalAssetValue.add(assetValue);
|
|
764
|
-
} else {
|
|
765
|
-
return totalAssetValue;
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
const [worstCaseTokenAmount, worstCaseQuoteTokenAmount] =
|
|
770
|
-
getWorstCaseTokenAmounts(
|
|
771
|
-
spotPosition,
|
|
772
|
-
spotMarketAccount,
|
|
773
|
-
this.getOracleDataForSpotMarket(spotPosition.marketIndex)
|
|
774
|
-
);
|
|
775
|
-
|
|
776
|
-
let newTotalAssetValue = totalAssetValue;
|
|
777
|
-
if (worstCaseTokenAmount.gt(ZERO)) {
|
|
778
|
-
const baseAssetValue = this.getSpotAssetValue(
|
|
779
|
-
worstCaseTokenAmount,
|
|
780
|
-
oraclePriceData,
|
|
781
|
-
spotMarketAccount,
|
|
782
|
-
marginCategory,
|
|
783
|
-
strict,
|
|
784
|
-
now
|
|
785
|
-
);
|
|
786
|
-
|
|
787
|
-
newTotalAssetValue = newTotalAssetValue.add(baseAssetValue);
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
if (worstCaseQuoteTokenAmount.gt(ZERO)) {
|
|
791
|
-
newTotalAssetValue = newTotalAssetValue.add(
|
|
792
|
-
worstCaseQuoteTokenAmount
|
|
793
|
-
);
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
return newTotalAssetValue;
|
|
797
|
-
},
|
|
798
|
-
ZERO
|
|
790
|
+
const { totalAssetValue } = this.getSpotMarketAssetAndLiabilityValue(
|
|
791
|
+
marketIndex,
|
|
792
|
+
marginCategory,
|
|
793
|
+
undefined,
|
|
794
|
+
includeOpenOrders,
|
|
795
|
+
strict,
|
|
796
|
+
now
|
|
799
797
|
);
|
|
798
|
+
return totalAssetValue;
|
|
800
799
|
}
|
|
801
800
|
|
|
802
801
|
getSpotAssetValue(
|
|
@@ -842,15 +841,45 @@ export class User {
|
|
|
842
841
|
return assetValue;
|
|
843
842
|
}
|
|
844
843
|
|
|
845
|
-
public
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
844
|
+
public getSpotTokenAmount(marketIndex: number): BN {
|
|
845
|
+
const spotPosition = this.getSpotPosition(marketIndex);
|
|
846
|
+
return getTokenAmount(
|
|
847
|
+
spotPosition.scaledBalance,
|
|
848
|
+
this.driftClient.getSpotMarketAccount(marketIndex),
|
|
849
|
+
spotPosition.balanceType
|
|
851
850
|
);
|
|
852
851
|
}
|
|
853
852
|
|
|
853
|
+
public getSpotPositionValue(
|
|
854
|
+
marketIndex: number,
|
|
855
|
+
marginCategory?: MarginCategory,
|
|
856
|
+
includeOpenOrders?: boolean,
|
|
857
|
+
strict = false,
|
|
858
|
+
now?: BN
|
|
859
|
+
): BN {
|
|
860
|
+
const { totalAssetValue, totalLiabilityValue } =
|
|
861
|
+
this.getSpotMarketAssetAndLiabilityValue(
|
|
862
|
+
marketIndex,
|
|
863
|
+
marginCategory,
|
|
864
|
+
undefined,
|
|
865
|
+
includeOpenOrders,
|
|
866
|
+
strict,
|
|
867
|
+
now
|
|
868
|
+
);
|
|
869
|
+
|
|
870
|
+
return totalAssetValue.sub(totalLiabilityValue);
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
public getNetSpotMarketValue(withWeightMarginCategory?: MarginCategory): BN {
|
|
874
|
+
const { totalAssetValue, totalLiabilityValue } =
|
|
875
|
+
this.getSpotMarketAssetAndLiabilityValue(
|
|
876
|
+
undefined,
|
|
877
|
+
withWeightMarginCategory
|
|
878
|
+
);
|
|
879
|
+
|
|
880
|
+
return totalAssetValue.sub(totalLiabilityValue);
|
|
881
|
+
}
|
|
882
|
+
|
|
854
883
|
/**
|
|
855
884
|
* calculates TotalCollateral: collateral + unrealized pnl
|
|
856
885
|
* @returns : Precision QUOTE_PRECISION
|
|
@@ -1098,28 +1127,50 @@ export class User {
|
|
|
1098
1127
|
* @returns : Precision TEN_THOUSAND
|
|
1099
1128
|
*/
|
|
1100
1129
|
public getLeverage(): BN {
|
|
1101
|
-
|
|
1130
|
+
// get leverage components
|
|
1131
|
+
const { perpLiabilityValue, perpPnl, spotAssetValue, spotLiabilityValue } =
|
|
1132
|
+
this.getLeverageComponents();
|
|
1133
|
+
|
|
1134
|
+
const totalLiabilityValue = perpLiabilityValue.add(spotLiabilityValue);
|
|
1135
|
+
const totalAssetValue = spotAssetValue.add(perpPnl);
|
|
1136
|
+
const netAssetValue = totalAssetValue.sub(spotLiabilityValue);
|
|
1137
|
+
|
|
1138
|
+
if (netAssetValue.eq(ZERO)) {
|
|
1139
|
+
return ZERO;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
return totalLiabilityValue.mul(TEN_THOUSAND).div(netAssetValue);
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
getLeverageComponents(): {
|
|
1146
|
+
perpLiabilityValue: BN;
|
|
1147
|
+
perpPnl: BN;
|
|
1148
|
+
spotAssetValue: BN;
|
|
1149
|
+
spotLiabilityValue: BN;
|
|
1150
|
+
} {
|
|
1151
|
+
const perpLiability = this.getTotalPerpPositionValue(
|
|
1102
1152
|
undefined,
|
|
1103
1153
|
undefined,
|
|
1104
1154
|
true
|
|
1105
1155
|
);
|
|
1106
|
-
const
|
|
1156
|
+
const perpPnl = this.getUnrealizedPNL(true);
|
|
1157
|
+
|
|
1158
|
+
const {
|
|
1159
|
+
totalAssetValue: spotAssetValue,
|
|
1160
|
+
totalLiabilityValue: spotLiabilityValue,
|
|
1161
|
+
} = this.getSpotMarketAssetAndLiabilityValue(
|
|
1107
1162
|
undefined,
|
|
1108
1163
|
undefined,
|
|
1109
1164
|
undefined,
|
|
1110
1165
|
true
|
|
1111
1166
|
);
|
|
1112
1167
|
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
return ZERO;
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
return totalLiabilityValue.mul(TEN_THOUSAND).div(netAssetValue);
|
|
1168
|
+
return {
|
|
1169
|
+
perpLiabilityValue: perpLiability,
|
|
1170
|
+
perpPnl,
|
|
1171
|
+
spotAssetValue,
|
|
1172
|
+
spotLiabilityValue,
|
|
1173
|
+
};
|
|
1123
1174
|
}
|
|
1124
1175
|
|
|
1125
1176
|
getTotalLiabilityValue(marginCategory?: MarginCategory): BN {
|
|
@@ -1144,37 +1195,27 @@ export class User {
|
|
|
1144
1195
|
* @params category {Initial, Maintenance}
|
|
1145
1196
|
* @returns : Precision TEN_THOUSAND
|
|
1146
1197
|
*/
|
|
1147
|
-
public
|
|
1148
|
-
|
|
1198
|
+
public getMaxLeverageForPerp(
|
|
1199
|
+
perpMarketIndex: number,
|
|
1149
1200
|
category: MarginCategory = 'Initial'
|
|
1150
1201
|
): BN {
|
|
1151
|
-
const market = this.driftClient.getPerpMarketAccount(
|
|
1202
|
+
const market = this.driftClient.getPerpMarketAccount(perpMarketIndex);
|
|
1152
1203
|
|
|
1153
|
-
const
|
|
1154
|
-
|
|
1155
|
-
undefined,
|
|
1156
|
-
true
|
|
1157
|
-
);
|
|
1158
|
-
const totalSpotLiability = this.getSpotMarketLiabilityValue(
|
|
1159
|
-
undefined,
|
|
1160
|
-
undefined,
|
|
1161
|
-
undefined,
|
|
1162
|
-
true
|
|
1163
|
-
);
|
|
1204
|
+
const { perpLiabilityValue, perpPnl, spotAssetValue, spotLiabilityValue } =
|
|
1205
|
+
this.getLeverageComponents();
|
|
1164
1206
|
|
|
1165
|
-
const totalAssetValue =
|
|
1207
|
+
const totalAssetValue = spotAssetValue.add(perpPnl);
|
|
1166
1208
|
|
|
1167
|
-
const netAssetValue = totalAssetValue.sub(
|
|
1209
|
+
const netAssetValue = totalAssetValue.sub(spotLiabilityValue);
|
|
1168
1210
|
|
|
1169
1211
|
if (netAssetValue.eq(ZERO)) {
|
|
1170
1212
|
return ZERO;
|
|
1171
1213
|
}
|
|
1172
1214
|
|
|
1173
|
-
const totalLiabilityValue =
|
|
1215
|
+
const totalLiabilityValue = perpLiabilityValue.add(spotLiabilityValue);
|
|
1174
1216
|
|
|
1175
1217
|
const marginRatio = calculateMarketMarginRatio(
|
|
1176
1218
|
market,
|
|
1177
|
-
// worstCaseBaseAssetAmount.abs(),
|
|
1178
1219
|
ZERO, // todo
|
|
1179
1220
|
category
|
|
1180
1221
|
);
|
|
@@ -1192,30 +1233,113 @@ export class User {
|
|
|
1192
1233
|
}
|
|
1193
1234
|
|
|
1194
1235
|
/**
|
|
1195
|
-
* calculates
|
|
1236
|
+
* calculates max allowable leverage exceeding hitting requirement category
|
|
1237
|
+
* @param spotMarketIndex
|
|
1238
|
+
* @param direction
|
|
1196
1239
|
* @returns : Precision TEN_THOUSAND
|
|
1197
1240
|
*/
|
|
1198
|
-
public
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1241
|
+
public getMaxLeverageForSpot(
|
|
1242
|
+
spotMarketIndex: number,
|
|
1243
|
+
direction: PositionDirection
|
|
1244
|
+
): BN {
|
|
1245
|
+
const { perpLiabilityValue, perpPnl, spotAssetValue, spotLiabilityValue } =
|
|
1246
|
+
this.getLeverageComponents();
|
|
1247
|
+
|
|
1248
|
+
const totalLiabilityValue = perpLiabilityValue.add(spotLiabilityValue);
|
|
1249
|
+
const totalAssetValue = spotAssetValue.add(perpPnl);
|
|
1250
|
+
|
|
1251
|
+
const netAssetValue = totalAssetValue.sub(spotLiabilityValue);
|
|
1252
|
+
|
|
1253
|
+
if (netAssetValue.eq(ZERO)) {
|
|
1254
|
+
return ZERO;
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
const currentQuoteAssetValue = this.getSpotMarketAssetValue(
|
|
1258
|
+
QUOTE_SPOT_MARKET_INDEX
|
|
1203
1259
|
);
|
|
1204
|
-
const
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1260
|
+
const currentQuoteLiabilityValue = this.getSpotMarketLiabilityValue(
|
|
1261
|
+
QUOTE_SPOT_MARKET_INDEX
|
|
1262
|
+
);
|
|
1263
|
+
const currentQuoteValue = currentQuoteAssetValue.sub(
|
|
1264
|
+
currentQuoteLiabilityValue
|
|
1265
|
+
);
|
|
1266
|
+
|
|
1267
|
+
const currentSpotMarketAssetValue =
|
|
1268
|
+
this.getSpotMarketAssetValue(spotMarketIndex);
|
|
1269
|
+
const currentSpotMarketLiabilityValue =
|
|
1270
|
+
this.getSpotMarketLiabilityValue(spotMarketIndex);
|
|
1271
|
+
const currentSpotMarketNetValue = currentSpotMarketAssetValue.sub(
|
|
1272
|
+
currentSpotMarketLiabilityValue
|
|
1273
|
+
);
|
|
1274
|
+
|
|
1275
|
+
const tradeQuoteAmount = this.getMaxTradeSizeUSDCForSpot(
|
|
1276
|
+
spotMarketIndex,
|
|
1277
|
+
direction,
|
|
1278
|
+
currentQuoteAssetValue,
|
|
1279
|
+
currentSpotMarketNetValue
|
|
1209
1280
|
);
|
|
1210
1281
|
|
|
1211
|
-
|
|
1282
|
+
let assetValueToAdd = ZERO;
|
|
1283
|
+
let liabilityValueToAdd = ZERO;
|
|
1284
|
+
|
|
1285
|
+
const newQuoteNetValue = isVariant(direction, 'short')
|
|
1286
|
+
? currentQuoteValue.add(tradeQuoteAmount)
|
|
1287
|
+
: currentQuoteValue.sub(tradeQuoteAmount);
|
|
1288
|
+
const newQuoteAssetValue = BN.max(newQuoteNetValue, ZERO);
|
|
1289
|
+
const newQuoteLiabilityValue = BN.min(newQuoteNetValue, ZERO).abs();
|
|
1290
|
+
|
|
1291
|
+
assetValueToAdd = assetValueToAdd.add(
|
|
1292
|
+
newQuoteAssetValue.sub(currentQuoteAssetValue)
|
|
1293
|
+
);
|
|
1294
|
+
liabilityValueToAdd = liabilityValueToAdd.add(
|
|
1295
|
+
newQuoteLiabilityValue.sub(currentQuoteLiabilityValue)
|
|
1296
|
+
);
|
|
1297
|
+
|
|
1298
|
+
const newSpotMarketNetValue = isVariant(direction, 'long')
|
|
1299
|
+
? currentSpotMarketNetValue.add(tradeQuoteAmount)
|
|
1300
|
+
: currentSpotMarketNetValue.sub(tradeQuoteAmount);
|
|
1301
|
+
const newSpotMarketAssetValue = BN.max(newSpotMarketNetValue, ZERO);
|
|
1302
|
+
const newSpotMarketLiabilityValue = BN.min(
|
|
1303
|
+
newSpotMarketNetValue,
|
|
1304
|
+
ZERO
|
|
1305
|
+
).abs();
|
|
1306
|
+
|
|
1307
|
+
assetValueToAdd = assetValueToAdd.add(
|
|
1308
|
+
newSpotMarketAssetValue.sub(currentSpotMarketAssetValue)
|
|
1309
|
+
);
|
|
1310
|
+
liabilityValueToAdd = liabilityValueToAdd.add(
|
|
1311
|
+
newSpotMarketLiabilityValue.sub(currentSpotMarketLiabilityValue)
|
|
1312
|
+
);
|
|
1313
|
+
|
|
1314
|
+
const finalTotalAssetValue = totalAssetValue.add(assetValueToAdd);
|
|
1315
|
+
const finalTotalSpotLiability = spotLiabilityValue.add(liabilityValueToAdd);
|
|
1316
|
+
|
|
1317
|
+
const finalTotalLiabilityValue =
|
|
1318
|
+
totalLiabilityValue.add(liabilityValueToAdd);
|
|
1319
|
+
|
|
1320
|
+
const finalNetAssetValue = finalTotalAssetValue.sub(
|
|
1321
|
+
finalTotalSpotLiability
|
|
1322
|
+
);
|
|
1323
|
+
|
|
1324
|
+
return finalTotalLiabilityValue.mul(TEN_THOUSAND).div(finalNetAssetValue);
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
/**
|
|
1328
|
+
* calculates margin ratio: 1 / leverage
|
|
1329
|
+
* @returns : Precision TEN_THOUSAND
|
|
1330
|
+
*/
|
|
1331
|
+
public getMarginRatio(): BN {
|
|
1332
|
+
const { perpLiabilityValue, perpPnl, spotAssetValue, spotLiabilityValue } =
|
|
1333
|
+
this.getLeverageComponents();
|
|
1334
|
+
|
|
1335
|
+
const totalLiabilityValue = perpLiabilityValue.add(spotLiabilityValue);
|
|
1336
|
+
const totalAssetValue = spotAssetValue.add(perpPnl);
|
|
1212
1337
|
|
|
1213
1338
|
if (totalLiabilityValue.eq(ZERO)) {
|
|
1214
1339
|
return BN_MAX;
|
|
1215
1340
|
}
|
|
1216
1341
|
|
|
1217
|
-
const
|
|
1218
|
-
const netAssetValue = totalAssetValue.sub(totalSpotLiability);
|
|
1342
|
+
const netAssetValue = totalAssetValue.sub(spotLiabilityValue);
|
|
1219
1343
|
|
|
1220
1344
|
return netAssetValue.mul(TEN_THOUSAND).div(totalLiabilityValue);
|
|
1221
1345
|
}
|
|
@@ -1285,7 +1409,10 @@ export class User {
|
|
|
1285
1409
|
* @param marketIndex
|
|
1286
1410
|
* @returns Precision : PRICE_PRECISION
|
|
1287
1411
|
*/
|
|
1288
|
-
public spotLiquidationPrice(
|
|
1412
|
+
public spotLiquidationPrice(
|
|
1413
|
+
marketIndex: number,
|
|
1414
|
+
positionBaseSizeChange: BN = ZERO
|
|
1415
|
+
): BN {
|
|
1289
1416
|
const currentSpotPosition = this.getSpotPosition(marketIndex);
|
|
1290
1417
|
|
|
1291
1418
|
if (!currentSpotPosition) {
|
|
@@ -1300,7 +1427,7 @@ export class User {
|
|
|
1300
1427
|
);
|
|
1301
1428
|
|
|
1302
1429
|
const market = this.driftClient.getSpotMarketAccount(marketIndex);
|
|
1303
|
-
|
|
1430
|
+
let signedTokenAmount = getSignedTokenAmount(
|
|
1304
1431
|
getTokenAmount(
|
|
1305
1432
|
currentSpotPosition.scaledBalance,
|
|
1306
1433
|
market,
|
|
@@ -1308,6 +1435,7 @@ export class User {
|
|
|
1308
1435
|
),
|
|
1309
1436
|
currentSpotPosition.balanceType
|
|
1310
1437
|
);
|
|
1438
|
+
signedTokenAmount = signedTokenAmount.add(positionBaseSizeChange);
|
|
1311
1439
|
|
|
1312
1440
|
if (signedTokenAmount.eq(ZERO)) {
|
|
1313
1441
|
return new BN(-1);
|
|
@@ -1570,7 +1698,7 @@ export class User {
|
|
|
1570
1698
|
* @param tradeSide
|
|
1571
1699
|
* @returns tradeSizeAllowed : Precision QUOTE_PRECISION
|
|
1572
1700
|
*/
|
|
1573
|
-
public
|
|
1701
|
+
public getMaxTradeSizeUSDCForPerp(
|
|
1574
1702
|
targetMarketIndex: number,
|
|
1575
1703
|
tradeSide: PositionDirection
|
|
1576
1704
|
): BN {
|
|
@@ -1595,7 +1723,7 @@ export class User {
|
|
|
1595
1723
|
? ZERO
|
|
1596
1724
|
: this.getPerpPositionValue(targetMarketIndex, oracleData);
|
|
1597
1725
|
|
|
1598
|
-
let maxPositionSize = this.
|
|
1726
|
+
let maxPositionSize = this.getPerpBuyingPower(targetMarketIndex);
|
|
1599
1727
|
if (maxPositionSize.gte(ZERO)) {
|
|
1600
1728
|
if (oppositeSizeValueUSDC.eq(ZERO)) {
|
|
1601
1729
|
// case 1 : Regular trade where current total position less than max, and no opposite position to account for
|
|
@@ -1629,8 +1757,9 @@ export class User {
|
|
|
1629
1757
|
const freeCollateralAfterClose = totalCollateral.sub(
|
|
1630
1758
|
marginRequirementAfterClosing
|
|
1631
1759
|
);
|
|
1760
|
+
|
|
1632
1761
|
const buyingPowerAfterClose =
|
|
1633
|
-
this.
|
|
1762
|
+
this.getPerpBuyingPowerFromFreeCollateralAndBaseAssetAmount(
|
|
1634
1763
|
targetMarketIndex,
|
|
1635
1764
|
freeCollateralAfterClose,
|
|
1636
1765
|
ZERO
|
|
@@ -1648,21 +1777,202 @@ export class User {
|
|
|
1648
1777
|
return maxPositionSize.sub(oneMilli);
|
|
1649
1778
|
}
|
|
1650
1779
|
|
|
1780
|
+
/**
|
|
1781
|
+
* Get the maximum trade size for a given market, taking into account the user's current leverage, positions, collateral, etc.
|
|
1782
|
+
*
|
|
1783
|
+
* @param targetMarketIndex
|
|
1784
|
+
* @param direction
|
|
1785
|
+
* @param currentQuoteAssetValue
|
|
1786
|
+
* @param currentSpotMarketNetValue
|
|
1787
|
+
* @returns tradeSizeAllowed : Precision QUOTE_PRECISION
|
|
1788
|
+
*/
|
|
1789
|
+
public getMaxTradeSizeUSDCForSpot(
|
|
1790
|
+
targetMarketIndex: number,
|
|
1791
|
+
direction: PositionDirection,
|
|
1792
|
+
currentQuoteAssetValue?: BN,
|
|
1793
|
+
currentSpotMarketNetValue?: BN
|
|
1794
|
+
): BN {
|
|
1795
|
+
const market = this.driftClient.getSpotMarketAccount(targetMarketIndex);
|
|
1796
|
+
|
|
1797
|
+
currentQuoteAssetValue = this.getSpotMarketAssetValue(
|
|
1798
|
+
QUOTE_SPOT_MARKET_INDEX
|
|
1799
|
+
);
|
|
1800
|
+
|
|
1801
|
+
currentSpotMarketNetValue =
|
|
1802
|
+
currentSpotMarketNetValue ?? this.getSpotPositionValue(targetMarketIndex);
|
|
1803
|
+
|
|
1804
|
+
let freeCollateral = this.getFreeCollateral();
|
|
1805
|
+
const marginRatio = calculateSpotMarketMarginRatio(
|
|
1806
|
+
market,
|
|
1807
|
+
'Initial',
|
|
1808
|
+
ZERO,
|
|
1809
|
+
isVariant(direction, 'long')
|
|
1810
|
+
? SpotBalanceType.DEPOSIT
|
|
1811
|
+
: SpotBalanceType.BORROW
|
|
1812
|
+
);
|
|
1813
|
+
|
|
1814
|
+
let tradeAmount = ZERO;
|
|
1815
|
+
if (this.getUserAccount().isMarginTradingEnabled) {
|
|
1816
|
+
// if the user is buying/selling and already short/long, need to account for closing out short/long
|
|
1817
|
+
if (isVariant(direction, 'long') && currentSpotMarketNetValue.lt(ZERO)) {
|
|
1818
|
+
tradeAmount = currentSpotMarketNetValue.abs();
|
|
1819
|
+
const marginRatio = calculateSpotMarketMarginRatio(
|
|
1820
|
+
market,
|
|
1821
|
+
'Initial',
|
|
1822
|
+
this.getSpotTokenAmount(targetMarketIndex),
|
|
1823
|
+
SpotBalanceType.BORROW
|
|
1824
|
+
);
|
|
1825
|
+
freeCollateral = freeCollateral.add(
|
|
1826
|
+
tradeAmount.mul(new BN(marginRatio)).div(MARGIN_PRECISION)
|
|
1827
|
+
);
|
|
1828
|
+
} else if (
|
|
1829
|
+
isVariant(direction, 'short') &&
|
|
1830
|
+
currentSpotMarketNetValue.gt(ZERO)
|
|
1831
|
+
) {
|
|
1832
|
+
tradeAmount = currentSpotMarketNetValue;
|
|
1833
|
+
const marginRatio = calculateSpotMarketMarginRatio(
|
|
1834
|
+
market,
|
|
1835
|
+
'Initial',
|
|
1836
|
+
this.getSpotTokenAmount(targetMarketIndex),
|
|
1837
|
+
SpotBalanceType.DEPOSIT
|
|
1838
|
+
);
|
|
1839
|
+
freeCollateral = freeCollateral.add(
|
|
1840
|
+
tradeAmount.mul(new BN(marginRatio)).div(MARGIN_PRECISION)
|
|
1841
|
+
);
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
tradeAmount = tradeAmount.add(
|
|
1845
|
+
freeCollateral.mul(MARGIN_PRECISION).div(new BN(marginRatio))
|
|
1846
|
+
);
|
|
1847
|
+
} else if (isVariant(direction, 'long')) {
|
|
1848
|
+
tradeAmount = BN.min(
|
|
1849
|
+
currentQuoteAssetValue,
|
|
1850
|
+
freeCollateral.mul(MARGIN_PRECISION).div(new BN(marginRatio))
|
|
1851
|
+
);
|
|
1852
|
+
} else {
|
|
1853
|
+
tradeAmount = BN.max(ZERO, currentSpotMarketNetValue);
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
return tradeAmount;
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1651
1859
|
// TODO - should this take the price impact of the trade into account for strict accuracy?
|
|
1652
1860
|
|
|
1653
1861
|
/**
|
|
1654
1862
|
* Returns the leverage ratio for the account after adding (or subtracting) the given quote size to the given position
|
|
1655
1863
|
* @param targetMarketIndex
|
|
1656
|
-
* @param
|
|
1864
|
+
* @param: targetMarketType
|
|
1657
1865
|
* @param tradeQuoteAmount
|
|
1866
|
+
* @param tradeSide
|
|
1867
|
+
* @param includeOpenOrders
|
|
1658
1868
|
* @returns leverageRatio : Precision TEN_THOUSAND
|
|
1659
1869
|
*/
|
|
1660
1870
|
public accountLeverageRatioAfterTrade(
|
|
1661
1871
|
targetMarketIndex: number,
|
|
1872
|
+
targetMarketType: MarketType,
|
|
1662
1873
|
tradeQuoteAmount: BN,
|
|
1663
1874
|
tradeSide: PositionDirection,
|
|
1664
1875
|
includeOpenOrders = true
|
|
1665
1876
|
): BN {
|
|
1877
|
+
const tradeIsPerp = isVariant(targetMarketType, 'perp');
|
|
1878
|
+
|
|
1879
|
+
if (!tradeIsPerp) {
|
|
1880
|
+
// calculate new asset/liability values for base and quote market to find new account leverage
|
|
1881
|
+
const totalLiabilityValue = this.getTotalLiabilityValue();
|
|
1882
|
+
const totalAssetValue = this.getTotalAssetValue();
|
|
1883
|
+
const spotLiabilityValue = this.getSpotMarketLiabilityValue(
|
|
1884
|
+
undefined,
|
|
1885
|
+
undefined,
|
|
1886
|
+
undefined,
|
|
1887
|
+
includeOpenOrders
|
|
1888
|
+
);
|
|
1889
|
+
|
|
1890
|
+
const currentQuoteAssetValue = this.getSpotMarketAssetValue(
|
|
1891
|
+
QUOTE_SPOT_MARKET_INDEX,
|
|
1892
|
+
undefined,
|
|
1893
|
+
includeOpenOrders
|
|
1894
|
+
);
|
|
1895
|
+
const currentQuoteLiabilityValue = this.getSpotMarketLiabilityValue(
|
|
1896
|
+
QUOTE_SPOT_MARKET_INDEX,
|
|
1897
|
+
undefined,
|
|
1898
|
+
undefined,
|
|
1899
|
+
includeOpenOrders
|
|
1900
|
+
);
|
|
1901
|
+
const currentQuoteValue = currentQuoteAssetValue.sub(
|
|
1902
|
+
currentQuoteLiabilityValue
|
|
1903
|
+
);
|
|
1904
|
+
|
|
1905
|
+
const currentSpotMarketAssetValue = this.getSpotMarketAssetValue(
|
|
1906
|
+
targetMarketIndex,
|
|
1907
|
+
undefined,
|
|
1908
|
+
includeOpenOrders
|
|
1909
|
+
);
|
|
1910
|
+
const currentSpotMarketLiabilityValue = this.getSpotMarketLiabilityValue(
|
|
1911
|
+
targetMarketIndex,
|
|
1912
|
+
undefined,
|
|
1913
|
+
undefined,
|
|
1914
|
+
includeOpenOrders
|
|
1915
|
+
);
|
|
1916
|
+
const currentSpotMarketNetValue = currentSpotMarketAssetValue.sub(
|
|
1917
|
+
currentSpotMarketLiabilityValue
|
|
1918
|
+
);
|
|
1919
|
+
|
|
1920
|
+
let assetValueToAdd = ZERO;
|
|
1921
|
+
let liabilityValueToAdd = ZERO;
|
|
1922
|
+
|
|
1923
|
+
const newQuoteNetValue =
|
|
1924
|
+
tradeSide == PositionDirection.SHORT
|
|
1925
|
+
? currentQuoteValue.add(tradeQuoteAmount)
|
|
1926
|
+
: currentQuoteValue.sub(tradeQuoteAmount);
|
|
1927
|
+
const newQuoteAssetValue = BN.max(newQuoteNetValue, ZERO);
|
|
1928
|
+
const newQuoteLiabilityValue = BN.min(newQuoteNetValue, ZERO).abs();
|
|
1929
|
+
|
|
1930
|
+
assetValueToAdd = assetValueToAdd.add(
|
|
1931
|
+
newQuoteAssetValue.sub(currentQuoteAssetValue)
|
|
1932
|
+
);
|
|
1933
|
+
liabilityValueToAdd = liabilityValueToAdd.add(
|
|
1934
|
+
newQuoteLiabilityValue.sub(currentQuoteLiabilityValue)
|
|
1935
|
+
);
|
|
1936
|
+
|
|
1937
|
+
const newSpotMarketNetValue =
|
|
1938
|
+
tradeSide == PositionDirection.LONG
|
|
1939
|
+
? currentSpotMarketNetValue.add(tradeQuoteAmount)
|
|
1940
|
+
: currentSpotMarketNetValue.sub(tradeQuoteAmount);
|
|
1941
|
+
const newSpotMarketAssetValue = BN.max(newSpotMarketNetValue, ZERO);
|
|
1942
|
+
const newSpotMarketLiabilityValue = BN.min(
|
|
1943
|
+
newSpotMarketNetValue,
|
|
1944
|
+
ZERO
|
|
1945
|
+
).abs();
|
|
1946
|
+
|
|
1947
|
+
assetValueToAdd = assetValueToAdd.add(
|
|
1948
|
+
newSpotMarketAssetValue.sub(currentSpotMarketAssetValue)
|
|
1949
|
+
);
|
|
1950
|
+
liabilityValueToAdd = liabilityValueToAdd.add(
|
|
1951
|
+
newSpotMarketLiabilityValue.sub(currentSpotMarketLiabilityValue)
|
|
1952
|
+
);
|
|
1953
|
+
|
|
1954
|
+
const totalAssetValueAfterTrade = totalAssetValue.add(assetValueToAdd);
|
|
1955
|
+
const totalSpotLiabilityValueAfterTrade =
|
|
1956
|
+
spotLiabilityValue.add(liabilityValueToAdd);
|
|
1957
|
+
|
|
1958
|
+
const totalLiabilityValueAfterTrade =
|
|
1959
|
+
totalLiabilityValue.add(liabilityValueToAdd);
|
|
1960
|
+
|
|
1961
|
+
const netAssetValueAfterTrade = totalAssetValueAfterTrade.sub(
|
|
1962
|
+
totalSpotLiabilityValueAfterTrade
|
|
1963
|
+
);
|
|
1964
|
+
|
|
1965
|
+
if (netAssetValueAfterTrade.eq(ZERO)) {
|
|
1966
|
+
return ZERO;
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
const newLeverage = totalLiabilityValueAfterTrade
|
|
1970
|
+
.mul(TEN_THOUSAND)
|
|
1971
|
+
.div(netAssetValueAfterTrade);
|
|
1972
|
+
|
|
1973
|
+
return newLeverage;
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1666
1976
|
const currentPosition =
|
|
1667
1977
|
this.getPerpPosition(targetMarketIndex) ||
|
|
1668
1978
|
this.getEmptyPosition(targetMarketIndex);
|
|
@@ -1842,7 +2152,7 @@ export class User {
|
|
|
1842
2152
|
const depositAmount = getTokenAmount(
|
|
1843
2153
|
position.scaledBalance,
|
|
1844
2154
|
spotMarket,
|
|
1845
|
-
|
|
2155
|
+
SpotBalanceType.DEPOSIT
|
|
1846
2156
|
);
|
|
1847
2157
|
|
|
1848
2158
|
if (netDeposits.lt(ZERO)) {
|