@drift-labs/sdk 2.13.0-beta.1 → 2.13.0-beta.2
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/idl/drift.json +1 -1
- package/lib/math/margin.d.ts +1 -1
- package/lib/math/margin.js +7 -7
- package/lib/math/oracles.js +5 -8
- package/lib/math/utils.js +3 -0
- package/lib/user.d.ts +3 -2
- package/lib/user.js +25 -19
- package/package.json +1 -1
- package/src/idl/drift.json +1 -1
- package/src/math/margin.ts +9 -7
- package/src/math/oracles.ts +4 -7
- package/src/math/utils.ts +5 -1
- package/src/user.ts +59 -20
package/lib/idl/drift.json
CHANGED
package/lib/math/margin.d.ts
CHANGED
|
@@ -7,5 +7,5 @@ imfFactor: BN, liabilityWeight: BN, precision: BN): BN;
|
|
|
7
7
|
export declare function calculateSizeDiscountAssetWeight(size: BN, // AMM_RESERVE_PRECISION
|
|
8
8
|
imfFactor: BN, assetWeight: BN): BN;
|
|
9
9
|
export declare function calculateOraclePriceForPerpMargin(perpPosition: PerpPosition, market: PerpMarketAccount, oraclePriceData: OraclePriceData): BN;
|
|
10
|
-
export declare function calculateBaseAssetValueWithOracle(market: PerpMarketAccount, perpPosition: PerpPosition, oraclePriceData: OraclePriceData): BN;
|
|
10
|
+
export declare function calculateBaseAssetValueWithOracle(market: PerpMarketAccount, perpPosition: PerpPosition, oraclePriceData: OraclePriceData, includeOpenOrders?: boolean): BN;
|
|
11
11
|
export declare function calculateWorstCaseBaseAssetAmount(perpPosition: PerpPosition): BN;
|
package/lib/math/margin.js
CHANGED
|
@@ -11,7 +11,7 @@ imfFactor, liabilityWeight, precision) {
|
|
|
11
11
|
if (imfFactor.eq(numericConstants_1.ZERO)) {
|
|
12
12
|
return liabilityWeight;
|
|
13
13
|
}
|
|
14
|
-
const sizeSqrt = utils_1.squareRootBN(size.mul(new anchor_1.BN(10)).add(new anchor_1.BN(1))); //1e9 -> 1e10 -> 1e5
|
|
14
|
+
const sizeSqrt = utils_1.squareRootBN(size.abs().mul(new anchor_1.BN(10)).add(new anchor_1.BN(1))); //1e9 -> 1e10 -> 1e5
|
|
15
15
|
const denom0 = anchor_1.BN.max(new anchor_1.BN(1), numericConstants_1.SPOT_MARKET_IMF_PRECISION.div(imfFactor));
|
|
16
16
|
assert_1.assert(denom0.gt(numericConstants_1.ZERO));
|
|
17
17
|
const liabilityWeightNumerator = liabilityWeight.sub(liabilityWeight.div(anchor_1.BN.max(new anchor_1.BN(1), numericConstants_1.SPOT_MARKET_IMF_PRECISION.div(imfFactor))));
|
|
@@ -30,7 +30,7 @@ imfFactor, assetWeight) {
|
|
|
30
30
|
if (imfFactor.eq(numericConstants_1.ZERO)) {
|
|
31
31
|
return assetWeight;
|
|
32
32
|
}
|
|
33
|
-
const sizeSqrt = utils_1.squareRootBN(size.mul(new anchor_1.BN(10)).add(new anchor_1.BN(1))); //1e9 -> 1e10 -> 1e5
|
|
33
|
+
const sizeSqrt = utils_1.squareRootBN(size.abs().mul(new anchor_1.BN(10)).add(new anchor_1.BN(1))); //1e9 -> 1e10 -> 1e5
|
|
34
34
|
const imfNumerator = numericConstants_1.SPOT_MARKET_IMF_PRECISION.add(numericConstants_1.SPOT_MARKET_IMF_PRECISION.div(new anchor_1.BN(10)));
|
|
35
35
|
const sizeDiscountAssetWeight = imfNumerator
|
|
36
36
|
.mul(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION)
|
|
@@ -58,15 +58,15 @@ function calculateOraclePriceForPerpMargin(perpPosition, market, oraclePriceData
|
|
|
58
58
|
return marginPrice;
|
|
59
59
|
}
|
|
60
60
|
exports.calculateOraclePriceForPerpMargin = calculateOraclePriceForPerpMargin;
|
|
61
|
-
function calculateBaseAssetValueWithOracle(market, perpPosition, oraclePriceData) {
|
|
61
|
+
function calculateBaseAssetValueWithOracle(market, perpPosition, oraclePriceData, includeOpenOrders = false) {
|
|
62
62
|
let price = oraclePriceData.price;
|
|
63
63
|
if (types_1.isVariant(market.status, 'settlement')) {
|
|
64
64
|
price = market.expiryPrice;
|
|
65
65
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
.
|
|
69
|
-
|
|
66
|
+
const baseAssetAmount = includeOpenOrders
|
|
67
|
+
? calculateWorstCaseBaseAssetAmount(perpPosition)
|
|
68
|
+
: perpPosition.baseAssetAmount;
|
|
69
|
+
return baseAssetAmount.abs().mul(price).div(numericConstants_1.AMM_RESERVE_PRECISION);
|
|
70
70
|
}
|
|
71
71
|
exports.calculateBaseAssetValueWithOracle = calculateBaseAssetValueWithOracle;
|
|
72
72
|
function calculateWorstCaseBaseAssetAmount(perpPosition) {
|
package/lib/math/oracles.js
CHANGED
|
@@ -54,16 +54,13 @@ function isOracleTooDivergent(amm, oraclePriceData, oracleGuardRails, now) {
|
|
|
54
54
|
exports.isOracleTooDivergent = isOracleTooDivergent;
|
|
55
55
|
function calculateLiveOracleTwap(histOracleData, oraclePriceData, now, period) {
|
|
56
56
|
let oracleTwap = undefined;
|
|
57
|
-
if (period.eq(numericConstants_1.
|
|
58
|
-
|
|
59
|
-
// period = amm.fundingPeriod;
|
|
60
|
-
oracleTwap = histOracleData.lastOraclePriceTwap;
|
|
61
|
-
}
|
|
62
|
-
else if (period.eq(numericConstants_1.FIVE_MINUTE)) {
|
|
63
|
-
histOracleData.lastOraclePriceTwap5Min;
|
|
57
|
+
if (period.eq(numericConstants_1.FIVE_MINUTE)) {
|
|
58
|
+
oracleTwap = histOracleData.lastOraclePriceTwap5Min;
|
|
64
59
|
}
|
|
65
60
|
else {
|
|
66
|
-
|
|
61
|
+
//todo: assumes its fundingPeriod (1hr)
|
|
62
|
+
// period = amm.fundingPeriod;
|
|
63
|
+
oracleTwap = histOracleData.lastOraclePriceTwap;
|
|
67
64
|
}
|
|
68
65
|
const sinceLastUpdate = index_1.BN.max(numericConstants_1.ONE, now.sub(histOracleData.lastOraclePriceTwapTs));
|
|
69
66
|
const sinceStart = index_1.BN.max(numericConstants_1.ZERO, period.sub(sinceLastUpdate));
|
package/lib/math/utils.js
CHANGED
|
@@ -7,6 +7,9 @@ function clampBN(x, min, max) {
|
|
|
7
7
|
}
|
|
8
8
|
exports.clampBN = clampBN;
|
|
9
9
|
const squareRootBN = (n, closeness = new __1.BN(1)) => {
|
|
10
|
+
if (n.lt(__1.ZERO)) {
|
|
11
|
+
throw new Error('square root of negative number');
|
|
12
|
+
}
|
|
10
13
|
// Assuming the sqrt of n as n only
|
|
11
14
|
let x = n;
|
|
12
15
|
// The closed guess will be stored in the root
|
package/lib/user.d.ts
CHANGED
|
@@ -77,10 +77,11 @@ export declare class User {
|
|
|
77
77
|
*/
|
|
78
78
|
getSettledLPPosition(marketIndex: number): [PerpPosition, BN, BN];
|
|
79
79
|
/**
|
|
80
|
-
* calculates Buying Power =
|
|
80
|
+
* calculates Buying Power = free collateral / initial margin ratio
|
|
81
81
|
* @returns : Precision QUOTE_PRECISION
|
|
82
82
|
*/
|
|
83
83
|
getBuyingPower(marketIndex: number): BN;
|
|
84
|
+
getBuyingPowerFromFreeCollateralAndBaseAssetAmount(marketIndex: number, freeCollateral: BN, baseAssetAmount: BN): BN;
|
|
84
85
|
/**
|
|
85
86
|
* calculates Free Collateral = Total collateral - initial margin requirement
|
|
86
87
|
* @returns : Precision QUOTE_PRECISION
|
|
@@ -133,7 +134,7 @@ export declare class User {
|
|
|
133
134
|
* calculates position value in margin system
|
|
134
135
|
* @returns : Precision QUOTE_PRECISION
|
|
135
136
|
*/
|
|
136
|
-
getPerpPositionValue(marketIndex: number, oraclePriceData: OraclePriceData): BN;
|
|
137
|
+
getPerpPositionValue(marketIndex: number, oraclePriceData: OraclePriceData, includeOpenOrders?: boolean): BN;
|
|
137
138
|
getPositionSide(currentPosition: Pick<PerpPosition, 'baseAssetAmount'>): PositionDirection | undefined;
|
|
138
139
|
/**
|
|
139
140
|
* calculates average exit price (optionally for closing up to 100% of position)
|
package/lib/user.js
CHANGED
|
@@ -239,13 +239,20 @@ class User {
|
|
|
239
239
|
return [position, remainderBaa, pnl];
|
|
240
240
|
}
|
|
241
241
|
/**
|
|
242
|
-
* calculates Buying Power =
|
|
242
|
+
* calculates Buying Power = free collateral / initial margin ratio
|
|
243
243
|
* @returns : Precision QUOTE_PRECISION
|
|
244
244
|
*/
|
|
245
245
|
getBuyingPower(marketIndex) {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
.
|
|
246
|
+
const perpPosition = this.getPerpPosition(marketIndex);
|
|
247
|
+
const worstCaseBaseAssetAmount = perpPosition
|
|
248
|
+
? margin_1.calculateWorstCaseBaseAssetAmount(perpPosition)
|
|
249
|
+
: numericConstants_1.ZERO;
|
|
250
|
+
const freeCollateral = this.getFreeCollateral();
|
|
251
|
+
return this.getBuyingPowerFromFreeCollateralAndBaseAssetAmount(marketIndex, freeCollateral, worstCaseBaseAssetAmount);
|
|
252
|
+
}
|
|
253
|
+
getBuyingPowerFromFreeCollateralAndBaseAssetAmount(marketIndex, freeCollateral, baseAssetAmount) {
|
|
254
|
+
const marginRatio = _1.calculateMarketMarginRatio(this.driftClient.getPerpMarketAccount(marketIndex), baseAssetAmount, 'Initial');
|
|
255
|
+
return freeCollateral.mul(numericConstants_1.MARGIN_PRECISION).div(new _1.BN(marginRatio));
|
|
249
256
|
}
|
|
250
257
|
/**
|
|
251
258
|
* calculates Free Collateral = Total collateral - initial margin requirement
|
|
@@ -557,10 +564,10 @@ class User {
|
|
|
557
564
|
* calculates position value in margin system
|
|
558
565
|
* @returns : Precision QUOTE_PRECISION
|
|
559
566
|
*/
|
|
560
|
-
getPerpPositionValue(marketIndex, oraclePriceData) {
|
|
567
|
+
getPerpPositionValue(marketIndex, oraclePriceData, includeOpenOrders = false) {
|
|
561
568
|
const userPosition = this.getPerpPosition(marketIndex) || this.getEmptyPosition(marketIndex);
|
|
562
569
|
const market = this.driftClient.getPerpMarketAccount(userPosition.marketIndex);
|
|
563
|
-
return margin_1.calculateBaseAssetValueWithOracle(market, userPosition, oraclePriceData);
|
|
570
|
+
return margin_1.calculateBaseAssetValueWithOracle(market, userPosition, oraclePriceData, includeOpenOrders);
|
|
564
571
|
}
|
|
565
572
|
getPositionSide(currentPosition) {
|
|
566
573
|
if (currentPosition.baseAssetAmount.gt(numericConstants_1.ZERO)) {
|
|
@@ -779,7 +786,7 @@ class User {
|
|
|
779
786
|
3. (10k - 4k) / (100k - 4k) = 6k/96k => .0625 */
|
|
780
787
|
const totalCollateral = this.getTotalCollateral('Maintenance');
|
|
781
788
|
// calculate the total position value ignoring any value from the target market of the trade
|
|
782
|
-
const totalPositionValueExcludingTargetMarket = this.getTotalPerpPositionValueExcludingMarket(perpPosition.marketIndex);
|
|
789
|
+
const totalPositionValueExcludingTargetMarket = this.getTotalPerpPositionValueExcludingMarket(perpPosition.marketIndex, undefined, undefined, true);
|
|
783
790
|
const currentPerpPosition = this.getPerpPosition(perpPosition.marketIndex) ||
|
|
784
791
|
this.getEmptyPosition(perpPosition.marketIndex);
|
|
785
792
|
const currentPerpPositionBaseSize = currentPerpPosition.baseAssetAmount;
|
|
@@ -794,8 +801,8 @@ class User {
|
|
|
794
801
|
quoteBreakEvenAmount: new _1.BN(0),
|
|
795
802
|
quoteEntryAmount: new _1.BN(0),
|
|
796
803
|
openOrders: 0,
|
|
797
|
-
openBids:
|
|
798
|
-
openAsks:
|
|
804
|
+
openBids: currentPerpPosition.openBids,
|
|
805
|
+
openAsks: currentPerpPosition.openAsks,
|
|
799
806
|
settledPnl: numericConstants_1.ZERO,
|
|
800
807
|
lpShares: numericConstants_1.ZERO,
|
|
801
808
|
lastBaseAssetAmountPerLp: numericConstants_1.ZERO,
|
|
@@ -804,13 +811,13 @@ class User {
|
|
|
804
811
|
if (proposedBaseAssetAmount.eq(numericConstants_1.ZERO))
|
|
805
812
|
return new _1.BN(-1);
|
|
806
813
|
const market = this.driftClient.getPerpMarketAccount(proposedPerpPosition.marketIndex);
|
|
807
|
-
const proposedPerpPositionValue = margin_1.calculateBaseAssetValueWithOracle(market, proposedPerpPosition, this.getOracleDataForPerpMarket(market.marketIndex));
|
|
814
|
+
const proposedPerpPositionValue = margin_1.calculateBaseAssetValueWithOracle(market, proposedPerpPosition, this.getOracleDataForPerpMarket(market.marketIndex), true);
|
|
808
815
|
// total position value after trade
|
|
809
816
|
const totalPositionValueAfterTrade = totalPositionValueExcludingTargetMarket.add(proposedPerpPositionValue);
|
|
810
817
|
const marginRequirementOfAll = this.getMaintenanceMarginRequirement();
|
|
811
|
-
const positionValue = margin_1.calculateBaseAssetValueWithOracle(market,
|
|
818
|
+
const positionValue = margin_1.calculateBaseAssetValueWithOracle(market, currentPerpPosition, this.getOracleDataForPerpMarket(market.marketIndex), true);
|
|
812
819
|
const marginRequirementOfTargetMarket = positionValue
|
|
813
|
-
.mul(new _1.BN(_1.calculateMarketMarginRatio(market,
|
|
820
|
+
.mul(new _1.BN(_1.calculateMarketMarginRatio(market, margin_1.calculateWorstCaseBaseAssetAmount(currentPerpPosition).abs(), 'Maintenance')))
|
|
814
821
|
.div(numericConstants_1.MARGIN_PRECISION);
|
|
815
822
|
const marginRequirementExcludingTargetMarket = marginRequirementOfAll.sub(marginRequirementOfTargetMarket);
|
|
816
823
|
const freeCollateralExcludingTargetMarket = totalCollateral.sub(marginRequirementExcludingTargetMarket);
|
|
@@ -819,13 +826,14 @@ class User {
|
|
|
819
826
|
proposedPerpPosition.baseAssetAmount.gt(numericConstants_1.ZERO)) {
|
|
820
827
|
return new _1.BN(-1);
|
|
821
828
|
}
|
|
829
|
+
const proposedWorstCastBaseAssetAmount = margin_1.calculateWorstCaseBaseAssetAmount(proposedPerpPosition);
|
|
822
830
|
const marginRequirementTargetMarket = proposedPerpPositionValue
|
|
823
|
-
.mul(new _1.BN(_1.calculateMarketMarginRatio(market,
|
|
831
|
+
.mul(new _1.BN(_1.calculateMarketMarginRatio(market, proposedWorstCastBaseAssetAmount.abs(), 'Maintenance')))
|
|
824
832
|
.div(numericConstants_1.MARGIN_PRECISION);
|
|
825
833
|
const marginRequirementAfterTrade = marginRequirementExcludingTargetMarket.add(marginRequirementTargetMarket);
|
|
826
834
|
const freeCollateralAfterTrade = totalCollateral.sub(marginRequirementAfterTrade);
|
|
827
835
|
const marketMaxMaintLeverage = new _1.BN(numericConstants_1.TEN_THOUSAND.mul(numericConstants_1.TEN_THOUSAND).toNumber() /
|
|
828
|
-
_1.calculateMarketMarginRatio(market,
|
|
836
|
+
_1.calculateMarketMarginRatio(market, proposedWorstCastBaseAssetAmount.abs(), 'Maintenance'));
|
|
829
837
|
let priceDelta;
|
|
830
838
|
if (proposedBaseAssetAmount.lt(numericConstants_1.ZERO)) {
|
|
831
839
|
priceDelta = freeCollateralAfterTrade
|
|
@@ -933,9 +941,7 @@ class User {
|
|
|
933
941
|
}
|
|
934
942
|
else {
|
|
935
943
|
const freeCollateralAfterClose = totalCollateral.sub(marginRequirementAfterClosing);
|
|
936
|
-
const buyingPowerAfterClose = freeCollateralAfterClose
|
|
937
|
-
.mul(this.getMaxLeverage(targetMarketIndex))
|
|
938
|
-
.div(numericConstants_1.TEN_THOUSAND);
|
|
944
|
+
const buyingPowerAfterClose = this.getBuyingPowerFromFreeCollateralAndBaseAssetAmount(targetMarketIndex, freeCollateralAfterClose, numericConstants_1.ZERO);
|
|
939
945
|
maxPositionSize = perpPositionValue.add(buyingPowerAfterClose);
|
|
940
946
|
}
|
|
941
947
|
}
|
|
@@ -960,7 +966,7 @@ class User {
|
|
|
960
966
|
const currentPosition = this.getPerpPosition(targetMarketIndex) ||
|
|
961
967
|
this.getEmptyPosition(targetMarketIndex);
|
|
962
968
|
const oracleData = this.getOracleDataForPerpMarket(targetMarketIndex);
|
|
963
|
-
let currentPositionQuoteAmount = this.getPerpPositionValue(targetMarketIndex, oracleData);
|
|
969
|
+
let currentPositionQuoteAmount = this.getPerpPositionValue(targetMarketIndex, oracleData, includeOpenOrders);
|
|
964
970
|
const currentSide = currentPosition && currentPosition.baseAssetAmount.isNeg()
|
|
965
971
|
? _1.PositionDirection.SHORT
|
|
966
972
|
: _1.PositionDirection.LONG;
|
|
@@ -1089,7 +1095,7 @@ class User {
|
|
|
1089
1095
|
const oracleData = this.getOracleDataForPerpMarket(marketToIgnore);
|
|
1090
1096
|
let currentPerpPositionValueUSDC = numericConstants_1.ZERO;
|
|
1091
1097
|
if (currentPerpPosition) {
|
|
1092
|
-
currentPerpPositionValueUSDC = this.getPerpPositionValue(marketToIgnore, oracleData);
|
|
1098
|
+
currentPerpPositionValueUSDC = this.getPerpPositionValue(marketToIgnore, oracleData, includeOpenOrders);
|
|
1093
1099
|
}
|
|
1094
1100
|
return this.getTotalPerpPositionValue(marginCategory, liquidationBuffer, includeOpenOrders).sub(currentPerpPositionValueUSDC);
|
|
1095
1101
|
}
|
package/package.json
CHANGED
package/src/idl/drift.json
CHANGED
package/src/math/margin.ts
CHANGED
|
@@ -22,7 +22,7 @@ export function calculateSizePremiumLiabilityWeight(
|
|
|
22
22
|
return liabilityWeight;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
const sizeSqrt = squareRootBN(size.mul(new BN(10)).add(new BN(1))); //1e9 -> 1e10 -> 1e5
|
|
25
|
+
const sizeSqrt = squareRootBN(size.abs().mul(new BN(10)).add(new BN(1))); //1e9 -> 1e10 -> 1e5
|
|
26
26
|
|
|
27
27
|
const denom0 = BN.max(new BN(1), SPOT_MARKET_IMF_PRECISION.div(imfFactor));
|
|
28
28
|
assert(denom0.gt(ZERO));
|
|
@@ -57,7 +57,7 @@ export function calculateSizeDiscountAssetWeight(
|
|
|
57
57
|
return assetWeight;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
const sizeSqrt = squareRootBN(size.mul(new BN(10)).add(new BN(1))); //1e9 -> 1e10 -> 1e5
|
|
60
|
+
const sizeSqrt = squareRootBN(size.abs().mul(new BN(10)).add(new BN(1))); //1e9 -> 1e10 -> 1e5
|
|
61
61
|
const imfNumerator = SPOT_MARKET_IMF_PRECISION.add(
|
|
62
62
|
SPOT_MARKET_IMF_PRECISION.div(new BN(10))
|
|
63
63
|
);
|
|
@@ -106,17 +106,19 @@ export function calculateOraclePriceForPerpMargin(
|
|
|
106
106
|
export function calculateBaseAssetValueWithOracle(
|
|
107
107
|
market: PerpMarketAccount,
|
|
108
108
|
perpPosition: PerpPosition,
|
|
109
|
-
oraclePriceData: OraclePriceData
|
|
109
|
+
oraclePriceData: OraclePriceData,
|
|
110
|
+
includeOpenOrders = false
|
|
110
111
|
): BN {
|
|
111
112
|
let price = oraclePriceData.price;
|
|
112
113
|
if (isVariant(market.status, 'settlement')) {
|
|
113
114
|
price = market.expiryPrice;
|
|
114
115
|
}
|
|
115
116
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
.
|
|
119
|
-
|
|
117
|
+
const baseAssetAmount = includeOpenOrders
|
|
118
|
+
? calculateWorstCaseBaseAssetAmount(perpPosition)
|
|
119
|
+
: perpPosition.baseAssetAmount;
|
|
120
|
+
|
|
121
|
+
return baseAssetAmount.abs().mul(price).div(AMM_RESERVE_PRECISION);
|
|
120
122
|
}
|
|
121
123
|
|
|
122
124
|
export function calculateWorstCaseBaseAssetAmount(
|
package/src/math/oracles.ts
CHANGED
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
ONE,
|
|
8
8
|
ZERO,
|
|
9
9
|
FIVE_MINUTE,
|
|
10
|
-
ONE_HOUR,
|
|
11
10
|
} from '../constants/numericConstants';
|
|
12
11
|
import { BN, HistoricalOracleData, PerpMarketAccount } from '../index';
|
|
13
12
|
import { assert } from '../assert/assert';
|
|
@@ -98,14 +97,12 @@ export function calculateLiveOracleTwap(
|
|
|
98
97
|
period: BN
|
|
99
98
|
): BN {
|
|
100
99
|
let oracleTwap = undefined;
|
|
101
|
-
if (period.eq(
|
|
102
|
-
|
|
100
|
+
if (period.eq(FIVE_MINUTE)) {
|
|
101
|
+
oracleTwap = histOracleData.lastOraclePriceTwap5Min;
|
|
102
|
+
} else {
|
|
103
|
+
//todo: assumes its fundingPeriod (1hr)
|
|
103
104
|
// period = amm.fundingPeriod;
|
|
104
105
|
oracleTwap = histOracleData.lastOraclePriceTwap;
|
|
105
|
-
} else if (period.eq(FIVE_MINUTE)) {
|
|
106
|
-
histOracleData.lastOraclePriceTwap5Min;
|
|
107
|
-
} else {
|
|
108
|
-
throw Error('unsupported twap period passed');
|
|
109
106
|
}
|
|
110
107
|
|
|
111
108
|
const sinceLastUpdate = BN.max(
|
package/src/math/utils.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import { BN } from '../';
|
|
1
|
+
import { BN, ZERO } from '../';
|
|
2
2
|
|
|
3
3
|
export function clampBN(x: BN, min: BN, max: BN): BN {
|
|
4
4
|
return BN.max(min, BN.min(x, max));
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
export const squareRootBN = (n, closeness = new BN(1)): BN => {
|
|
8
|
+
if (n.lt(ZERO)) {
|
|
9
|
+
throw new Error('square root of negative number');
|
|
10
|
+
}
|
|
11
|
+
|
|
8
12
|
// Assuming the sqrt of n as n only
|
|
9
13
|
let x = n;
|
|
10
14
|
|
package/src/user.ts
CHANGED
|
@@ -365,13 +365,36 @@ export class User {
|
|
|
365
365
|
}
|
|
366
366
|
|
|
367
367
|
/**
|
|
368
|
-
* calculates Buying Power =
|
|
368
|
+
* calculates Buying Power = free collateral / initial margin ratio
|
|
369
369
|
* @returns : Precision QUOTE_PRECISION
|
|
370
370
|
*/
|
|
371
371
|
public getBuyingPower(marketIndex: number): BN {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
372
|
+
const perpPosition = this.getPerpPosition(marketIndex);
|
|
373
|
+
const worstCaseBaseAssetAmount = perpPosition
|
|
374
|
+
? calculateWorstCaseBaseAssetAmount(perpPosition)
|
|
375
|
+
: ZERO;
|
|
376
|
+
|
|
377
|
+
const freeCollateral = this.getFreeCollateral();
|
|
378
|
+
|
|
379
|
+
return this.getBuyingPowerFromFreeCollateralAndBaseAssetAmount(
|
|
380
|
+
marketIndex,
|
|
381
|
+
freeCollateral,
|
|
382
|
+
worstCaseBaseAssetAmount
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
getBuyingPowerFromFreeCollateralAndBaseAssetAmount(
|
|
387
|
+
marketIndex: number,
|
|
388
|
+
freeCollateral: BN,
|
|
389
|
+
baseAssetAmount: BN
|
|
390
|
+
): BN {
|
|
391
|
+
const marginRatio = calculateMarketMarginRatio(
|
|
392
|
+
this.driftClient.getPerpMarketAccount(marketIndex),
|
|
393
|
+
baseAssetAmount,
|
|
394
|
+
'Initial'
|
|
395
|
+
);
|
|
396
|
+
|
|
397
|
+
return freeCollateral.mul(MARGIN_PRECISION).div(new BN(marginRatio));
|
|
375
398
|
}
|
|
376
399
|
|
|
377
400
|
/**
|
|
@@ -978,7 +1001,8 @@ export class User {
|
|
|
978
1001
|
*/
|
|
979
1002
|
public getPerpPositionValue(
|
|
980
1003
|
marketIndex: number,
|
|
981
|
-
oraclePriceData: OraclePriceData
|
|
1004
|
+
oraclePriceData: OraclePriceData,
|
|
1005
|
+
includeOpenOrders = false
|
|
982
1006
|
): BN {
|
|
983
1007
|
const userPosition =
|
|
984
1008
|
this.getPerpPosition(marketIndex) || this.getEmptyPosition(marketIndex);
|
|
@@ -988,7 +1012,8 @@ export class User {
|
|
|
988
1012
|
return calculateBaseAssetValueWithOracle(
|
|
989
1013
|
market,
|
|
990
1014
|
userPosition,
|
|
991
|
-
oraclePriceData
|
|
1015
|
+
oraclePriceData,
|
|
1016
|
+
includeOpenOrders
|
|
992
1017
|
);
|
|
993
1018
|
}
|
|
994
1019
|
|
|
@@ -1341,7 +1366,12 @@ export class User {
|
|
|
1341
1366
|
|
|
1342
1367
|
// calculate the total position value ignoring any value from the target market of the trade
|
|
1343
1368
|
const totalPositionValueExcludingTargetMarket =
|
|
1344
|
-
this.getTotalPerpPositionValueExcludingMarket(
|
|
1369
|
+
this.getTotalPerpPositionValueExcludingMarket(
|
|
1370
|
+
perpPosition.marketIndex,
|
|
1371
|
+
undefined,
|
|
1372
|
+
undefined,
|
|
1373
|
+
true
|
|
1374
|
+
);
|
|
1345
1375
|
|
|
1346
1376
|
const currentPerpPosition =
|
|
1347
1377
|
this.getPerpPosition(perpPosition.marketIndex) ||
|
|
@@ -1363,8 +1393,8 @@ export class User {
|
|
|
1363
1393
|
quoteBreakEvenAmount: new BN(0),
|
|
1364
1394
|
quoteEntryAmount: new BN(0),
|
|
1365
1395
|
openOrders: 0,
|
|
1366
|
-
openBids:
|
|
1367
|
-
openAsks:
|
|
1396
|
+
openBids: currentPerpPosition.openBids,
|
|
1397
|
+
openAsks: currentPerpPosition.openAsks,
|
|
1368
1398
|
settledPnl: ZERO,
|
|
1369
1399
|
lpShares: ZERO,
|
|
1370
1400
|
lastBaseAssetAmountPerLp: ZERO,
|
|
@@ -1380,7 +1410,8 @@ export class User {
|
|
|
1380
1410
|
const proposedPerpPositionValue = calculateBaseAssetValueWithOracle(
|
|
1381
1411
|
market,
|
|
1382
1412
|
proposedPerpPosition,
|
|
1383
|
-
this.getOracleDataForPerpMarket(market.marketIndex)
|
|
1413
|
+
this.getOracleDataForPerpMarket(market.marketIndex),
|
|
1414
|
+
true
|
|
1384
1415
|
);
|
|
1385
1416
|
|
|
1386
1417
|
// total position value after trade
|
|
@@ -1390,15 +1421,16 @@ export class User {
|
|
|
1390
1421
|
const marginRequirementOfAll = this.getMaintenanceMarginRequirement();
|
|
1391
1422
|
const positionValue = calculateBaseAssetValueWithOracle(
|
|
1392
1423
|
market,
|
|
1393
|
-
|
|
1394
|
-
this.getOracleDataForPerpMarket(market.marketIndex)
|
|
1424
|
+
currentPerpPosition,
|
|
1425
|
+
this.getOracleDataForPerpMarket(market.marketIndex),
|
|
1426
|
+
true
|
|
1395
1427
|
);
|
|
1396
1428
|
const marginRequirementOfTargetMarket = positionValue
|
|
1397
1429
|
.mul(
|
|
1398
1430
|
new BN(
|
|
1399
1431
|
calculateMarketMarginRatio(
|
|
1400
1432
|
market,
|
|
1401
|
-
|
|
1433
|
+
calculateWorstCaseBaseAssetAmount(currentPerpPosition).abs(),
|
|
1402
1434
|
'Maintenance'
|
|
1403
1435
|
)
|
|
1404
1436
|
)
|
|
@@ -1421,12 +1453,14 @@ export class User {
|
|
|
1421
1453
|
return new BN(-1);
|
|
1422
1454
|
}
|
|
1423
1455
|
|
|
1456
|
+
const proposedWorstCastBaseAssetAmount =
|
|
1457
|
+
calculateWorstCaseBaseAssetAmount(proposedPerpPosition);
|
|
1424
1458
|
const marginRequirementTargetMarket = proposedPerpPositionValue
|
|
1425
1459
|
.mul(
|
|
1426
1460
|
new BN(
|
|
1427
1461
|
calculateMarketMarginRatio(
|
|
1428
1462
|
market,
|
|
1429
|
-
|
|
1463
|
+
proposedWorstCastBaseAssetAmount.abs(),
|
|
1430
1464
|
'Maintenance'
|
|
1431
1465
|
)
|
|
1432
1466
|
)
|
|
@@ -1443,7 +1477,7 @@ export class User {
|
|
|
1443
1477
|
TEN_THOUSAND.mul(TEN_THOUSAND).toNumber() /
|
|
1444
1478
|
calculateMarketMarginRatio(
|
|
1445
1479
|
market,
|
|
1446
|
-
|
|
1480
|
+
proposedWorstCastBaseAssetAmount.abs(),
|
|
1447
1481
|
'Maintenance'
|
|
1448
1482
|
)
|
|
1449
1483
|
);
|
|
@@ -1591,9 +1625,12 @@ export class User {
|
|
|
1591
1625
|
const freeCollateralAfterClose = totalCollateral.sub(
|
|
1592
1626
|
marginRequirementAfterClosing
|
|
1593
1627
|
);
|
|
1594
|
-
const buyingPowerAfterClose =
|
|
1595
|
-
|
|
1596
|
-
|
|
1628
|
+
const buyingPowerAfterClose =
|
|
1629
|
+
this.getBuyingPowerFromFreeCollateralAndBaseAssetAmount(
|
|
1630
|
+
targetMarketIndex,
|
|
1631
|
+
freeCollateralAfterClose,
|
|
1632
|
+
ZERO
|
|
1633
|
+
);
|
|
1597
1634
|
maxPositionSize = perpPositionValue.add(buyingPowerAfterClose);
|
|
1598
1635
|
}
|
|
1599
1636
|
} else {
|
|
@@ -1630,7 +1667,8 @@ export class User {
|
|
|
1630
1667
|
|
|
1631
1668
|
let currentPositionQuoteAmount = this.getPerpPositionValue(
|
|
1632
1669
|
targetMarketIndex,
|
|
1633
|
-
oracleData
|
|
1670
|
+
oracleData,
|
|
1671
|
+
includeOpenOrders
|
|
1634
1672
|
);
|
|
1635
1673
|
|
|
1636
1674
|
const currentSide =
|
|
@@ -1841,7 +1879,8 @@ export class User {
|
|
|
1841
1879
|
if (currentPerpPosition) {
|
|
1842
1880
|
currentPerpPositionValueUSDC = this.getPerpPositionValue(
|
|
1843
1881
|
marketToIgnore,
|
|
1844
|
-
oracleData
|
|
1882
|
+
oracleData,
|
|
1883
|
+
includeOpenOrders
|
|
1845
1884
|
);
|
|
1846
1885
|
}
|
|
1847
1886
|
|