@drift-labs/sdk 0.2.0-master.2 → 0.2.0-master.22
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/bulkUserStatsSubscription.d.ts +7 -0
- package/lib/accounts/bulkUserStatsSubscription.js +21 -0
- package/lib/accounts/bulkUserSubscription.js +0 -1
- package/lib/accounts/fetch.d.ts +2 -1
- package/lib/accounts/fetch.js +9 -1
- package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
- package/lib/accounts/pollingUserStatsAccountSubscriber.js +113 -0
- package/lib/accounts/types.d.ts +14 -1
- package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
- package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
- package/lib/addresses/pda.d.ts +1 -0
- package/lib/addresses/pda.js +8 -1
- package/lib/admin.d.ts +9 -5
- package/lib/admin.js +52 -11
- package/lib/clearingHouse.d.ts +52 -23
- package/lib/clearingHouse.js +736 -200
- package/lib/clearingHouseConfig.d.ts +1 -0
- package/lib/clearingHouseUser.d.ts +24 -16
- package/lib/clearingHouseUser.js +223 -101
- package/lib/clearingHouseUserStats.d.ts +18 -0
- package/lib/clearingHouseUserStats.js +49 -0
- package/lib/clearingHouseUserStatsConfig.d.ts +14 -0
- package/lib/clearingHouseUserStatsConfig.js +2 -0
- package/lib/config.js +1 -1
- package/lib/constants/banks.d.ts +2 -2
- package/lib/constants/banks.js +12 -4
- package/lib/constants/numericConstants.d.ts +5 -0
- package/lib/constants/numericConstants.js +8 -3
- package/lib/events/eventList.js +3 -0
- package/lib/events/types.d.ts +3 -1
- package/lib/events/types.js +2 -0
- package/lib/factory/bigNum.d.ts +1 -0
- package/lib/factory/bigNum.js +34 -10
- package/lib/idl/clearing_house.json +1603 -377
- package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
- package/lib/index.d.ts +9 -3
- package/lib/index.js +13 -3
- package/lib/math/amm.d.ts +1 -0
- package/lib/math/amm.js +22 -38
- package/lib/math/auction.js +4 -1
- package/lib/math/bankBalance.d.ts +7 -1
- package/lib/math/bankBalance.js +77 -2
- package/lib/math/margin.d.ts +11 -0
- package/lib/math/margin.js +72 -0
- package/lib/math/market.d.ts +4 -1
- package/lib/math/market.js +35 -1
- package/lib/math/oracles.d.ts +3 -0
- package/lib/math/oracles.js +25 -5
- package/lib/math/orders.d.ts +6 -2
- package/lib/math/orders.js +62 -12
- package/lib/math/position.d.ts +8 -0
- package/lib/math/position.js +45 -12
- package/lib/math/trade.d.ts +1 -1
- package/lib/math/trade.js +7 -10
- package/lib/orderParams.d.ts +14 -5
- package/lib/orderParams.js +8 -96
- package/lib/slot/SlotSubscriber.d.ts +7 -0
- package/lib/slot/SlotSubscriber.js +3 -0
- package/lib/{mockUSDCFaucet.d.ts → tokenFaucet.d.ts} +8 -5
- package/lib/{mockUSDCFaucet.js → tokenFaucet.js} +63 -51
- package/lib/tx/retryTxSender.js +9 -2
- package/lib/tx/utils.js +1 -1
- package/lib/types.d.ts +236 -26
- package/lib/types.js +64 -1
- package/lib/util/computeUnits.js +1 -1
- package/lib/util/getTokenAddress.d.ts +2 -0
- package/lib/util/getTokenAddress.js +9 -0
- package/package.json +3 -3
- package/src/accounts/bulkUserStatsSubscription.ts +33 -0
- package/src/accounts/bulkUserSubscription.ts +0 -1
- package/src/accounts/fetch.ts +27 -2
- package/src/accounts/pollingUserStatsAccountSubscriber.ts +172 -0
- package/src/accounts/types.ts +18 -0
- package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
- package/src/addresses/marketAddresses.js +26 -0
- package/src/addresses/pda.ts +13 -0
- package/src/admin.ts +82 -15
- package/src/assert/assert.js +9 -0
- package/src/clearingHouse.ts +1232 -323
- package/src/clearingHouseConfig.ts +1 -0
- package/src/clearingHouseUser.ts +343 -155
- package/src/clearingHouseUserStats.ts +75 -0
- package/src/clearingHouseUserStatsConfig.ts +18 -0
- package/src/config.ts +1 -1
- package/src/constants/banks.js +42 -0
- package/src/constants/banks.ts +14 -4
- package/src/constants/markets.js +42 -0
- package/src/constants/numericConstants.js +41 -0
- package/src/constants/numericConstants.ts +14 -2
- package/src/events/eventList.js +77 -0
- package/src/events/eventList.ts +3 -0
- package/src/events/eventSubscriber.js +139 -0
- package/src/events/sort.js +44 -0
- package/src/events/txEventCache.js +71 -0
- package/src/events/types.ts +6 -0
- package/src/examples/makeTradeExample.js +80 -0
- package/src/factory/bigNum.js +390 -0
- package/src/factory/bigNum.ts +42 -13
- package/src/factory/oracleClient.js +20 -0
- package/src/idl/clearing_house.json +1603 -377
- package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
- package/src/index.ts +9 -3
- package/src/math/amm.ts +54 -55
- package/src/math/auction.js +42 -0
- package/src/math/auction.ts +5 -1
- package/src/math/bankBalance.ts +148 -2
- package/src/math/conversion.js +11 -0
- package/src/math/funding.js +248 -0
- package/src/math/margin.ts +124 -0
- package/src/math/market.ts +66 -1
- package/src/math/oracles.js +26 -0
- package/src/math/oracles.ts +42 -5
- package/src/math/orders.ts +129 -13
- package/src/math/position.ts +64 -9
- package/src/math/repeg.js +128 -0
- package/src/math/state.js +15 -0
- package/src/math/trade.js +253 -0
- package/src/math/trade.ts +23 -25
- package/src/math/utils.js +0 -1
- package/src/oracles/oracleClientCache.js +19 -0
- package/src/oracles/pythClient.js +46 -0
- package/src/oracles/quoteAssetOracleClient.js +32 -0
- package/src/oracles/switchboardClient.js +69 -0
- package/src/oracles/types.js +2 -0
- package/src/orderParams.js +20 -0
- package/src/orderParams.ts +20 -141
- package/src/slot/SlotSubscriber.js +39 -0
- package/src/slot/SlotSubscriber.ts +11 -1
- package/src/token/index.js +38 -0
- package/src/tokenFaucet.js +189 -0
- package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +82 -70
- package/src/tx/retryTxSender.ts +11 -3
- package/src/tx/types.js +2 -0
- package/src/tx/utils.js +17 -0
- package/src/tx/utils.ts +1 -1
- package/src/types.ts +239 -27
- package/src/userName.js +20 -0
- package/src/util/computeUnits.js +21 -11
- package/src/util/computeUnits.ts +1 -1
- package/src/util/getTokenAddress.js +9 -0
- package/src/util/getTokenAddress.ts +18 -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 +10 -0
- package/lib/orders.d.ts +0 -8
- package/lib/orders.js +0 -142
- package/src/orders.ts +0 -251
- package/src/util/computeUnits.js.map +0 -1
package/src/math/orders.ts
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import { ClearingHouseUser } from '../clearingHouseUser';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
isOneOfVariant,
|
|
4
|
+
isVariant,
|
|
5
|
+
MarketAccount,
|
|
6
|
+
Order,
|
|
7
|
+
PositionDirection,
|
|
8
|
+
} from '../types';
|
|
3
9
|
import { ZERO, TWO } from '../constants/numericConstants';
|
|
4
10
|
import { BN } from '@project-serum/anchor';
|
|
5
11
|
import { OraclePriceData } from '../oracles/types';
|
|
6
|
-
import { getAuctionPrice } from './auction';
|
|
12
|
+
import { getAuctionPrice, isAuctionComplete } from './auction';
|
|
13
|
+
import { calculateAskPrice, calculateBidPrice } from './market';
|
|
14
|
+
import {
|
|
15
|
+
calculateMaxBaseAssetAmountFillable,
|
|
16
|
+
calculateMaxBaseAssetAmountToTrade,
|
|
17
|
+
} from './amm';
|
|
7
18
|
|
|
8
19
|
export function isOrderRiskIncreasing(
|
|
9
20
|
user: ClearingHouseUser,
|
|
@@ -120,27 +131,132 @@ export function standardizeBaseAssetAmount(
|
|
|
120
131
|
|
|
121
132
|
export function getLimitPrice(
|
|
122
133
|
order: Order,
|
|
134
|
+
market: MarketAccount,
|
|
123
135
|
oraclePriceData: OraclePriceData,
|
|
124
136
|
slot: number
|
|
125
137
|
): BN {
|
|
126
138
|
let limitPrice;
|
|
127
139
|
if (!order.oraclePriceOffset.eq(ZERO)) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
140
|
+
limitPrice = oraclePriceData.price.add(order.oraclePriceOffset);
|
|
141
|
+
} else if (isOneOfVariant(order.orderType, ['market', 'triggerMarket'])) {
|
|
142
|
+
if (!isAuctionComplete(order, slot)) {
|
|
143
|
+
limitPrice = getAuctionPrice(order, slot);
|
|
144
|
+
} else if (!order.price.eq(ZERO)) {
|
|
145
|
+
limitPrice = order.price;
|
|
146
|
+
} else if (isVariant(order.direction, 'long')) {
|
|
147
|
+
const askPrice = calculateAskPrice(market, oraclePriceData);
|
|
148
|
+
const delta = askPrice.div(new BN(market.amm.maxSlippageRatio));
|
|
149
|
+
limitPrice = askPrice.add(delta);
|
|
133
150
|
} else {
|
|
134
|
-
|
|
151
|
+
const bidPrice = calculateBidPrice(market, oraclePriceData);
|
|
152
|
+
const delta = bidPrice.div(new BN(market.amm.maxSlippageRatio));
|
|
153
|
+
limitPrice = bidPrice.sub(delta);
|
|
135
154
|
}
|
|
136
|
-
} else if (
|
|
137
|
-
isVariant(order.orderType, 'market') ||
|
|
138
|
-
isVariant(order.orderType, 'triggerMarket')
|
|
139
|
-
) {
|
|
140
|
-
limitPrice = getAuctionPrice(order, slot);
|
|
141
155
|
} else {
|
|
142
156
|
limitPrice = order.price;
|
|
143
157
|
}
|
|
144
158
|
|
|
145
159
|
return limitPrice;
|
|
146
160
|
}
|
|
161
|
+
|
|
162
|
+
export function isFillableByVAMM(
|
|
163
|
+
order: Order,
|
|
164
|
+
market: MarketAccount,
|
|
165
|
+
oraclePriceData: OraclePriceData,
|
|
166
|
+
slot: number,
|
|
167
|
+
maxAuctionDuration: number
|
|
168
|
+
): boolean {
|
|
169
|
+
return (
|
|
170
|
+
(isAuctionComplete(order, slot) &&
|
|
171
|
+
!calculateBaseAssetAmountForAmmToFulfill(
|
|
172
|
+
order,
|
|
173
|
+
market,
|
|
174
|
+
oraclePriceData,
|
|
175
|
+
slot
|
|
176
|
+
).eq(ZERO)) ||
|
|
177
|
+
isOrderExpired(order, slot, maxAuctionDuration)
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function calculateBaseAssetAmountForAmmToFulfill(
|
|
182
|
+
order: Order,
|
|
183
|
+
market: MarketAccount,
|
|
184
|
+
oraclePriceData: OraclePriceData,
|
|
185
|
+
slot: number
|
|
186
|
+
): BN {
|
|
187
|
+
if (
|
|
188
|
+
isOneOfVariant(order.orderType, ['triggerMarket', 'triggerLimit']) &&
|
|
189
|
+
order.triggered === false
|
|
190
|
+
) {
|
|
191
|
+
return ZERO;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const limitPrice = getLimitPrice(order, market, oraclePriceData, slot);
|
|
195
|
+
const baseAssetAmount = calculateBaseAssetAmountToFillUpToLimitPrice(
|
|
196
|
+
order,
|
|
197
|
+
market,
|
|
198
|
+
limitPrice,
|
|
199
|
+
oraclePriceData
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
const maxBaseAssetAmount = calculateMaxBaseAssetAmountFillable(
|
|
203
|
+
market.amm,
|
|
204
|
+
order.direction
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
return BN.min(maxBaseAssetAmount, baseAssetAmount);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export function calculateBaseAssetAmountToFillUpToLimitPrice(
|
|
211
|
+
order: Order,
|
|
212
|
+
market: MarketAccount,
|
|
213
|
+
limitPrice: BN,
|
|
214
|
+
oraclePriceData: OraclePriceData
|
|
215
|
+
): BN {
|
|
216
|
+
const [maxAmountToTrade, direction] = calculateMaxBaseAssetAmountToTrade(
|
|
217
|
+
market.amm,
|
|
218
|
+
limitPrice,
|
|
219
|
+
order.direction,
|
|
220
|
+
oraclePriceData
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
const baseAssetAmount = standardizeBaseAssetAmount(
|
|
224
|
+
maxAmountToTrade,
|
|
225
|
+
market.amm.baseAssetAmountStepSize
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
// Check that directions are the same
|
|
229
|
+
const sameDirection = isSameDirection(direction, order.direction);
|
|
230
|
+
if (!sameDirection) {
|
|
231
|
+
return ZERO;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return baseAssetAmount.gt(order.baseAssetAmount)
|
|
235
|
+
? order.baseAssetAmount
|
|
236
|
+
: baseAssetAmount;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function isSameDirection(
|
|
240
|
+
firstDirection: PositionDirection,
|
|
241
|
+
secondDirection: PositionDirection
|
|
242
|
+
): boolean {
|
|
243
|
+
return (
|
|
244
|
+
(isVariant(firstDirection, 'long') && isVariant(secondDirection, 'long')) ||
|
|
245
|
+
(isVariant(firstDirection, 'short') && isVariant(secondDirection, 'short'))
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export function isOrderExpired(
|
|
250
|
+
order: Order,
|
|
251
|
+
slot: number,
|
|
252
|
+
maxAuctionDuration: number
|
|
253
|
+
): boolean {
|
|
254
|
+
if (
|
|
255
|
+
!isVariant(order.orderType, 'market') ||
|
|
256
|
+
!isVariant(order.status, 'open')
|
|
257
|
+
) {
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return new BN(slot).sub(order.slot).gt(new BN(maxAuctionDuration));
|
|
262
|
+
}
|
package/src/math/position.ts
CHANGED
|
@@ -18,6 +18,8 @@ import {
|
|
|
18
18
|
getSwapDirection,
|
|
19
19
|
} from './amm';
|
|
20
20
|
|
|
21
|
+
import { calculateMarginBaseAssetValue } from './margin';
|
|
22
|
+
|
|
21
23
|
/**
|
|
22
24
|
* calculateBaseAssetValue
|
|
23
25
|
* = market value of closing entire position
|
|
@@ -84,6 +86,7 @@ export function calculateBaseAssetValue(
|
|
|
84
86
|
* @param market
|
|
85
87
|
* @param marketPosition
|
|
86
88
|
* @param withFunding (adds unrealized funding payment pnl to result)
|
|
89
|
+
* @param oraclePriceData
|
|
87
90
|
* @returns BaseAssetAmount : Precision QUOTE_PRECISION
|
|
88
91
|
*/
|
|
89
92
|
export function calculatePositionPNL(
|
|
@@ -93,21 +96,21 @@ export function calculatePositionPNL(
|
|
|
93
96
|
oraclePriceData: OraclePriceData
|
|
94
97
|
): BN {
|
|
95
98
|
if (marketPosition.baseAssetAmount.eq(ZERO)) {
|
|
96
|
-
return
|
|
99
|
+
return marketPosition.quoteAssetAmount;
|
|
97
100
|
}
|
|
98
101
|
|
|
99
|
-
const baseAssetValue =
|
|
102
|
+
const baseAssetValue = calculateMarginBaseAssetValue(
|
|
100
103
|
market,
|
|
101
104
|
marketPosition,
|
|
102
105
|
oraclePriceData
|
|
103
106
|
);
|
|
104
107
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
const baseAssetValueSign = marketPosition.baseAssetAmount.isNeg()
|
|
109
|
+
? new BN(-1)
|
|
110
|
+
: new BN(1);
|
|
111
|
+
let pnl = baseAssetValue
|
|
112
|
+
.mul(baseAssetValueSign)
|
|
113
|
+
.add(marketPosition.quoteAssetAmount);
|
|
111
114
|
|
|
112
115
|
if (withFunding) {
|
|
113
116
|
const fundingRatePnL = calculatePositionFundingPNL(
|
|
@@ -121,6 +124,36 @@ export function calculatePositionPNL(
|
|
|
121
124
|
return pnl;
|
|
122
125
|
}
|
|
123
126
|
|
|
127
|
+
export function calculateUnsettledPnl(
|
|
128
|
+
market: MarketAccount,
|
|
129
|
+
marketPosition: UserPosition,
|
|
130
|
+
oraclePriceData: OraclePriceData
|
|
131
|
+
): BN {
|
|
132
|
+
const unrealizedPnl = calculatePositionPNL(
|
|
133
|
+
market,
|
|
134
|
+
marketPosition,
|
|
135
|
+
true,
|
|
136
|
+
oraclePriceData
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
let unsettledPnl = unrealizedPnl;
|
|
140
|
+
if (unrealizedPnl.gt(ZERO)) {
|
|
141
|
+
const fundingPnL = calculatePositionFundingPNL(market, marketPosition).div(
|
|
142
|
+
PRICE_TO_QUOTE_PRECISION
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
const maxPositivePnl = BN.max(
|
|
146
|
+
marketPosition.quoteAssetAmount
|
|
147
|
+
.sub(marketPosition.quoteEntryAmount)
|
|
148
|
+
.add(fundingPnL),
|
|
149
|
+
ZERO
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
unsettledPnl = BN.min(maxPositivePnl, unrealizedPnl);
|
|
153
|
+
}
|
|
154
|
+
return unsettledPnl;
|
|
155
|
+
}
|
|
156
|
+
|
|
124
157
|
/**
|
|
125
158
|
*
|
|
126
159
|
* @param market
|
|
@@ -153,7 +186,12 @@ export function calculatePositionFundingPNL(
|
|
|
153
186
|
}
|
|
154
187
|
|
|
155
188
|
export function positionIsAvailable(position: UserPosition): boolean {
|
|
156
|
-
return
|
|
189
|
+
return (
|
|
190
|
+
position.baseAssetAmount.eq(ZERO) &&
|
|
191
|
+
position.openOrders.eq(ZERO) &&
|
|
192
|
+
position.quoteAssetAmount.eq(ZERO) &&
|
|
193
|
+
position.lpShares.eq(ZERO)
|
|
194
|
+
);
|
|
157
195
|
}
|
|
158
196
|
|
|
159
197
|
/**
|
|
@@ -166,6 +204,23 @@ export function calculateEntryPrice(userPosition: UserPosition): BN {
|
|
|
166
204
|
return ZERO;
|
|
167
205
|
}
|
|
168
206
|
|
|
207
|
+
return userPosition.quoteEntryAmount
|
|
208
|
+
.mul(MARK_PRICE_PRECISION)
|
|
209
|
+
.mul(AMM_TO_QUOTE_PRECISION_RATIO)
|
|
210
|
+
.div(userPosition.baseAssetAmount)
|
|
211
|
+
.abs();
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
*
|
|
216
|
+
* @param userPosition
|
|
217
|
+
* @returns Precision: MARK_PRICE_PRECISION (10^10)
|
|
218
|
+
*/
|
|
219
|
+
export function calculateCostBasis(userPosition: UserPosition): BN {
|
|
220
|
+
if (userPosition.baseAssetAmount.eq(ZERO)) {
|
|
221
|
+
return ZERO;
|
|
222
|
+
}
|
|
223
|
+
|
|
169
224
|
return userPosition.quoteAssetAmount
|
|
170
225
|
.mul(MARK_PRICE_PRECISION)
|
|
171
226
|
.mul(AMM_TO_QUOTE_PRECISION_RATIO)
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.calculateBudgetedPeg = exports.calculateBudgetedK = exports.calculateBudgetedKBN = exports.calculateRepegCost = exports.calculateAdjustKCost = void 0;
|
|
4
|
+
const anchor_1 = require("@project-serum/anchor");
|
|
5
|
+
const assert_1 = require("../assert/assert");
|
|
6
|
+
const numericConstants_1 = require("../constants/numericConstants");
|
|
7
|
+
/**
|
|
8
|
+
* Helper function calculating adjust k cost
|
|
9
|
+
* @param amm
|
|
10
|
+
* @param numerator
|
|
11
|
+
* @param denomenator
|
|
12
|
+
* @returns cost : Precision QUOTE_ASSET_PRECISION
|
|
13
|
+
*/
|
|
14
|
+
function calculateAdjustKCost(amm, numerator, denomenator) {
|
|
15
|
+
// const k = market.amm.sqrtK.mul(market.amm.sqrtK);
|
|
16
|
+
const x = amm.baseAssetReserve;
|
|
17
|
+
const y = amm.quoteAssetReserve;
|
|
18
|
+
const d = amm.netBaseAssetAmount;
|
|
19
|
+
const Q = amm.pegMultiplier;
|
|
20
|
+
const quoteScale = y.mul(d).mul(Q); //.div(AMM_RESERVE_PRECISION);
|
|
21
|
+
const p = numerator.mul(numericConstants_1.MARK_PRICE_PRECISION).div(denomenator);
|
|
22
|
+
const cost = quoteScale
|
|
23
|
+
.div(x.add(d))
|
|
24
|
+
.sub(quoteScale
|
|
25
|
+
.mul(p)
|
|
26
|
+
.div(numericConstants_1.MARK_PRICE_PRECISION)
|
|
27
|
+
.div(x.mul(p).div(numericConstants_1.MARK_PRICE_PRECISION).add(d)))
|
|
28
|
+
.div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO)
|
|
29
|
+
.div(numericConstants_1.PEG_PRECISION);
|
|
30
|
+
return cost.mul(new anchor_1.BN(-1));
|
|
31
|
+
}
|
|
32
|
+
exports.calculateAdjustKCost = calculateAdjustKCost;
|
|
33
|
+
/**
|
|
34
|
+
* Helper function calculating adjust pegMultiplier (repeg) cost
|
|
35
|
+
*
|
|
36
|
+
* @param amm
|
|
37
|
+
* @param newPeg
|
|
38
|
+
* @returns cost : Precision QUOTE_ASSET_PRECISION
|
|
39
|
+
*/
|
|
40
|
+
function calculateRepegCost(amm, newPeg) {
|
|
41
|
+
const dqar = amm.quoteAssetReserve.sub(amm.terminalQuoteAssetReserve);
|
|
42
|
+
const cost = dqar
|
|
43
|
+
.mul(newPeg.sub(amm.pegMultiplier))
|
|
44
|
+
.div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO)
|
|
45
|
+
.div(numericConstants_1.PEG_PRECISION);
|
|
46
|
+
return cost;
|
|
47
|
+
}
|
|
48
|
+
exports.calculateRepegCost = calculateRepegCost;
|
|
49
|
+
function calculateBudgetedKBN(x, y, budget, Q, d) {
|
|
50
|
+
assert_1.assert(Q.gt(new anchor_1.BN(0)));
|
|
51
|
+
const C = budget.mul(new anchor_1.BN(-1));
|
|
52
|
+
let dSign = new anchor_1.BN(1);
|
|
53
|
+
if (d.lt(new anchor_1.BN(0))) {
|
|
54
|
+
dSign = new anchor_1.BN(-1);
|
|
55
|
+
}
|
|
56
|
+
const pegged_y_d_d = y
|
|
57
|
+
.mul(d)
|
|
58
|
+
.mul(d)
|
|
59
|
+
.mul(Q)
|
|
60
|
+
.div(numericConstants_1.AMM_RESERVE_PRECISION)
|
|
61
|
+
.div(numericConstants_1.AMM_RESERVE_PRECISION)
|
|
62
|
+
.div(numericConstants_1.PEG_PRECISION);
|
|
63
|
+
const numer1 = pegged_y_d_d;
|
|
64
|
+
const numer2 = C.mul(d)
|
|
65
|
+
.div(numericConstants_1.QUOTE_PRECISION)
|
|
66
|
+
.mul(x.add(d))
|
|
67
|
+
.div(numericConstants_1.AMM_RESERVE_PRECISION)
|
|
68
|
+
.mul(dSign);
|
|
69
|
+
const denom1 = C.mul(x)
|
|
70
|
+
.mul(x.add(d))
|
|
71
|
+
.div(numericConstants_1.AMM_RESERVE_PRECISION)
|
|
72
|
+
.div(numericConstants_1.QUOTE_PRECISION);
|
|
73
|
+
const denom2 = pegged_y_d_d;
|
|
74
|
+
const numerator = numer1.sub(numer2).div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO);
|
|
75
|
+
const denominator = denom1.add(denom2).div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO);
|
|
76
|
+
return [numerator, denominator];
|
|
77
|
+
}
|
|
78
|
+
exports.calculateBudgetedKBN = calculateBudgetedKBN;
|
|
79
|
+
function calculateBudgetedK(amm, cost) {
|
|
80
|
+
// wolframalpha.com
|
|
81
|
+
// (1/(x+d) - p/(x*p+d))*y*d*Q = C solve for p
|
|
82
|
+
// p = (d(y*d*Q - C(x+d))) / (C*x(x+d) + y*d*d*Q)
|
|
83
|
+
// numer
|
|
84
|
+
// = y*d*d*Q - Cxd - Cdd
|
|
85
|
+
// = y/x*Q*d*d - Cd - Cd/x
|
|
86
|
+
// = mark - C/d - C/(x)
|
|
87
|
+
// = mark/C - 1/d - 1/x
|
|
88
|
+
// denom
|
|
89
|
+
// = C*x*x + C*x*d + y*d*d*Q
|
|
90
|
+
// = x/d**2 + 1 / d + mark/C
|
|
91
|
+
// todo: assumes k = x * y
|
|
92
|
+
// otherwise use: (y(1-p) + (kp^2/(x*p+d)) - k/(x+d)) * Q = C solve for p
|
|
93
|
+
const x = amm.baseAssetReserve;
|
|
94
|
+
const y = amm.quoteAssetReserve;
|
|
95
|
+
const d = amm.netBaseAssetAmount;
|
|
96
|
+
const Q = amm.pegMultiplier;
|
|
97
|
+
const [numerator, denominator] = calculateBudgetedKBN(x, y, cost, Q, d);
|
|
98
|
+
return [numerator, denominator];
|
|
99
|
+
}
|
|
100
|
+
exports.calculateBudgetedK = calculateBudgetedK;
|
|
101
|
+
function calculateBudgetedPeg(amm, cost, targetPrice) {
|
|
102
|
+
// wolframalpha.com
|
|
103
|
+
// (1/(x+d) - p/(x*p+d))*y*d*Q = C solve for p
|
|
104
|
+
// p = (d(y*d*Q - C(x+d))) / (C*x(x+d) + y*y*d*Q)
|
|
105
|
+
// todo: assumes k = x * y
|
|
106
|
+
// otherwise use: (y(1-p) + (kp^2/(x*p+d)) - k/(x+d)) * Q = C solve for p
|
|
107
|
+
const targetPeg = targetPrice
|
|
108
|
+
.mul(amm.baseAssetReserve)
|
|
109
|
+
.div(amm.quoteAssetReserve)
|
|
110
|
+
.div(numericConstants_1.PRICE_DIV_PEG);
|
|
111
|
+
const k = amm.sqrtK.mul(amm.sqrtK);
|
|
112
|
+
const x = amm.baseAssetReserve;
|
|
113
|
+
const y = amm.quoteAssetReserve;
|
|
114
|
+
const d = amm.netBaseAssetAmount;
|
|
115
|
+
const Q = amm.pegMultiplier;
|
|
116
|
+
const C = cost.mul(new anchor_1.BN(-1));
|
|
117
|
+
const deltaQuoteAssetReserves = y.sub(k.div(x.add(d)));
|
|
118
|
+
const pegChangeDirection = targetPeg.sub(Q);
|
|
119
|
+
const useTargetPeg = (deltaQuoteAssetReserves.lt(numericConstants_1.ZERO) && pegChangeDirection.gt(numericConstants_1.ZERO)) ||
|
|
120
|
+
(deltaQuoteAssetReserves.gt(numericConstants_1.ZERO) && pegChangeDirection.lt(numericConstants_1.ZERO));
|
|
121
|
+
if (deltaQuoteAssetReserves.eq(numericConstants_1.ZERO) || useTargetPeg) {
|
|
122
|
+
return targetPeg;
|
|
123
|
+
}
|
|
124
|
+
const deltaPegMultiplier = C.mul(numericConstants_1.MARK_PRICE_PRECISION).div(deltaQuoteAssetReserves.div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO));
|
|
125
|
+
const newPeg = Q.sub(deltaPegMultiplier.mul(numericConstants_1.PEG_PRECISION).div(numericConstants_1.MARK_PRICE_PRECISION));
|
|
126
|
+
return newPeg;
|
|
127
|
+
}
|
|
128
|
+
exports.calculateBudgetedPeg = calculateBudgetedPeg;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getExchangeFee = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Get the clearing house percent fee charged on notional of taking trades
|
|
6
|
+
*
|
|
7
|
+
* @param state
|
|
8
|
+
* @returns Precision : basis points (bps)
|
|
9
|
+
*/
|
|
10
|
+
function getExchangeFee(state) {
|
|
11
|
+
const exchangeFee = state.feeStructure.feeNumerator.toNumber() /
|
|
12
|
+
state.feeStructure.feeDenominator.toNumber();
|
|
13
|
+
return exchangeFee;
|
|
14
|
+
}
|
|
15
|
+
exports.getExchangeFee = getExchangeFee;
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.calculateTargetPriceTrade = exports.calculateTradeAcquiredAmounts = exports.calculateTradeSlippage = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
const anchor_1 = require("@project-serum/anchor");
|
|
6
|
+
const assert_1 = require("../assert/assert");
|
|
7
|
+
const numericConstants_1 = require("../constants/numericConstants");
|
|
8
|
+
const market_1 = require("./market");
|
|
9
|
+
const amm_1 = require("./amm");
|
|
10
|
+
const utils_1 = require("./utils");
|
|
11
|
+
const types_2 = require("../types");
|
|
12
|
+
const MAXPCT = new anchor_1.BN(1000); //percentage units are [0,1000] => [0,1]
|
|
13
|
+
/**
|
|
14
|
+
* Calculates avg/max slippage (price impact) for candidate trade
|
|
15
|
+
* @param direction
|
|
16
|
+
* @param amount
|
|
17
|
+
* @param market
|
|
18
|
+
* @param inputAssetType which asset is being traded
|
|
19
|
+
* @param useSpread whether to consider spread with calculating slippage
|
|
20
|
+
* @return [pctAvgSlippage, pctMaxSlippage, entryPrice, newPrice]
|
|
21
|
+
*
|
|
22
|
+
* 'pctAvgSlippage' => the percentage change to entryPrice (average est slippage in execution) : Precision MARK_PRICE_PRECISION
|
|
23
|
+
*
|
|
24
|
+
* 'pctMaxSlippage' => the percentage change to maxPrice (highest est slippage in execution) : Precision MARK_PRICE_PRECISION
|
|
25
|
+
*
|
|
26
|
+
* 'entryPrice' => the average price of the trade : Precision MARK_PRICE_PRECISION
|
|
27
|
+
*
|
|
28
|
+
* 'newPrice' => the price of the asset after the trade : Precision MARK_PRICE_PRECISION
|
|
29
|
+
*/
|
|
30
|
+
function calculateTradeSlippage(direction, amount, market, inputAssetType = 'quote', oraclePriceData, useSpread = true) {
|
|
31
|
+
let oldPrice;
|
|
32
|
+
if (useSpread && market.amm.baseSpread > 0) {
|
|
33
|
+
if (types_2.isVariant(direction, 'long')) {
|
|
34
|
+
oldPrice = market_1.calculateAskPrice(market, oraclePriceData);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
oldPrice = market_1.calculateBidPrice(market, oraclePriceData);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
oldPrice = market_1.calculateMarkPrice(market, oraclePriceData);
|
|
42
|
+
}
|
|
43
|
+
if (amount.eq(numericConstants_1.ZERO)) {
|
|
44
|
+
return [numericConstants_1.ZERO, numericConstants_1.ZERO, oldPrice, oldPrice];
|
|
45
|
+
}
|
|
46
|
+
const [acquiredBaseReserve, acquiredQuoteReserve, acquiredQuoteAssetAmount] = calculateTradeAcquiredAmounts(direction, amount, market, inputAssetType, oraclePriceData, useSpread);
|
|
47
|
+
const entryPrice = acquiredQuoteAssetAmount
|
|
48
|
+
.mul(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO)
|
|
49
|
+
.mul(numericConstants_1.MARK_PRICE_PRECISION)
|
|
50
|
+
.div(acquiredBaseReserve.abs());
|
|
51
|
+
let amm;
|
|
52
|
+
if (useSpread && market.amm.baseSpread > 0) {
|
|
53
|
+
const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } = amm_1.calculateUpdatedAMMSpreadReserves(market.amm, direction, oraclePriceData);
|
|
54
|
+
amm = {
|
|
55
|
+
baseAssetReserve,
|
|
56
|
+
quoteAssetReserve,
|
|
57
|
+
sqrtK: sqrtK,
|
|
58
|
+
pegMultiplier: newPeg,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
amm = market.amm;
|
|
63
|
+
}
|
|
64
|
+
const newPrice = amm_1.calculatePrice(amm.baseAssetReserve.sub(acquiredBaseReserve), amm.quoteAssetReserve.sub(acquiredQuoteReserve), amm.pegMultiplier);
|
|
65
|
+
if (direction == types_1.PositionDirection.SHORT) {
|
|
66
|
+
assert_1.assert(newPrice.lte(oldPrice));
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
assert_1.assert(oldPrice.lte(newPrice));
|
|
70
|
+
}
|
|
71
|
+
const pctMaxSlippage = newPrice
|
|
72
|
+
.sub(oldPrice)
|
|
73
|
+
.mul(numericConstants_1.MARK_PRICE_PRECISION)
|
|
74
|
+
.div(oldPrice)
|
|
75
|
+
.abs();
|
|
76
|
+
const pctAvgSlippage = entryPrice
|
|
77
|
+
.sub(oldPrice)
|
|
78
|
+
.mul(numericConstants_1.MARK_PRICE_PRECISION)
|
|
79
|
+
.div(oldPrice)
|
|
80
|
+
.abs();
|
|
81
|
+
return [pctAvgSlippage, pctMaxSlippage, entryPrice, newPrice];
|
|
82
|
+
}
|
|
83
|
+
exports.calculateTradeSlippage = calculateTradeSlippage;
|
|
84
|
+
/**
|
|
85
|
+
* Calculates acquired amounts for trade executed
|
|
86
|
+
* @param direction
|
|
87
|
+
* @param amount
|
|
88
|
+
* @param market
|
|
89
|
+
* @param inputAssetType
|
|
90
|
+
* @param useSpread
|
|
91
|
+
* @return
|
|
92
|
+
* | 'acquiredBase' => positive/negative change in user's base : BN AMM_RESERVE_PRECISION
|
|
93
|
+
* | 'acquiredQuote' => positive/negative change in user's quote : BN TODO-PRECISION
|
|
94
|
+
*/
|
|
95
|
+
function calculateTradeAcquiredAmounts(direction, amount, market, inputAssetType = 'quote', oraclePriceData, useSpread = true) {
|
|
96
|
+
if (amount.eq(numericConstants_1.ZERO)) {
|
|
97
|
+
return [numericConstants_1.ZERO, numericConstants_1.ZERO, numericConstants_1.ZERO];
|
|
98
|
+
}
|
|
99
|
+
const swapDirection = amm_1.getSwapDirection(inputAssetType, direction);
|
|
100
|
+
let amm;
|
|
101
|
+
if (useSpread && market.amm.baseSpread > 0) {
|
|
102
|
+
const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } = amm_1.calculateUpdatedAMMSpreadReserves(market.amm, direction, oraclePriceData);
|
|
103
|
+
amm = {
|
|
104
|
+
baseAssetReserve,
|
|
105
|
+
quoteAssetReserve,
|
|
106
|
+
sqrtK: sqrtK,
|
|
107
|
+
pegMultiplier: newPeg,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
amm = market.amm;
|
|
112
|
+
}
|
|
113
|
+
const [newQuoteAssetReserve, newBaseAssetReserve] = amm_1.calculateAmmReservesAfterSwap(amm, inputAssetType, amount, swapDirection);
|
|
114
|
+
const acquiredBase = amm.baseAssetReserve.sub(newBaseAssetReserve);
|
|
115
|
+
const acquiredQuote = amm.quoteAssetReserve.sub(newQuoteAssetReserve);
|
|
116
|
+
const acquiredQuoteAssetamount = amm_1.calculateQuoteAssetAmountSwapped(acquiredQuote.abs(), amm.pegMultiplier, swapDirection);
|
|
117
|
+
return [acquiredBase, acquiredQuote, acquiredQuoteAssetamount];
|
|
118
|
+
}
|
|
119
|
+
exports.calculateTradeAcquiredAmounts = calculateTradeAcquiredAmounts;
|
|
120
|
+
/**
|
|
121
|
+
* calculateTargetPriceTrade
|
|
122
|
+
* simple function for finding arbitraging trades
|
|
123
|
+
* @param market
|
|
124
|
+
* @param targetPrice
|
|
125
|
+
* @param pct optional default is 100% gap filling, can set smaller.
|
|
126
|
+
* @param outputAssetType which asset to trade.
|
|
127
|
+
* @param useSpread whether or not to consider the spread when calculating the trade size
|
|
128
|
+
* @returns trade direction/size in order to push price to a targetPrice,
|
|
129
|
+
*
|
|
130
|
+
* [
|
|
131
|
+
* direction => direction of trade required, PositionDirection
|
|
132
|
+
* tradeSize => size of trade required, TODO-PRECISION
|
|
133
|
+
* entryPrice => the entry price for the trade, MARK_PRICE_PRECISION
|
|
134
|
+
* targetPrice => the target price MARK_PRICE_PRECISION
|
|
135
|
+
* ]
|
|
136
|
+
*/
|
|
137
|
+
function calculateTargetPriceTrade(market, targetPrice, pct = MAXPCT, outputAssetType = 'quote', oraclePriceData, useSpread = true) {
|
|
138
|
+
assert_1.assert(market.amm.baseAssetReserve.gt(numericConstants_1.ZERO));
|
|
139
|
+
assert_1.assert(targetPrice.gt(numericConstants_1.ZERO));
|
|
140
|
+
assert_1.assert(pct.lte(MAXPCT) && pct.gt(numericConstants_1.ZERO));
|
|
141
|
+
const markPriceBefore = market_1.calculateMarkPrice(market, oraclePriceData);
|
|
142
|
+
const bidPriceBefore = market_1.calculateBidPrice(market, oraclePriceData);
|
|
143
|
+
const askPriceBefore = market_1.calculateAskPrice(market, oraclePriceData);
|
|
144
|
+
let direction;
|
|
145
|
+
if (targetPrice.gt(markPriceBefore)) {
|
|
146
|
+
const priceGap = targetPrice.sub(markPriceBefore);
|
|
147
|
+
const priceGapScaled = priceGap.mul(pct).div(MAXPCT);
|
|
148
|
+
targetPrice = markPriceBefore.add(priceGapScaled);
|
|
149
|
+
direction = types_1.PositionDirection.LONG;
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
const priceGap = markPriceBefore.sub(targetPrice);
|
|
153
|
+
const priceGapScaled = priceGap.mul(pct).div(MAXPCT);
|
|
154
|
+
targetPrice = markPriceBefore.sub(priceGapScaled);
|
|
155
|
+
direction = types_1.PositionDirection.SHORT;
|
|
156
|
+
}
|
|
157
|
+
let tradeSize;
|
|
158
|
+
let baseSize;
|
|
159
|
+
let baseAssetReserveBefore;
|
|
160
|
+
let quoteAssetReserveBefore;
|
|
161
|
+
let peg = market.amm.pegMultiplier;
|
|
162
|
+
if (useSpread && market.amm.baseSpread > 0) {
|
|
163
|
+
const { baseAssetReserve, quoteAssetReserve, newPeg } = amm_1.calculateUpdatedAMMSpreadReserves(market.amm, direction, oraclePriceData);
|
|
164
|
+
baseAssetReserveBefore = baseAssetReserve;
|
|
165
|
+
quoteAssetReserveBefore = quoteAssetReserve;
|
|
166
|
+
peg = newPeg;
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
baseAssetReserveBefore = market.amm.baseAssetReserve;
|
|
170
|
+
quoteAssetReserveBefore = market.amm.quoteAssetReserve;
|
|
171
|
+
}
|
|
172
|
+
const invariant = market.amm.sqrtK.mul(market.amm.sqrtK);
|
|
173
|
+
const k = invariant.mul(numericConstants_1.MARK_PRICE_PRECISION);
|
|
174
|
+
let baseAssetReserveAfter;
|
|
175
|
+
let quoteAssetReserveAfter;
|
|
176
|
+
const biasModifier = new anchor_1.BN(1);
|
|
177
|
+
let markPriceAfter;
|
|
178
|
+
if (useSpread &&
|
|
179
|
+
targetPrice.lt(askPriceBefore) &&
|
|
180
|
+
targetPrice.gt(bidPriceBefore)) {
|
|
181
|
+
// no trade, market is at target
|
|
182
|
+
if (markPriceBefore.gt(targetPrice)) {
|
|
183
|
+
direction = types_1.PositionDirection.SHORT;
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
direction = types_1.PositionDirection.LONG;
|
|
187
|
+
}
|
|
188
|
+
tradeSize = numericConstants_1.ZERO;
|
|
189
|
+
return [direction, tradeSize, targetPrice, targetPrice];
|
|
190
|
+
}
|
|
191
|
+
else if (markPriceBefore.gt(targetPrice)) {
|
|
192
|
+
// overestimate y2
|
|
193
|
+
baseAssetReserveAfter = utils_1.squareRootBN(k.div(targetPrice).mul(peg).div(numericConstants_1.PEG_PRECISION).sub(biasModifier)).sub(new anchor_1.BN(1));
|
|
194
|
+
quoteAssetReserveAfter = k
|
|
195
|
+
.div(numericConstants_1.MARK_PRICE_PRECISION)
|
|
196
|
+
.div(baseAssetReserveAfter);
|
|
197
|
+
markPriceAfter = amm_1.calculatePrice(baseAssetReserveAfter, quoteAssetReserveAfter, peg);
|
|
198
|
+
direction = types_1.PositionDirection.SHORT;
|
|
199
|
+
tradeSize = quoteAssetReserveBefore
|
|
200
|
+
.sub(quoteAssetReserveAfter)
|
|
201
|
+
.mul(peg)
|
|
202
|
+
.div(numericConstants_1.PEG_PRECISION)
|
|
203
|
+
.div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO);
|
|
204
|
+
baseSize = baseAssetReserveAfter.sub(baseAssetReserveBefore);
|
|
205
|
+
}
|
|
206
|
+
else if (markPriceBefore.lt(targetPrice)) {
|
|
207
|
+
// underestimate y2
|
|
208
|
+
baseAssetReserveAfter = utils_1.squareRootBN(k.div(targetPrice).mul(peg).div(numericConstants_1.PEG_PRECISION).add(biasModifier)).add(new anchor_1.BN(1));
|
|
209
|
+
quoteAssetReserveAfter = k
|
|
210
|
+
.div(numericConstants_1.MARK_PRICE_PRECISION)
|
|
211
|
+
.div(baseAssetReserveAfter);
|
|
212
|
+
markPriceAfter = amm_1.calculatePrice(baseAssetReserveAfter, quoteAssetReserveAfter, peg);
|
|
213
|
+
direction = types_1.PositionDirection.LONG;
|
|
214
|
+
tradeSize = quoteAssetReserveAfter
|
|
215
|
+
.sub(quoteAssetReserveBefore)
|
|
216
|
+
.mul(peg)
|
|
217
|
+
.div(numericConstants_1.PEG_PRECISION)
|
|
218
|
+
.div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO);
|
|
219
|
+
baseSize = baseAssetReserveBefore.sub(baseAssetReserveAfter);
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
// no trade, market is at target
|
|
223
|
+
direction = types_1.PositionDirection.LONG;
|
|
224
|
+
tradeSize = numericConstants_1.ZERO;
|
|
225
|
+
return [direction, tradeSize, targetPrice, targetPrice];
|
|
226
|
+
}
|
|
227
|
+
let tp1 = targetPrice;
|
|
228
|
+
let tp2 = markPriceAfter;
|
|
229
|
+
let originalDiff = targetPrice.sub(markPriceBefore);
|
|
230
|
+
if (direction == types_1.PositionDirection.SHORT) {
|
|
231
|
+
tp1 = markPriceAfter;
|
|
232
|
+
tp2 = targetPrice;
|
|
233
|
+
originalDiff = markPriceBefore.sub(targetPrice);
|
|
234
|
+
}
|
|
235
|
+
const entryPrice = tradeSize
|
|
236
|
+
.mul(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO)
|
|
237
|
+
.mul(numericConstants_1.MARK_PRICE_PRECISION)
|
|
238
|
+
.div(baseSize.abs());
|
|
239
|
+
assert_1.assert(tp1.sub(tp2).lte(originalDiff), 'Target Price Calculation incorrect');
|
|
240
|
+
assert_1.assert(tp2.lte(tp1) || tp2.sub(tp1).abs() < 100000, 'Target Price Calculation incorrect' +
|
|
241
|
+
tp2.toString() +
|
|
242
|
+
'>=' +
|
|
243
|
+
tp1.toString() +
|
|
244
|
+
'err: ' +
|
|
245
|
+
tp2.sub(tp1).abs().toString());
|
|
246
|
+
if (outputAssetType == 'quote') {
|
|
247
|
+
return [direction, tradeSize, entryPrice, targetPrice];
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
return [direction, baseSize, entryPrice, targetPrice];
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
exports.calculateTargetPriceTrade = calculateTargetPriceTrade;
|