@drift-labs/sdk 0.1.36-master.7 → 0.2.0-master.10
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/bulkAccountLoader.d.ts +6 -6
- package/lib/accounts/bulkAccountLoader.js +81 -95
- package/lib/accounts/bulkUserSubscription.js +13 -57
- package/lib/accounts/fetch.d.ts +4 -0
- package/lib/accounts/fetch.js +18 -0
- package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +34 -38
- package/lib/accounts/pollingClearingHouseAccountSubscriber.js +224 -224
- package/lib/accounts/pollingOracleSubscriber.d.ts +3 -3
- package/lib/accounts/pollingOracleSubscriber.js +37 -49
- package/lib/accounts/pollingTokenAccountSubscriber.d.ts +3 -3
- package/lib/accounts/pollingTokenAccountSubscriber.js +35 -50
- package/lib/accounts/pollingUserAccountSubscriber.d.ts +7 -13
- package/lib/accounts/pollingUserAccountSubscriber.js +71 -134
- package/lib/accounts/types.d.ts +34 -41
- package/lib/accounts/webSocketAccountSubscriber.d.ts +6 -4
- package/lib/accounts/webSocketAccountSubscriber.js +39 -35
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +33 -28
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +153 -185
- package/lib/accounts/webSocketUserAccountSubscriber.d.ts +5 -11
- package/lib/accounts/webSocketUserAccountSubscriber.js +22 -67
- package/lib/addresses/marketAddresses.d.ts +4 -0
- package/lib/addresses/marketAddresses.js +15 -0
- package/lib/addresses/pda.d.ts +12 -0
- package/lib/addresses/pda.js +83 -0
- package/lib/admin.d.ts +12 -18
- package/lib/admin.js +398 -558
- package/lib/clearingHouse.d.ts +83 -109
- package/lib/clearingHouse.js +832 -893
- package/lib/clearingHouseConfig.d.ts +34 -0
- package/lib/clearingHouseConfig.js +2 -0
- package/lib/clearingHouseUser.d.ts +19 -22
- package/lib/clearingHouseUser.js +155 -141
- package/lib/clearingHouseUserConfig.d.ts +14 -0
- package/lib/clearingHouseUserConfig.js +2 -0
- package/lib/config.d.ts +12 -0
- package/lib/config.js +35 -4
- package/lib/constants/banks.d.ts +16 -0
- package/lib/constants/banks.js +41 -0
- package/lib/constants/markets.d.ts +8 -3
- package/lib/constants/markets.js +13 -206
- package/lib/constants/numericConstants.d.ts +17 -0
- package/lib/constants/numericConstants.js +23 -6
- package/lib/events/eventList.d.ts +22 -0
- package/lib/events/eventList.js +77 -0
- package/lib/events/eventSubscriber.d.ts +34 -0
- package/lib/events/eventSubscriber.js +126 -0
- package/lib/events/fetchLogs.d.ts +13 -0
- package/lib/events/fetchLogs.js +39 -0
- package/lib/events/pollingLogProvider.d.ts +15 -0
- package/lib/events/pollingLogProvider.js +53 -0
- package/lib/events/sort.d.ts +2 -0
- package/lib/events/sort.js +44 -0
- package/lib/events/txEventCache.d.ts +24 -0
- package/lib/events/txEventCache.js +71 -0
- package/lib/events/types.d.ts +49 -0
- package/lib/events/types.js +20 -0
- package/lib/events/webSocketLogProvider.d.ts +12 -0
- package/lib/events/webSocketLogProvider.js +30 -0
- package/lib/examples/makeTradeExample.js +26 -27
- package/lib/factory/bigNum.d.ts +118 -0
- package/lib/factory/bigNum.js +364 -0
- package/lib/factory/oracleClient.d.ts +1 -2
- package/lib/factory/oracleClient.js +6 -2
- package/lib/idl/clearing_house.json +2258 -2774
- package/lib/index.d.ts +14 -5
- package/lib/index.js +18 -5
- package/lib/math/amm.d.ts +24 -29
- package/lib/math/amm.js +209 -176
- package/lib/math/auction.d.ts +5 -0
- package/lib/math/auction.js +42 -0
- package/lib/math/bankBalance.d.ts +9 -0
- package/lib/math/bankBalance.js +75 -0
- package/lib/math/conversion.d.ts +0 -1
- package/lib/math/conversion.js +1 -5
- package/lib/math/funding.d.ts +6 -6
- package/lib/math/funding.js +158 -175
- package/lib/math/market.d.ts +6 -6
- package/lib/math/market.js +10 -9
- package/lib/math/orders.d.ts +6 -1
- package/lib/math/orders.js +38 -1
- package/lib/math/position.d.ts +7 -5
- package/lib/math/position.js +29 -27
- package/lib/math/repeg.d.ts +22 -0
- package/lib/math/repeg.js +128 -0
- package/lib/math/trade.d.ts +5 -4
- package/lib/math/trade.js +29 -24
- package/lib/mockUSDCFaucet.js +87 -116
- package/lib/oracles/oracleClientCache.d.ts +8 -0
- package/lib/oracles/oracleClientCache.js +19 -0
- package/lib/oracles/pythClient.d.ts +3 -5
- package/lib/oracles/pythClient.js +12 -31
- package/lib/oracles/quoteAssetOracleClient.d.ts +9 -0
- package/lib/oracles/quoteAssetOracleClient.js +21 -0
- package/lib/oracles/switchboardClient.d.ts +3 -5
- package/lib/oracles/switchboardClient.js +29 -50
- package/lib/oracles/types.d.ts +6 -1
- package/lib/orderParams.d.ts +14 -5
- package/lib/orderParams.js +8 -96
- package/lib/orders.d.ts +6 -7
- package/lib/orders.js +11 -89
- package/lib/slot/SlotSubscriber.d.ts +19 -0
- package/lib/slot/SlotSubscriber.js +26 -0
- package/lib/tx/retryTxSender.d.ts +2 -2
- package/lib/tx/retryTxSender.js +108 -123
- package/lib/tx/types.d.ts +5 -1
- package/lib/tx/utils.d.ts +1 -1
- package/lib/tx/utils.js +11 -2
- package/lib/types.d.ts +180 -110
- package/lib/types.js +54 -1
- package/lib/userName.d.ts +4 -0
- package/lib/userName.js +20 -0
- package/lib/util/computeUnits.js +10 -21
- package/lib/util/tps.js +11 -22
- package/lib/wallet.js +7 -20
- package/package.json +11 -4
- package/src/accounts/bulkAccountLoader.js +197 -0
- package/src/accounts/bulkAccountLoader.ts +21 -15
- package/src/accounts/bulkUserSubscription.js +33 -0
- package/src/accounts/bulkUserSubscription.ts +1 -45
- package/src/accounts/fetch.js +29 -0
- package/src/accounts/fetch.ts +33 -0
- package/src/accounts/pollingClearingHouseAccountSubscriber.js +311 -0
- package/src/accounts/pollingClearingHouseAccountSubscriber.ts +249 -214
- package/src/accounts/pollingOracleSubscriber.js +93 -0
- package/src/accounts/pollingOracleSubscriber.ts +16 -8
- package/src/accounts/pollingTokenAccountSubscriber.js +90 -0
- package/src/accounts/pollingTokenAccountSubscriber.ts +11 -8
- package/src/accounts/pollingUserAccountSubscriber.js +132 -0
- package/src/accounts/pollingUserAccountSubscriber.ts +21 -86
- package/src/accounts/types.js +10 -0
- package/src/accounts/types.ts +41 -70
- package/src/accounts/utils.js +7 -0
- package/src/accounts/webSocketAccountSubscriber.js +93 -0
- package/src/accounts/webSocketAccountSubscriber.ts +33 -16
- package/src/accounts/webSocketClearingHouseAccountSubscriber.js +233 -0
- package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +190 -240
- package/src/accounts/webSocketUserAccountSubscriber.js +62 -0
- package/src/accounts/webSocketUserAccountSubscriber.ts +11 -71
- package/src/addresses/marketAddresses.js +26 -0
- package/src/addresses/marketAddresses.ts +18 -0
- package/{lib/addresses.js → src/addresses/pda.js} +45 -34
- package/src/addresses/pda.ts +118 -0
- package/src/admin.ts +247 -336
- package/src/assert/assert.js +9 -0
- package/src/clearingHouse.ts +1023 -1026
- package/src/clearingHouseConfig.ts +37 -0
- package/src/clearingHouseUser.ts +275 -185
- package/src/clearingHouseUserConfig.ts +18 -0
- package/src/config.ts +54 -1
- package/src/constants/banks.ts +50 -0
- package/src/constants/markets.ts +16 -207
- package/src/constants/numericConstants.ts +34 -5
- package/src/events/eventList.js +77 -0
- package/src/events/eventList.ts +94 -0
- package/src/events/eventSubscriber.js +139 -0
- package/src/events/eventSubscriber.ts +194 -0
- package/src/events/fetchLogs.js +50 -0
- package/src/events/fetchLogs.ts +80 -0
- package/src/events/pollingLogProvider.js +64 -0
- package/src/events/pollingLogProvider.ts +79 -0
- package/src/events/sort.js +44 -0
- package/src/events/sort.ts +65 -0
- package/src/events/txEventCache.js +71 -0
- package/src/events/txEventCache.ts +74 -0
- package/src/events/types.js +20 -0
- package/src/events/types.ts +98 -0
- package/src/events/webSocketLogProvider.js +41 -0
- package/src/events/webSocketLogProvider.ts +38 -0
- package/src/examples/makeTradeExample.js +80 -0
- package/src/examples/makeTradeExample.ts +20 -11
- package/src/factory/bigNum.js +364 -0
- package/src/factory/bigNum.ts +524 -0
- package/src/factory/oracleClient.js +20 -0
- package/src/factory/oracleClient.ts +7 -4
- package/src/idl/clearing_house.json +2258 -2774
- package/src/index.js +69 -0
- package/src/index.ts +14 -5
- package/src/math/amm.js +369 -0
- package/src/math/amm.ts +382 -243
- package/src/math/auction.js +42 -0
- package/src/math/auction.ts +43 -0
- package/src/math/bankBalance.js +75 -0
- package/src/math/bankBalance.ts +112 -0
- package/src/math/conversion.js +11 -0
- package/src/math/conversion.ts +1 -11
- package/src/math/funding.js +248 -0
- package/src/math/funding.ts +12 -9
- package/src/math/market.js +57 -0
- package/src/math/market.ts +37 -30
- package/src/math/oracles.js +26 -0
- package/src/math/orders.js +110 -0
- package/src/math/orders.ts +43 -1
- package/src/math/position.js +140 -0
- package/src/math/position.ts +52 -35
- package/src/math/repeg.js +128 -0
- package/src/math/repeg.ts +176 -0
- package/src/math/state.js +15 -0
- package/src/math/trade.js +253 -0
- package/src/math/trade.ts +55 -47
- package/src/math/utils.js +26 -0
- package/src/math/utils.js.map +1 -0
- package/src/mockUSDCFaucet.js +171 -0
- package/src/oracles/oracleClientCache.js +19 -0
- package/src/oracles/oracleClientCache.ts +20 -0
- package/src/oracles/pythClient.js +46 -0
- package/src/oracles/pythClient.ts +4 -11
- package/src/oracles/quoteAssetOracleClient.js +32 -0
- package/src/oracles/quoteAssetOracleClient.ts +25 -0
- package/src/oracles/switchboardClient.js +69 -0
- package/src/oracles/switchboardClient.ts +11 -24
- package/src/oracles/types.js +2 -0
- package/src/oracles/types.ts +7 -1
- package/src/orderParams.js +20 -0
- package/src/orderParams.ts +20 -141
- package/src/orders.js +134 -0
- package/src/orders.ts +25 -134
- package/src/slot/SlotSubscriber.js +39 -0
- package/src/slot/SlotSubscriber.ts +42 -0
- package/src/token/index.js +38 -0
- package/src/tx/retryTxSender.js +188 -0
- package/src/tx/retryTxSender.ts +6 -4
- package/src/tx/types.js +2 -0
- package/src/tx/types.ts +6 -1
- package/src/tx/utils.js +17 -0
- package/src/tx/utils.ts +22 -3
- package/src/types.js +114 -0
- package/src/types.ts +176 -124
- package/src/userName.js +20 -0
- package/src/userName.ts +20 -0
- package/src/util/promiseTimeout.js +14 -0
- package/src/util/tps.js +27 -0
- package/src/wallet.js +35 -0
- package/tests/bn/test.ts +255 -0
- package/tsconfig.json +12 -12
- package/lib/addresses.d.ts +0 -10
- package/lib/constants/accounts.d.ts +0 -15
- package/lib/constants/accounts.js +0 -18
- package/lib/factory/clearingHouse.d.ts +0 -35
- package/lib/factory/clearingHouse.js +0 -81
- package/lib/factory/clearingHouseUser.d.ts +0 -19
- package/lib/factory/clearingHouseUser.js +0 -34
- package/lib/math/insuranceFund.d.ts +0 -15
- package/lib/math/insuranceFund.js +0 -33
- package/lib/settlement.d.ts +0 -4
- package/lib/settlement.js +0 -10
- package/lib/tx/defaultTxSender.d.ts +0 -8
- package/lib/tx/defaultTxSender.js +0 -12
- package/src/addresses.ts +0 -82
- package/src/constants/accounts.ts +0 -26
- package/src/factory/clearingHouse.ts +0 -173
- package/src/factory/clearingHouseUser.ts +0 -73
- package/src/math/insuranceFund.ts +0 -29
- package/src/settlement.ts +0 -9
- package/src/tx/defaultTxSender.ts +0 -24
package/src/math/market.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { BN } from '@project-serum/anchor';
|
|
2
|
-
import {
|
|
2
|
+
import { MarketAccount, PositionDirection } from '../types';
|
|
3
3
|
import {
|
|
4
4
|
calculateAmmReservesAfterSwap,
|
|
5
5
|
calculatePrice,
|
|
6
|
-
|
|
6
|
+
calculateUpdatedAMMSpreadReserves,
|
|
7
7
|
getSwapDirection,
|
|
8
|
+
calculateUpdatedAMM,
|
|
8
9
|
} from './amm';
|
|
9
10
|
import { OraclePriceData } from '../oracles/types';
|
|
10
11
|
|
|
@@ -14,11 +15,15 @@ import { OraclePriceData } from '../oracles/types';
|
|
|
14
15
|
* @param market
|
|
15
16
|
* @return markPrice : Precision MARK_PRICE_PRECISION
|
|
16
17
|
*/
|
|
17
|
-
export function calculateMarkPrice(
|
|
18
|
+
export function calculateMarkPrice(
|
|
19
|
+
market: MarketAccount,
|
|
20
|
+
oraclePriceData: OraclePriceData
|
|
21
|
+
): BN {
|
|
22
|
+
const newAmm = calculateUpdatedAMM(market.amm, oraclePriceData);
|
|
18
23
|
return calculatePrice(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
24
|
+
newAmm.baseAssetReserve,
|
|
25
|
+
newAmm.quoteAssetReserve,
|
|
26
|
+
newAmm.pegMultiplier
|
|
22
27
|
);
|
|
23
28
|
}
|
|
24
29
|
|
|
@@ -28,17 +33,18 @@ export function calculateMarkPrice(market: Market): BN {
|
|
|
28
33
|
* @param market
|
|
29
34
|
* @return bidPrice : Precision MARK_PRICE_PRECISION
|
|
30
35
|
*/
|
|
31
|
-
export function calculateBidPrice(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
export function calculateBidPrice(
|
|
37
|
+
market: MarketAccount,
|
|
38
|
+
oraclePriceData: OraclePriceData
|
|
39
|
+
): BN {
|
|
40
|
+
const { baseAssetReserve, quoteAssetReserve, newPeg } =
|
|
41
|
+
calculateUpdatedAMMSpreadReserves(
|
|
42
|
+
market.amm,
|
|
43
|
+
PositionDirection.SHORT,
|
|
44
|
+
oraclePriceData
|
|
45
|
+
);
|
|
36
46
|
|
|
37
|
-
return calculatePrice(
|
|
38
|
-
baseAssetReserve,
|
|
39
|
-
quoteAssetReserve,
|
|
40
|
-
market.amm.pegMultiplier
|
|
41
|
-
);
|
|
47
|
+
return calculatePrice(baseAssetReserve, quoteAssetReserve, newPeg);
|
|
42
48
|
}
|
|
43
49
|
|
|
44
50
|
/**
|
|
@@ -47,24 +53,25 @@ export function calculateBidPrice(market: Market): BN {
|
|
|
47
53
|
* @param market
|
|
48
54
|
* @return bidPrice : Precision MARK_PRICE_PRECISION
|
|
49
55
|
*/
|
|
50
|
-
export function calculateAskPrice(
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
export function calculateAskPrice(
|
|
57
|
+
market: MarketAccount,
|
|
58
|
+
oraclePriceData: OraclePriceData
|
|
59
|
+
): BN {
|
|
60
|
+
const { baseAssetReserve, quoteAssetReserve, newPeg } =
|
|
61
|
+
calculateUpdatedAMMSpreadReserves(
|
|
62
|
+
market.amm,
|
|
63
|
+
PositionDirection.LONG,
|
|
64
|
+
oraclePriceData
|
|
65
|
+
);
|
|
55
66
|
|
|
56
|
-
return calculatePrice(
|
|
57
|
-
baseAssetReserve,
|
|
58
|
-
quoteAssetReserve,
|
|
59
|
-
market.amm.pegMultiplier
|
|
60
|
-
);
|
|
67
|
+
return calculatePrice(baseAssetReserve, quoteAssetReserve, newPeg);
|
|
61
68
|
}
|
|
62
69
|
|
|
63
70
|
export function calculateNewMarketAfterTrade(
|
|
64
71
|
baseAssetAmount: BN,
|
|
65
72
|
direction: PositionDirection,
|
|
66
|
-
market:
|
|
67
|
-
):
|
|
73
|
+
market: MarketAccount
|
|
74
|
+
): MarketAccount {
|
|
68
75
|
const [newQuoteAssetReserve, newBaseAssetReserve] =
|
|
69
76
|
calculateAmmReservesAfterSwap(
|
|
70
77
|
market.amm,
|
|
@@ -83,10 +90,10 @@ export function calculateNewMarketAfterTrade(
|
|
|
83
90
|
}
|
|
84
91
|
|
|
85
92
|
export function calculateMarkOracleSpread(
|
|
86
|
-
market:
|
|
93
|
+
market: MarketAccount,
|
|
87
94
|
oraclePriceData: OraclePriceData
|
|
88
95
|
): BN {
|
|
89
|
-
const markPrice = calculateMarkPrice(market);
|
|
96
|
+
const markPrice = calculateMarkPrice(market, oraclePriceData);
|
|
90
97
|
return calculateOracleSpread(markPrice, oraclePriceData);
|
|
91
98
|
}
|
|
92
99
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isOracleValid = void 0;
|
|
4
|
+
const numericConstants_1 = require("../constants/numericConstants");
|
|
5
|
+
const index_1 = require("../index");
|
|
6
|
+
function isOracleValid(amm, oraclePriceData, oracleGuardRails, slot) {
|
|
7
|
+
const isOraclePriceNonPositive = oraclePriceData.price.lt(numericConstants_1.ZERO);
|
|
8
|
+
const isOraclePriceTooVolatile = oraclePriceData.price
|
|
9
|
+
.div(index_1.BN.max(numericConstants_1.ONE, amm.lastOraclePriceTwap))
|
|
10
|
+
.gt(oracleGuardRails.validity.tooVolatileRatio) ||
|
|
11
|
+
amm.lastOraclePriceTwap
|
|
12
|
+
.div(index_1.BN.max(numericConstants_1.ONE, oraclePriceData.price))
|
|
13
|
+
.gt(oracleGuardRails.validity.tooVolatileRatio);
|
|
14
|
+
const isConfidenceTooLarge = oraclePriceData.price
|
|
15
|
+
.div(index_1.BN.max(numericConstants_1.ONE, oraclePriceData.confidence))
|
|
16
|
+
.lt(oracleGuardRails.validity.confidenceIntervalMaxSize);
|
|
17
|
+
const oracleIsStale = oraclePriceData.slot
|
|
18
|
+
.sub(new index_1.BN(slot))
|
|
19
|
+
.gt(oracleGuardRails.validity.slotsBeforeStale);
|
|
20
|
+
return !(!oraclePriceData.hasSufficientNumberOfDataPoints ||
|
|
21
|
+
oracleIsStale ||
|
|
22
|
+
isOraclePriceNonPositive ||
|
|
23
|
+
isOraclePriceTooVolatile ||
|
|
24
|
+
isConfidenceTooLarge);
|
|
25
|
+
}
|
|
26
|
+
exports.isOracleValid = isOracleValid;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getLimitPrice = exports.standardizeBaseAssetAmount = exports.isOrderReduceOnly = exports.isOrderRiskIncreasingInSameDirection = exports.isOrderRiskIncreasing = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
const numericConstants_1 = require("../constants/numericConstants");
|
|
6
|
+
const anchor_1 = require("@project-serum/anchor");
|
|
7
|
+
const auction_1 = require("./auction");
|
|
8
|
+
const market_1 = require("./market");
|
|
9
|
+
function isOrderRiskIncreasing(user, order) {
|
|
10
|
+
if (types_1.isVariant(order.status, 'init')) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
const position = user.getUserPosition(order.marketIndex) ||
|
|
14
|
+
user.getEmptyPosition(order.marketIndex);
|
|
15
|
+
// if no position exists, it's risk increasing
|
|
16
|
+
if (position.baseAssetAmount.eq(numericConstants_1.ZERO)) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
// if position is long and order is long
|
|
20
|
+
if (position.baseAssetAmount.gt(numericConstants_1.ZERO) && types_1.isVariant(order.direction, 'long')) {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
// if position is short and order is short
|
|
24
|
+
if (position.baseAssetAmount.lt(numericConstants_1.ZERO) &&
|
|
25
|
+
types_1.isVariant(order.direction, 'short')) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
const baseAssetAmountToFill = order.baseAssetAmount.sub(order.baseAssetAmountFilled);
|
|
29
|
+
// if order will flip position
|
|
30
|
+
if (baseAssetAmountToFill.gt(position.baseAssetAmount.abs().mul(numericConstants_1.TWO))) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
exports.isOrderRiskIncreasing = isOrderRiskIncreasing;
|
|
36
|
+
function isOrderRiskIncreasingInSameDirection(user, order) {
|
|
37
|
+
if (types_1.isVariant(order.status, 'init')) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
const position = user.getUserPosition(order.marketIndex) ||
|
|
41
|
+
user.getEmptyPosition(order.marketIndex);
|
|
42
|
+
// if no position exists, it's risk increasing
|
|
43
|
+
if (position.baseAssetAmount.eq(numericConstants_1.ZERO)) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
// if position is long and order is long
|
|
47
|
+
if (position.baseAssetAmount.gt(numericConstants_1.ZERO) && types_1.isVariant(order.direction, 'long')) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
// if position is short and order is short
|
|
51
|
+
if (position.baseAssetAmount.lt(numericConstants_1.ZERO) &&
|
|
52
|
+
types_1.isVariant(order.direction, 'short')) {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
exports.isOrderRiskIncreasingInSameDirection = isOrderRiskIncreasingInSameDirection;
|
|
58
|
+
function isOrderReduceOnly(user, order) {
|
|
59
|
+
if (types_1.isVariant(order.status, 'init')) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
const position = user.getUserPosition(order.marketIndex) ||
|
|
63
|
+
user.getEmptyPosition(order.marketIndex);
|
|
64
|
+
// if position is long and order is long
|
|
65
|
+
if (position.baseAssetAmount.gte(numericConstants_1.ZERO) &&
|
|
66
|
+
types_1.isVariant(order.direction, 'long')) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
// if position is short and order is short
|
|
70
|
+
if (position.baseAssetAmount.lte(numericConstants_1.ZERO) &&
|
|
71
|
+
types_1.isVariant(order.direction, 'short')) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
exports.isOrderReduceOnly = isOrderReduceOnly;
|
|
77
|
+
function standardizeBaseAssetAmount(baseAssetAmount, stepSize) {
|
|
78
|
+
const remainder = baseAssetAmount.mod(stepSize);
|
|
79
|
+
return baseAssetAmount.sub(remainder);
|
|
80
|
+
}
|
|
81
|
+
exports.standardizeBaseAssetAmount = standardizeBaseAssetAmount;
|
|
82
|
+
function getLimitPrice(order, market, oraclePriceData, slot) {
|
|
83
|
+
let limitPrice;
|
|
84
|
+
if (!order.oraclePriceOffset.eq(numericConstants_1.ZERO)) {
|
|
85
|
+
limitPrice = oraclePriceData.price.add(order.oraclePriceOffset);
|
|
86
|
+
}
|
|
87
|
+
else if (types_1.isOneOfVariant(order.orderType, ['market', 'triggerMarket'])) {
|
|
88
|
+
if (auction_1.isAuctionComplete(order, slot)) {
|
|
89
|
+
limitPrice = auction_1.getAuctionPrice(order, slot);
|
|
90
|
+
}
|
|
91
|
+
else if (!order.price.eq(numericConstants_1.ZERO)) {
|
|
92
|
+
limitPrice = order.price;
|
|
93
|
+
}
|
|
94
|
+
else if (types_1.isVariant(order.direction, 'long')) {
|
|
95
|
+
const askPrice = market_1.calculateAskPrice(market, oraclePriceData);
|
|
96
|
+
const delta = askPrice.div(new anchor_1.BN(market.amm.maxSlippageRatio));
|
|
97
|
+
limitPrice = askPrice.add(delta);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
const bidPrice = market_1.calculateBidPrice(market, oraclePriceData);
|
|
101
|
+
const delta = bidPrice.div(new anchor_1.BN(market.amm.maxSlippageRatio));
|
|
102
|
+
limitPrice = bidPrice.sub(delta);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
limitPrice = order.price;
|
|
107
|
+
}
|
|
108
|
+
return limitPrice;
|
|
109
|
+
}
|
|
110
|
+
exports.getLimitPrice = getLimitPrice;
|
package/src/math/orders.ts
CHANGED
|
@@ -1,6 +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
|
+
import { BN } from '@project-serum/anchor';
|
|
5
|
+
import { OraclePriceData } from '../oracles/types';
|
|
6
|
+
import { getAuctionPrice, isAuctionComplete } from './auction';
|
|
7
|
+
import { calculateAskPrice, calculateBidPrice } from './market';
|
|
4
8
|
|
|
5
9
|
export function isOrderRiskIncreasing(
|
|
6
10
|
user: ClearingHouseUser,
|
|
@@ -106,3 +110,41 @@ export function isOrderReduceOnly(
|
|
|
106
110
|
|
|
107
111
|
return true;
|
|
108
112
|
}
|
|
113
|
+
|
|
114
|
+
export function standardizeBaseAssetAmount(
|
|
115
|
+
baseAssetAmount: BN,
|
|
116
|
+
stepSize: BN
|
|
117
|
+
): BN {
|
|
118
|
+
const remainder = baseAssetAmount.mod(stepSize);
|
|
119
|
+
return baseAssetAmount.sub(remainder);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function getLimitPrice(
|
|
123
|
+
order: Order,
|
|
124
|
+
market: MarketAccount,
|
|
125
|
+
oraclePriceData: OraclePriceData,
|
|
126
|
+
slot: number
|
|
127
|
+
): BN {
|
|
128
|
+
let limitPrice;
|
|
129
|
+
if (!order.oraclePriceOffset.eq(ZERO)) {
|
|
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);
|
|
140
|
+
} else {
|
|
141
|
+
const bidPrice = calculateBidPrice(market, oraclePriceData);
|
|
142
|
+
const delta = bidPrice.div(new BN(market.amm.maxSlippageRatio));
|
|
143
|
+
limitPrice = bidPrice.sub(delta);
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
limitPrice = order.price;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return limitPrice;
|
|
150
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isEmptyPosition = exports.positionCurrentDirection = exports.findDirectionToClose = exports.calculateEntryPrice = exports.positionIsAvailable = exports.calculatePositionFundingPNL = exports.calculatePositionPNL = exports.calculateBaseAssetValue = void 0;
|
|
4
|
+
const __1 = require("../");
|
|
5
|
+
const numericConstants_1 = require("../constants/numericConstants");
|
|
6
|
+
const types_1 = require("../types");
|
|
7
|
+
const amm_1 = require("./amm");
|
|
8
|
+
/**
|
|
9
|
+
* calculateBaseAssetValue
|
|
10
|
+
* = market value of closing entire position
|
|
11
|
+
* @param market
|
|
12
|
+
* @param userPosition
|
|
13
|
+
* @param oraclePriceData
|
|
14
|
+
* @returns Base Asset Value. : Precision QUOTE_PRECISION
|
|
15
|
+
*/
|
|
16
|
+
function calculateBaseAssetValue(market, userPosition, oraclePriceData) {
|
|
17
|
+
if (userPosition.baseAssetAmount.eq(numericConstants_1.ZERO)) {
|
|
18
|
+
return numericConstants_1.ZERO;
|
|
19
|
+
}
|
|
20
|
+
const directionToClose = findDirectionToClose(userPosition);
|
|
21
|
+
let prepegAmm;
|
|
22
|
+
if (market.amm.baseSpread > 0) {
|
|
23
|
+
const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } = amm_1.calculateUpdatedAMMSpreadReserves(market.amm, directionToClose, oraclePriceData);
|
|
24
|
+
prepegAmm = {
|
|
25
|
+
baseAssetReserve,
|
|
26
|
+
quoteAssetReserve,
|
|
27
|
+
sqrtK: sqrtK,
|
|
28
|
+
pegMultiplier: newPeg,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
prepegAmm = amm_1.calculateUpdatedAMM(market.amm, oraclePriceData);
|
|
33
|
+
}
|
|
34
|
+
const [newQuoteAssetReserve, _] = amm_1.calculateAmmReservesAfterSwap(prepegAmm, 'base', userPosition.baseAssetAmount.abs(), amm_1.getSwapDirection('base', directionToClose));
|
|
35
|
+
switch (directionToClose) {
|
|
36
|
+
case types_1.PositionDirection.SHORT:
|
|
37
|
+
return prepegAmm.quoteAssetReserve
|
|
38
|
+
.sub(newQuoteAssetReserve)
|
|
39
|
+
.mul(prepegAmm.pegMultiplier)
|
|
40
|
+
.div(numericConstants_1.AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO);
|
|
41
|
+
case types_1.PositionDirection.LONG:
|
|
42
|
+
return newQuoteAssetReserve
|
|
43
|
+
.sub(prepegAmm.quoteAssetReserve)
|
|
44
|
+
.mul(prepegAmm.pegMultiplier)
|
|
45
|
+
.div(numericConstants_1.AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO)
|
|
46
|
+
.add(numericConstants_1.ONE);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.calculateBaseAssetValue = calculateBaseAssetValue;
|
|
50
|
+
/**
|
|
51
|
+
* calculatePositionPNL
|
|
52
|
+
* = BaseAssetAmount * (Avg Exit Price - Avg Entry Price)
|
|
53
|
+
* @param market
|
|
54
|
+
* @param marketPosition
|
|
55
|
+
* @param withFunding (adds unrealized funding payment pnl to result)
|
|
56
|
+
* @returns BaseAssetAmount : Precision QUOTE_PRECISION
|
|
57
|
+
*/
|
|
58
|
+
function calculatePositionPNL(market, marketPosition, withFunding = false, oraclePriceData) {
|
|
59
|
+
if (marketPosition.baseAssetAmount.eq(numericConstants_1.ZERO)) {
|
|
60
|
+
return numericConstants_1.ZERO;
|
|
61
|
+
}
|
|
62
|
+
const baseAssetValue = calculateBaseAssetValue(market, marketPosition, oraclePriceData);
|
|
63
|
+
let pnl;
|
|
64
|
+
if (marketPosition.baseAssetAmount.gt(numericConstants_1.ZERO)) {
|
|
65
|
+
pnl = baseAssetValue.sub(marketPosition.quoteAssetAmount);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
pnl = marketPosition.quoteAssetAmount.sub(baseAssetValue);
|
|
69
|
+
}
|
|
70
|
+
if (withFunding) {
|
|
71
|
+
const fundingRatePnL = calculatePositionFundingPNL(market, marketPosition).div(numericConstants_1.PRICE_TO_QUOTE_PRECISION);
|
|
72
|
+
pnl = pnl.add(fundingRatePnL);
|
|
73
|
+
}
|
|
74
|
+
return pnl;
|
|
75
|
+
}
|
|
76
|
+
exports.calculatePositionPNL = calculatePositionPNL;
|
|
77
|
+
/**
|
|
78
|
+
*
|
|
79
|
+
* @param market
|
|
80
|
+
* @param marketPosition
|
|
81
|
+
* @returns // TODO-PRECISION
|
|
82
|
+
*/
|
|
83
|
+
function calculatePositionFundingPNL(market, marketPosition) {
|
|
84
|
+
if (marketPosition.baseAssetAmount.eq(numericConstants_1.ZERO)) {
|
|
85
|
+
return numericConstants_1.ZERO;
|
|
86
|
+
}
|
|
87
|
+
let ammCumulativeFundingRate;
|
|
88
|
+
if (marketPosition.baseAssetAmount.gt(numericConstants_1.ZERO)) {
|
|
89
|
+
ammCumulativeFundingRate = market.amm.cumulativeFundingRateLong;
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
ammCumulativeFundingRate = market.amm.cumulativeFundingRateShort;
|
|
93
|
+
}
|
|
94
|
+
const perPositionFundingRate = ammCumulativeFundingRate
|
|
95
|
+
.sub(marketPosition.lastCumulativeFundingRate)
|
|
96
|
+
.mul(marketPosition.baseAssetAmount)
|
|
97
|
+
.div(numericConstants_1.AMM_RESERVE_PRECISION)
|
|
98
|
+
.div(numericConstants_1.FUNDING_PAYMENT_PRECISION)
|
|
99
|
+
.mul(new __1.BN(-1));
|
|
100
|
+
return perPositionFundingRate;
|
|
101
|
+
}
|
|
102
|
+
exports.calculatePositionFundingPNL = calculatePositionFundingPNL;
|
|
103
|
+
function positionIsAvailable(position) {
|
|
104
|
+
return (position.baseAssetAmount.eq(numericConstants_1.ZERO) &&
|
|
105
|
+
position.openOrders.eq(numericConstants_1.ZERO) &&
|
|
106
|
+
position.unsettledPnl.eq(numericConstants_1.ZERO));
|
|
107
|
+
}
|
|
108
|
+
exports.positionIsAvailable = positionIsAvailable;
|
|
109
|
+
/**
|
|
110
|
+
*
|
|
111
|
+
* @param userPosition
|
|
112
|
+
* @returns Precision: MARK_PRICE_PRECISION (10^10)
|
|
113
|
+
*/
|
|
114
|
+
function calculateEntryPrice(userPosition) {
|
|
115
|
+
if (userPosition.baseAssetAmount.eq(numericConstants_1.ZERO)) {
|
|
116
|
+
return numericConstants_1.ZERO;
|
|
117
|
+
}
|
|
118
|
+
return userPosition.quoteAssetAmount
|
|
119
|
+
.mul(numericConstants_1.MARK_PRICE_PRECISION)
|
|
120
|
+
.mul(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO)
|
|
121
|
+
.div(userPosition.baseAssetAmount)
|
|
122
|
+
.abs();
|
|
123
|
+
}
|
|
124
|
+
exports.calculateEntryPrice = calculateEntryPrice;
|
|
125
|
+
function findDirectionToClose(userPosition) {
|
|
126
|
+
return userPosition.baseAssetAmount.gt(numericConstants_1.ZERO)
|
|
127
|
+
? types_1.PositionDirection.SHORT
|
|
128
|
+
: types_1.PositionDirection.LONG;
|
|
129
|
+
}
|
|
130
|
+
exports.findDirectionToClose = findDirectionToClose;
|
|
131
|
+
function positionCurrentDirection(userPosition) {
|
|
132
|
+
return userPosition.baseAssetAmount.gte(numericConstants_1.ZERO)
|
|
133
|
+
? types_1.PositionDirection.LONG
|
|
134
|
+
: types_1.PositionDirection.SHORT;
|
|
135
|
+
}
|
|
136
|
+
exports.positionCurrentDirection = positionCurrentDirection;
|
|
137
|
+
function isEmptyPosition(userPosition) {
|
|
138
|
+
return (userPosition.baseAssetAmount.eq(numericConstants_1.ZERO) && userPosition.openOrders.eq(numericConstants_1.ZERO));
|
|
139
|
+
}
|
|
140
|
+
exports.isEmptyPosition = isEmptyPosition;
|
package/src/math/position.ts
CHANGED
|
@@ -9,29 +9,54 @@ import {
|
|
|
9
9
|
PRICE_TO_QUOTE_PRECISION,
|
|
10
10
|
ZERO,
|
|
11
11
|
} from '../constants/numericConstants';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
12
|
+
import { OraclePriceData } from '../oracles/types';
|
|
13
|
+
import { MarketAccount, PositionDirection, UserPosition } from '../types';
|
|
14
|
+
import {
|
|
15
|
+
calculateUpdatedAMM,
|
|
16
|
+
calculateUpdatedAMMSpreadReserves,
|
|
17
|
+
calculateAmmReservesAfterSwap,
|
|
18
|
+
getSwapDirection,
|
|
19
|
+
} from './amm';
|
|
15
20
|
|
|
16
21
|
/**
|
|
17
22
|
* calculateBaseAssetValue
|
|
18
23
|
* = market value of closing entire position
|
|
19
24
|
* @param market
|
|
20
25
|
* @param userPosition
|
|
26
|
+
* @param oraclePriceData
|
|
21
27
|
* @returns Base Asset Value. : Precision QUOTE_PRECISION
|
|
22
28
|
*/
|
|
23
29
|
export function calculateBaseAssetValue(
|
|
24
|
-
market:
|
|
25
|
-
userPosition: UserPosition
|
|
30
|
+
market: MarketAccount,
|
|
31
|
+
userPosition: UserPosition,
|
|
32
|
+
oraclePriceData: OraclePriceData
|
|
26
33
|
): BN {
|
|
27
34
|
if (userPosition.baseAssetAmount.eq(ZERO)) {
|
|
28
35
|
return ZERO;
|
|
29
36
|
}
|
|
30
37
|
|
|
31
38
|
const directionToClose = findDirectionToClose(userPosition);
|
|
39
|
+
let prepegAmm: Parameters<typeof calculateAmmReservesAfterSwap>[0];
|
|
40
|
+
|
|
41
|
+
if (market.amm.baseSpread > 0) {
|
|
42
|
+
const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } =
|
|
43
|
+
calculateUpdatedAMMSpreadReserves(
|
|
44
|
+
market.amm,
|
|
45
|
+
directionToClose,
|
|
46
|
+
oraclePriceData
|
|
47
|
+
);
|
|
48
|
+
prepegAmm = {
|
|
49
|
+
baseAssetReserve,
|
|
50
|
+
quoteAssetReserve,
|
|
51
|
+
sqrtK: sqrtK,
|
|
52
|
+
pegMultiplier: newPeg,
|
|
53
|
+
};
|
|
54
|
+
} else {
|
|
55
|
+
prepegAmm = calculateUpdatedAMM(market.amm, oraclePriceData);
|
|
56
|
+
}
|
|
32
57
|
|
|
33
58
|
const [newQuoteAssetReserve, _] = calculateAmmReservesAfterSwap(
|
|
34
|
-
|
|
59
|
+
prepegAmm,
|
|
35
60
|
'base',
|
|
36
61
|
userPosition.baseAssetAmount.abs(),
|
|
37
62
|
getSwapDirection('base', directionToClose)
|
|
@@ -39,15 +64,15 @@ export function calculateBaseAssetValue(
|
|
|
39
64
|
|
|
40
65
|
switch (directionToClose) {
|
|
41
66
|
case PositionDirection.SHORT:
|
|
42
|
-
return
|
|
67
|
+
return prepegAmm.quoteAssetReserve
|
|
43
68
|
.sub(newQuoteAssetReserve)
|
|
44
|
-
.mul(
|
|
69
|
+
.mul(prepegAmm.pegMultiplier)
|
|
45
70
|
.div(AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO);
|
|
46
71
|
|
|
47
72
|
case PositionDirection.LONG:
|
|
48
73
|
return newQuoteAssetReserve
|
|
49
|
-
.sub(
|
|
50
|
-
.mul(
|
|
74
|
+
.sub(prepegAmm.quoteAssetReserve)
|
|
75
|
+
.mul(prepegAmm.pegMultiplier)
|
|
51
76
|
.div(AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO)
|
|
52
77
|
.add(ONE);
|
|
53
78
|
}
|
|
@@ -62,15 +87,20 @@ export function calculateBaseAssetValue(
|
|
|
62
87
|
* @returns BaseAssetAmount : Precision QUOTE_PRECISION
|
|
63
88
|
*/
|
|
64
89
|
export function calculatePositionPNL(
|
|
65
|
-
market:
|
|
90
|
+
market: MarketAccount,
|
|
66
91
|
marketPosition: UserPosition,
|
|
67
|
-
withFunding = false
|
|
92
|
+
withFunding = false,
|
|
93
|
+
oraclePriceData: OraclePriceData
|
|
68
94
|
): BN {
|
|
69
95
|
if (marketPosition.baseAssetAmount.eq(ZERO)) {
|
|
70
96
|
return ZERO;
|
|
71
97
|
}
|
|
72
98
|
|
|
73
|
-
const baseAssetValue = calculateBaseAssetValue(
|
|
99
|
+
const baseAssetValue = calculateBaseAssetValue(
|
|
100
|
+
market,
|
|
101
|
+
marketPosition,
|
|
102
|
+
oraclePriceData
|
|
103
|
+
);
|
|
74
104
|
|
|
75
105
|
let pnl;
|
|
76
106
|
if (marketPosition.baseAssetAmount.gt(ZERO)) {
|
|
@@ -91,27 +121,6 @@ export function calculatePositionPNL(
|
|
|
91
121
|
return pnl;
|
|
92
122
|
}
|
|
93
123
|
|
|
94
|
-
export function calculateSettledPositionPNL(
|
|
95
|
-
market: Market,
|
|
96
|
-
marketPosition: UserPosition
|
|
97
|
-
): BN {
|
|
98
|
-
let pnl = calculatePositionPNL(market, marketPosition);
|
|
99
|
-
|
|
100
|
-
if (pnl.gt(ZERO)) {
|
|
101
|
-
try {
|
|
102
|
-
pnl = pnl
|
|
103
|
-
.mul(new BN(SETTLEMENT_RATIOS[marketPosition.marketIndex.toNumber()]))
|
|
104
|
-
.div(SETTLEMENT_RATIO_PRECISION);
|
|
105
|
-
} catch (e) {
|
|
106
|
-
console.log(pnl.toString());
|
|
107
|
-
console.log(marketPosition.marketIndex.toNumber());
|
|
108
|
-
throw e;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return pnl;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
124
|
/**
|
|
116
125
|
*
|
|
117
126
|
* @param market
|
|
@@ -119,7 +128,7 @@ export function calculateSettledPositionPNL(
|
|
|
119
128
|
* @returns // TODO-PRECISION
|
|
120
129
|
*/
|
|
121
130
|
export function calculatePositionFundingPNL(
|
|
122
|
-
market:
|
|
131
|
+
market: MarketAccount,
|
|
123
132
|
marketPosition: UserPosition
|
|
124
133
|
): BN {
|
|
125
134
|
if (marketPosition.baseAssetAmount.eq(ZERO)) {
|
|
@@ -143,6 +152,14 @@ export function calculatePositionFundingPNL(
|
|
|
143
152
|
return perPositionFundingRate;
|
|
144
153
|
}
|
|
145
154
|
|
|
155
|
+
export function positionIsAvailable(position: UserPosition): boolean {
|
|
156
|
+
return (
|
|
157
|
+
position.baseAssetAmount.eq(ZERO) &&
|
|
158
|
+
position.openOrders.eq(ZERO) &&
|
|
159
|
+
position.unsettledPnl.eq(ZERO)
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
146
163
|
/**
|
|
147
164
|
*
|
|
148
165
|
* @param userPosition
|