@drift-labs/sdk 2.0.15 → 2.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/constants/numericConstants.d.ts +1 -0
- package/lib/constants/numericConstants.js +2 -1
- package/lib/math/amm.d.ts +6 -6
- package/lib/math/amm.js +60 -39
- package/lib/math/utils.d.ts +1 -1
- package/package.json +1 -1
- package/src/constants/numericConstants.ts +4 -0
- package/src/math/amm.ts +98 -62
- package/src/math/utils.ts +1 -1
- package/src/events/eventList.js +0 -77
|
@@ -56,3 +56,4 @@ export declare const QUOTE_SPOT_MARKET_INDEX = 0;
|
|
|
56
56
|
export declare const LAMPORTS_PRECISION: BN;
|
|
57
57
|
export declare const LAMPORTS_EXP: BN;
|
|
58
58
|
export declare const OPEN_ORDER_MARGIN_REQUIREMENT: BN;
|
|
59
|
+
export declare const DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT: BN;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BID_ASK_SPREAD_PRECISION = exports.MARGIN_PRECISION = exports.AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO = exports.PRICE_TO_QUOTE_PRECISION = exports.PRICE_DIV_PEG = exports.AMM_TO_QUOTE_PRECISION_RATIO = exports.BASE_PRECISION_EXP = exports.BASE_PRECISION = exports.AMM_RESERVE_PRECISION = exports.PEG_PRECISION = exports.FUNDING_RATE_BUFFER_PRECISION = exports.FUNDING_RATE_PRECISION = exports.PRICE_PRECISION = exports.QUOTE_PRECISION = exports.LIQUIDATION_FEE_PRECISION = exports.SPOT_MARKET_IMF_PRECISION = exports.SPOT_MARKET_IMF_PRECISION_EXP = exports.SPOT_MARKET_BALANCE_PRECISION = exports.SPOT_MARKET_BALANCE_PRECISION_EXP = exports.SPOT_MARKET_WEIGHT_PRECISION = exports.SPOT_MARKET_UTILIZATION_PRECISION = exports.SPOT_MARKET_UTILIZATION_PRECISION_EXP = exports.SPOT_MARKET_CUMULATIVE_INTEREST_PRECISION = exports.SPOT_MARKET_CUMULATIVE_INTEREST_PRECISION_EXP = exports.SPOT_MARKET_RATE_PRECISION = exports.SPOT_MARKET_RATE_PRECISION_EXP = exports.AMM_RESERVE_PRECISION_EXP = exports.PEG_PRECISION_EXP = exports.FUNDING_RATE_PRECISION_EXP = exports.PRICE_PRECISION_EXP = exports.FUNDING_RATE_BUFFER_PRECISION_EXP = exports.QUOTE_PRECISION_EXP = exports.CONCENTRATION_PRECISION = exports.PERCENTAGE_PRECISION = exports.PERCENTAGE_PRECISION_EXP = exports.MAX_LEVERAGE = exports.TEN_MILLION = exports.BN_MAX = exports.TEN_THOUSAND = exports.TEN = exports.NINE = exports.EIGHT = exports.SEVEN = exports.SIX = exports.FIVE = exports.FOUR = exports.THREE = exports.TWO = exports.ONE = exports.ZERO = void 0;
|
|
4
|
-
exports.OPEN_ORDER_MARGIN_REQUIREMENT = exports.LAMPORTS_EXP = exports.LAMPORTS_PRECISION = exports.QUOTE_SPOT_MARKET_INDEX = exports.ONE_YEAR = exports.LIQUIDATION_PCT_PRECISION = void 0;
|
|
4
|
+
exports.DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT = exports.OPEN_ORDER_MARGIN_REQUIREMENT = exports.LAMPORTS_EXP = exports.LAMPORTS_PRECISION = exports.QUOTE_SPOT_MARKET_INDEX = exports.ONE_YEAR = exports.LIQUIDATION_PCT_PRECISION = void 0;
|
|
5
5
|
const web3_js_1 = require("@solana/web3.js");
|
|
6
6
|
const __1 = require("../");
|
|
7
7
|
exports.ZERO = new __1.BN(0);
|
|
@@ -60,3 +60,4 @@ exports.QUOTE_SPOT_MARKET_INDEX = 0;
|
|
|
60
60
|
exports.LAMPORTS_PRECISION = new __1.BN(web3_js_1.LAMPORTS_PER_SOL);
|
|
61
61
|
exports.LAMPORTS_EXP = new __1.BN(Math.log10(web3_js_1.LAMPORTS_PER_SOL));
|
|
62
62
|
exports.OPEN_ORDER_MARGIN_REQUIREMENT = exports.QUOTE_PRECISION.div(new __1.BN(100));
|
|
63
|
+
exports.DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT = new __1.BN(-25).mul(exports.QUOTE_PRECISION);
|
package/lib/math/amm.d.ts
CHANGED
|
@@ -38,12 +38,12 @@ export declare function calculateInventoryScale(baseAssetAmountWithAmm: BN, base
|
|
|
38
38
|
export declare function calculateEffectiveLeverage(baseSpread: number, quoteAssetReserve: BN, terminalQuoteAssetReserve: BN, pegMultiplier: BN, netBaseAssetAmount: BN, reservePrice: BN, totalFeeMinusDistributions: BN): number;
|
|
39
39
|
export declare function calculateMaxSpread(marginRatioInitial: number): number;
|
|
40
40
|
export declare function calculateVolSpreadBN(lastOracleConfPct: BN, reservePrice: BN, markStd: BN, oracleStd: BN, longIntensity: BN, shortIntensity: BN, volume24H: BN): [BN, BN];
|
|
41
|
-
export declare function calculateSpreadBN(baseSpread: number, lastOracleReservePriceSpreadPct: BN, lastOracleConfPct: BN, maxSpread: number, quoteAssetReserve: BN, terminalQuoteAssetReserve: BN, pegMultiplier: BN, baseAssetAmountWithAmm: BN, reservePrice: BN, totalFeeMinusDistributions: BN, baseAssetReserve: BN, minBaseAssetReserve: BN, maxBaseAssetReserve: BN, markStd: BN, oracleStd: BN, longIntensity: BN, shortIntensity: BN, volume24H: BN): [number, number];
|
|
42
|
-
export declare function calculateSpread(amm: AMM,
|
|
43
|
-
export declare function calculateSpreadReserves(amm: AMM,
|
|
44
|
-
baseAssetReserve:
|
|
45
|
-
quoteAssetReserve:
|
|
46
|
-
};
|
|
41
|
+
export declare function calculateSpreadBN(baseSpread: number, lastOracleReservePriceSpreadPct: BN, lastOracleConfPct: BN, maxSpread: number, quoteAssetReserve: BN, terminalQuoteAssetReserve: BN, pegMultiplier: BN, baseAssetAmountWithAmm: BN, reservePrice: BN, totalFeeMinusDistributions: BN, netRevenueSinceLastFunding: BN, baseAssetReserve: BN, minBaseAssetReserve: BN, maxBaseAssetReserve: BN, markStd: BN, oracleStd: BN, longIntensity: BN, shortIntensity: BN, volume24H: BN): [number, number];
|
|
42
|
+
export declare function calculateSpread(amm: AMM, oraclePriceData: OraclePriceData): [number, number];
|
|
43
|
+
export declare function calculateSpreadReserves(amm: AMM, oraclePriceData: OraclePriceData): {
|
|
44
|
+
baseAssetReserve: any;
|
|
45
|
+
quoteAssetReserve: any;
|
|
46
|
+
}[];
|
|
47
47
|
/**
|
|
48
48
|
* Helper function calculating constant product curve output. Agnostic to whether input asset is quote or base
|
|
49
49
|
*
|
package/lib/math/amm.js
CHANGED
|
@@ -100,7 +100,10 @@ function calculateUpdatedAMM(amm, oraclePriceData) {
|
|
|
100
100
|
exports.calculateUpdatedAMM = calculateUpdatedAMM;
|
|
101
101
|
function calculateUpdatedAMMSpreadReserves(amm, direction, oraclePriceData) {
|
|
102
102
|
const newAmm = calculateUpdatedAMM(amm, oraclePriceData);
|
|
103
|
-
const
|
|
103
|
+
const [shortReserves, longReserves] = calculateSpreadReserves(newAmm, oraclePriceData);
|
|
104
|
+
const dirReserves = (0, types_1.isVariant)(direction, 'long')
|
|
105
|
+
? longReserves
|
|
106
|
+
: shortReserves;
|
|
104
107
|
const result = {
|
|
105
108
|
baseAssetReserve: dirReserves.baseAssetReserve,
|
|
106
109
|
quoteAssetReserve: dirReserves.quoteAssetReserve,
|
|
@@ -118,8 +121,7 @@ function calculateBidAskPrice(amm, oraclePriceData, withUpdate = true) {
|
|
|
118
121
|
else {
|
|
119
122
|
newAmm = amm;
|
|
120
123
|
}
|
|
121
|
-
const askReserves = calculateSpreadReserves(newAmm,
|
|
122
|
-
const bidReserves = calculateSpreadReserves(newAmm, types_1.PositionDirection.SHORT, oraclePriceData);
|
|
124
|
+
const [bidReserves, askReserves] = calculateSpreadReserves(newAmm, oraclePriceData);
|
|
123
125
|
const askPrice = calculatePrice(askReserves.baseAssetReserve, askReserves.quoteAssetReserve, newAmm.pegMultiplier);
|
|
124
126
|
const bidPrice = calculatePrice(bidReserves.baseAssetReserve, bidReserves.quoteAssetReserve, newAmm.pegMultiplier);
|
|
125
127
|
return [bidPrice, askPrice];
|
|
@@ -236,10 +238,11 @@ function calculateVolSpreadBN(lastOracleConfPct, reservePrice, markStd, oracleSt
|
|
|
236
238
|
const marketAvgStdPct = markStd
|
|
237
239
|
.add(oracleStd)
|
|
238
240
|
.mul(numericConstants_1.PERCENTAGE_PRECISION)
|
|
239
|
-
.div(reservePrice
|
|
241
|
+
.div(reservePrice)
|
|
242
|
+
.div(new anchor_1.BN(2));
|
|
240
243
|
const volSpread = anchor_1.BN.max(lastOracleConfPct, marketAvgStdPct.div(new anchor_1.BN(2)));
|
|
244
|
+
const clampMin = numericConstants_1.PERCENTAGE_PRECISION.div(new anchor_1.BN(100));
|
|
241
245
|
const clampMax = numericConstants_1.PERCENTAGE_PRECISION.mul(new anchor_1.BN(16)).div(new anchor_1.BN(10));
|
|
242
|
-
const clampMin = numericConstants_1.PERCENTAGE_PRECISION.div(new anchor_1.BN(10));
|
|
243
246
|
const longVolSpreadFactor = (0, __1.clampBN)(longIntensity.mul(numericConstants_1.PERCENTAGE_PRECISION).div(anchor_1.BN.max(numericConstants_1.ONE, volume24H)), clampMin, clampMax);
|
|
244
247
|
const shortVolSpreadFactor = (0, __1.clampBN)(shortIntensity.mul(numericConstants_1.PERCENTAGE_PRECISION).div(anchor_1.BN.max(numericConstants_1.ONE, volume24H)), clampMin, clampMax);
|
|
245
248
|
const longVolSpread = anchor_1.BN.max(lastOracleConfPct, volSpread.mul(longVolSpreadFactor).div(numericConstants_1.PERCENTAGE_PRECISION));
|
|
@@ -247,7 +250,7 @@ function calculateVolSpreadBN(lastOracleConfPct, reservePrice, markStd, oracleSt
|
|
|
247
250
|
return [longVolSpread, shortVolSpread];
|
|
248
251
|
}
|
|
249
252
|
exports.calculateVolSpreadBN = calculateVolSpreadBN;
|
|
250
|
-
function calculateSpreadBN(baseSpread, lastOracleReservePriceSpreadPct, lastOracleConfPct, maxSpread, quoteAssetReserve, terminalQuoteAssetReserve, pegMultiplier, baseAssetAmountWithAmm, reservePrice, totalFeeMinusDistributions, baseAssetReserve, minBaseAssetReserve, maxBaseAssetReserve, markStd, oracleStd, longIntensity, shortIntensity, volume24H) {
|
|
253
|
+
function calculateSpreadBN(baseSpread, lastOracleReservePriceSpreadPct, lastOracleConfPct, maxSpread, quoteAssetReserve, terminalQuoteAssetReserve, pegMultiplier, baseAssetAmountWithAmm, reservePrice, totalFeeMinusDistributions, netRevenueSinceLastFunding, baseAssetReserve, minBaseAssetReserve, maxBaseAssetReserve, markStd, oracleStd, longIntensity, shortIntensity, volume24H) {
|
|
251
254
|
const [longVolSpread, shortVolSpread] = calculateVolSpreadBN(lastOracleConfPct, reservePrice, markStd, oracleStd, longIntensity, shortIntensity, volume24H);
|
|
252
255
|
let longSpread = Math.max(baseSpread / 2, longVolSpread.toNumber());
|
|
253
256
|
let shortSpread = Math.max(baseSpread / 2, shortVolSpread.toNumber());
|
|
@@ -267,9 +270,9 @@ function calculateSpreadBN(baseSpread, lastOracleReservePriceSpreadPct, lastOrac
|
|
|
267
270
|
else if (baseAssetAmountWithAmm.lt(numericConstants_1.ZERO)) {
|
|
268
271
|
shortSpread *= inventorySpreadScale;
|
|
269
272
|
}
|
|
270
|
-
const effectiveLeverage = calculateEffectiveLeverage(baseSpread, quoteAssetReserve, terminalQuoteAssetReserve, pegMultiplier, baseAssetAmountWithAmm, reservePrice, totalFeeMinusDistributions);
|
|
271
273
|
const MAX_SPREAD_SCALE = 10;
|
|
272
274
|
if (totalFeeMinusDistributions.gt(numericConstants_1.ZERO)) {
|
|
275
|
+
const effectiveLeverage = calculateEffectiveLeverage(baseSpread, quoteAssetReserve, terminalQuoteAssetReserve, pegMultiplier, baseAssetAmountWithAmm, reservePrice, totalFeeMinusDistributions);
|
|
273
276
|
const spreadScale = Math.min(MAX_SPREAD_SCALE, 1 + effectiveLeverage);
|
|
274
277
|
if (baseAssetAmountWithAmm.gt(numericConstants_1.ZERO)) {
|
|
275
278
|
longSpread *= spreadScale;
|
|
@@ -282,23 +285,40 @@ function calculateSpreadBN(baseSpread, lastOracleReservePriceSpreadPct, lastOrac
|
|
|
282
285
|
longSpread *= MAX_SPREAD_SCALE;
|
|
283
286
|
shortSpread *= MAX_SPREAD_SCALE;
|
|
284
287
|
}
|
|
288
|
+
if (netRevenueSinceLastFunding.lt(numericConstants_1.DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT)) {
|
|
289
|
+
const retreatAmount = Math.min(maxTargetSpread / 10, Math.floor((baseSpread * netRevenueSinceLastFunding.abs().toNumber()) /
|
|
290
|
+
numericConstants_1.DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT.toNumber()));
|
|
291
|
+
const halfRetreatAmount = Math.floor(retreatAmount / 2);
|
|
292
|
+
if (baseAssetAmountWithAmm.gt(numericConstants_1.ZERO)) {
|
|
293
|
+
longSpread += retreatAmount;
|
|
294
|
+
shortSpread += halfRetreatAmount;
|
|
295
|
+
}
|
|
296
|
+
else if (baseAssetAmountWithAmm.lt(numericConstants_1.ZERO)) {
|
|
297
|
+
longSpread += halfRetreatAmount;
|
|
298
|
+
shortSpread += retreatAmount;
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
longSpread += halfRetreatAmount;
|
|
302
|
+
shortSpread += halfRetreatAmount;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
285
305
|
const totalSpread = longSpread + shortSpread;
|
|
286
306
|
if (totalSpread > maxTargetSpread) {
|
|
287
307
|
if (longSpread > shortSpread) {
|
|
288
|
-
longSpread = Math.
|
|
308
|
+
longSpread = Math.ceil((longSpread * maxTargetSpread) / totalSpread);
|
|
289
309
|
shortSpread = maxTargetSpread - longSpread;
|
|
290
310
|
}
|
|
291
311
|
else {
|
|
292
|
-
shortSpread = Math.
|
|
312
|
+
shortSpread = Math.ceil((shortSpread * maxTargetSpread) / totalSpread);
|
|
293
313
|
longSpread = maxTargetSpread - shortSpread;
|
|
294
314
|
}
|
|
295
315
|
}
|
|
296
316
|
return [longSpread, shortSpread];
|
|
297
317
|
}
|
|
298
318
|
exports.calculateSpreadBN = calculateSpreadBN;
|
|
299
|
-
function calculateSpread(amm,
|
|
319
|
+
function calculateSpread(amm, oraclePriceData) {
|
|
300
320
|
if (amm.baseSpread == 0 || amm.curveUpdateIntensity == 0) {
|
|
301
|
-
return amm.baseSpread / 2;
|
|
321
|
+
return [amm.baseSpread / 2, amm.baseSpread / 2];
|
|
302
322
|
}
|
|
303
323
|
const reservePrice = calculatePrice(amm.baseAssetReserve, amm.quoteAssetReserve, amm.pegMultiplier);
|
|
304
324
|
const targetPrice = (oraclePriceData === null || oraclePriceData === void 0 ? void 0 : oraclePriceData.price) || reservePrice;
|
|
@@ -312,38 +332,36 @@ function calculateSpread(amm, direction, oraclePriceData) {
|
|
|
312
332
|
.div(reservePrice);
|
|
313
333
|
const now = new anchor_1.BN(new Date().getTime() / 1000); //todo
|
|
314
334
|
const liveOracleStd = (0, oracles_1.calculateLiveOracleStd)(amm, oraclePriceData, now);
|
|
315
|
-
const [longSpread, shortSpread] = calculateSpreadBN(amm.baseSpread, targetMarkSpreadPct, confIntervalPct, amm.maxSpread, amm.quoteAssetReserve, amm.terminalQuoteAssetReserve, amm.pegMultiplier, amm.baseAssetAmountWithAmm, reservePrice, amm.totalFeeMinusDistributions, amm.baseAssetReserve, amm.minBaseAssetReserve, amm.maxBaseAssetReserve, amm.markStd, liveOracleStd, amm.longIntensityVolume, amm.shortIntensityVolume, amm.volume24H);
|
|
316
|
-
|
|
317
|
-
if ((0, types_1.isVariant)(direction, 'long')) {
|
|
318
|
-
spread = longSpread;
|
|
319
|
-
}
|
|
320
|
-
else {
|
|
321
|
-
spread = shortSpread;
|
|
322
|
-
}
|
|
323
|
-
return spread;
|
|
335
|
+
const [longSpread, shortSpread] = calculateSpreadBN(amm.baseSpread, targetMarkSpreadPct, confIntervalPct, amm.maxSpread, amm.quoteAssetReserve, amm.terminalQuoteAssetReserve, amm.pegMultiplier, amm.baseAssetAmountWithAmm, reservePrice, amm.totalFeeMinusDistributions, amm.netRevenueSinceLastFunding, amm.baseAssetReserve, amm.minBaseAssetReserve, amm.maxBaseAssetReserve, amm.markStd, liveOracleStd, amm.longIntensityVolume, amm.shortIntensityVolume, amm.volume24H);
|
|
336
|
+
return [longSpread, shortSpread];
|
|
324
337
|
}
|
|
325
338
|
exports.calculateSpread = calculateSpread;
|
|
326
|
-
function calculateSpreadReserves(amm,
|
|
327
|
-
|
|
328
|
-
|
|
339
|
+
function calculateSpreadReserves(amm, oraclePriceData) {
|
|
340
|
+
function calculateSpreadReserve(spread, direction, amm) {
|
|
341
|
+
if (spread === 0) {
|
|
342
|
+
return {
|
|
343
|
+
baseAssetReserve: amm.baseAssetReserve,
|
|
344
|
+
quoteAssetReserve: amm.quoteAssetReserve,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
const quoteAssetReserveDelta = amm.quoteAssetReserve.div(numericConstants_1.BID_ASK_SPREAD_PRECISION.div(new anchor_1.BN(spread / 2)));
|
|
348
|
+
let quoteAssetReserve;
|
|
349
|
+
if ((0, types_1.isVariant)(direction, 'long')) {
|
|
350
|
+
quoteAssetReserve = amm.quoteAssetReserve.add(quoteAssetReserveDelta);
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
quoteAssetReserve = amm.quoteAssetReserve.sub(quoteAssetReserveDelta);
|
|
354
|
+
}
|
|
355
|
+
const baseAssetReserve = amm.sqrtK.mul(amm.sqrtK).div(quoteAssetReserve);
|
|
329
356
|
return {
|
|
330
|
-
baseAssetReserve
|
|
331
|
-
quoteAssetReserve
|
|
357
|
+
baseAssetReserve,
|
|
358
|
+
quoteAssetReserve,
|
|
332
359
|
};
|
|
333
360
|
}
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
}
|
|
339
|
-
else {
|
|
340
|
-
quoteAssetReserve = amm.quoteAssetReserve.sub(quoteAsserReserveDelta);
|
|
341
|
-
}
|
|
342
|
-
const baseAssetReserve = amm.sqrtK.mul(amm.sqrtK).div(quoteAssetReserve);
|
|
343
|
-
return {
|
|
344
|
-
baseAssetReserve,
|
|
345
|
-
quoteAssetReserve,
|
|
346
|
-
};
|
|
361
|
+
const [longSpread, shortSpread] = calculateSpread(amm, oraclePriceData);
|
|
362
|
+
const askReserves = calculateSpreadReserve(longSpread, types_1.PositionDirection.LONG, amm);
|
|
363
|
+
const bidReserves = calculateSpreadReserve(shortSpread, types_1.PositionDirection.SHORT, amm);
|
|
364
|
+
return [bidReserves, askReserves];
|
|
347
365
|
}
|
|
348
366
|
exports.calculateSpreadReserves = calculateSpreadReserves;
|
|
349
367
|
/**
|
|
@@ -410,7 +428,10 @@ function calculateMaxBaseAssetAmountToTrade(amm, limit_price, direction, oracleP
|
|
|
410
428
|
.div(limit_price)
|
|
411
429
|
.div(numericConstants_1.PEG_PRECISION);
|
|
412
430
|
const newBaseAssetReserve = (0, __1.squareRootBN)(newBaseAssetReserveSquared);
|
|
413
|
-
const
|
|
431
|
+
const [shortSpreadReserves, longSpreadReserves] = calculateSpreadReserves(amm, oraclePriceData);
|
|
432
|
+
const baseAssetReserveBefore = (0, types_1.isVariant)(direction, 'long')
|
|
433
|
+
? longSpreadReserves.baseAssetReserve
|
|
434
|
+
: shortSpreadReserves.baseAssetReserve;
|
|
414
435
|
if (newBaseAssetReserve.gt(baseAssetReserveBefore)) {
|
|
415
436
|
return [
|
|
416
437
|
newBaseAssetReserve.sub(baseAssetReserveBefore),
|
package/lib/math/utils.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -91,3 +91,7 @@ export const LAMPORTS_PRECISION = new BN(LAMPORTS_PER_SOL);
|
|
|
91
91
|
export const LAMPORTS_EXP = new BN(Math.log10(LAMPORTS_PER_SOL));
|
|
92
92
|
|
|
93
93
|
export const OPEN_ORDER_MARGIN_REQUIREMENT = QUOTE_PRECISION.div(new BN(100));
|
|
94
|
+
|
|
95
|
+
export const DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT = new BN(
|
|
96
|
+
-25
|
|
97
|
+
).mul(QUOTE_PRECISION);
|
package/src/math/amm.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
PRICE_DIV_PEG,
|
|
13
13
|
PERCENTAGE_PRECISION,
|
|
14
14
|
BASE_PRECISION,
|
|
15
|
+
DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT,
|
|
15
16
|
} from '../constants/numericConstants';
|
|
16
17
|
import {
|
|
17
18
|
AMM,
|
|
@@ -190,11 +191,15 @@ export function calculateUpdatedAMMSpreadReserves(
|
|
|
190
191
|
oraclePriceData: OraclePriceData
|
|
191
192
|
): { baseAssetReserve: BN; quoteAssetReserve: BN; sqrtK: BN; newPeg: BN } {
|
|
192
193
|
const newAmm = calculateUpdatedAMM(amm, oraclePriceData);
|
|
193
|
-
const
|
|
194
|
+
const [shortReserves, longReserves] = calculateSpreadReserves(
|
|
194
195
|
newAmm,
|
|
195
|
-
direction,
|
|
196
196
|
oraclePriceData
|
|
197
197
|
);
|
|
198
|
+
|
|
199
|
+
const dirReserves = isVariant(direction, 'long')
|
|
200
|
+
? longReserves
|
|
201
|
+
: shortReserves;
|
|
202
|
+
|
|
198
203
|
const result = {
|
|
199
204
|
baseAssetReserve: dirReserves.baseAssetReserve,
|
|
200
205
|
quoteAssetReserve: dirReserves.quoteAssetReserve,
|
|
@@ -217,14 +222,8 @@ export function calculateBidAskPrice(
|
|
|
217
222
|
newAmm = amm;
|
|
218
223
|
}
|
|
219
224
|
|
|
220
|
-
const askReserves = calculateSpreadReserves(
|
|
225
|
+
const [bidReserves, askReserves] = calculateSpreadReserves(
|
|
221
226
|
newAmm,
|
|
222
|
-
PositionDirection.LONG,
|
|
223
|
-
oraclePriceData
|
|
224
|
-
);
|
|
225
|
-
const bidReserves = calculateSpreadReserves(
|
|
226
|
-
newAmm,
|
|
227
|
-
PositionDirection.SHORT,
|
|
228
227
|
oraclePriceData
|
|
229
228
|
);
|
|
230
229
|
|
|
@@ -431,11 +430,12 @@ export function calculateVolSpreadBN(
|
|
|
431
430
|
const marketAvgStdPct = markStd
|
|
432
431
|
.add(oracleStd)
|
|
433
432
|
.mul(PERCENTAGE_PRECISION)
|
|
434
|
-
.div(reservePrice
|
|
433
|
+
.div(reservePrice)
|
|
434
|
+
.div(new BN(2));
|
|
435
435
|
const volSpread = BN.max(lastOracleConfPct, marketAvgStdPct.div(new BN(2)));
|
|
436
436
|
|
|
437
|
+
const clampMin = PERCENTAGE_PRECISION.div(new BN(100));
|
|
437
438
|
const clampMax = PERCENTAGE_PRECISION.mul(new BN(16)).div(new BN(10));
|
|
438
|
-
const clampMin = PERCENTAGE_PRECISION.div(new BN(10));
|
|
439
439
|
|
|
440
440
|
const longVolSpreadFactor = clampBN(
|
|
441
441
|
longIntensity.mul(PERCENTAGE_PRECISION).div(BN.max(ONE, volume24H)),
|
|
@@ -471,6 +471,7 @@ export function calculateSpreadBN(
|
|
|
471
471
|
baseAssetAmountWithAmm: BN,
|
|
472
472
|
reservePrice: BN,
|
|
473
473
|
totalFeeMinusDistributions: BN,
|
|
474
|
+
netRevenueSinceLastFunding: BN,
|
|
474
475
|
baseAssetReserve: BN,
|
|
475
476
|
minBaseAssetReserve: BN,
|
|
476
477
|
maxBaseAssetReserve: BN,
|
|
@@ -527,18 +528,17 @@ export function calculateSpreadBN(
|
|
|
527
528
|
shortSpread *= inventorySpreadScale;
|
|
528
529
|
}
|
|
529
530
|
|
|
530
|
-
const effectiveLeverage = calculateEffectiveLeverage(
|
|
531
|
-
baseSpread,
|
|
532
|
-
quoteAssetReserve,
|
|
533
|
-
terminalQuoteAssetReserve,
|
|
534
|
-
pegMultiplier,
|
|
535
|
-
baseAssetAmountWithAmm,
|
|
536
|
-
reservePrice,
|
|
537
|
-
totalFeeMinusDistributions
|
|
538
|
-
);
|
|
539
|
-
|
|
540
531
|
const MAX_SPREAD_SCALE = 10;
|
|
541
532
|
if (totalFeeMinusDistributions.gt(ZERO)) {
|
|
533
|
+
const effectiveLeverage = calculateEffectiveLeverage(
|
|
534
|
+
baseSpread,
|
|
535
|
+
quoteAssetReserve,
|
|
536
|
+
terminalQuoteAssetReserve,
|
|
537
|
+
pegMultiplier,
|
|
538
|
+
baseAssetAmountWithAmm,
|
|
539
|
+
reservePrice,
|
|
540
|
+
totalFeeMinusDistributions
|
|
541
|
+
);
|
|
542
542
|
const spreadScale = Math.min(MAX_SPREAD_SCALE, 1 + effectiveLeverage);
|
|
543
543
|
if (baseAssetAmountWithAmm.gt(ZERO)) {
|
|
544
544
|
longSpread *= spreadScale;
|
|
@@ -550,13 +550,38 @@ export function calculateSpreadBN(
|
|
|
550
550
|
shortSpread *= MAX_SPREAD_SCALE;
|
|
551
551
|
}
|
|
552
552
|
|
|
553
|
+
if (
|
|
554
|
+
netRevenueSinceLastFunding.lt(
|
|
555
|
+
DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT
|
|
556
|
+
)
|
|
557
|
+
) {
|
|
558
|
+
const retreatAmount = Math.min(
|
|
559
|
+
maxTargetSpread / 10,
|
|
560
|
+
Math.floor(
|
|
561
|
+
(baseSpread * netRevenueSinceLastFunding.abs().toNumber()) /
|
|
562
|
+
DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT.toNumber()
|
|
563
|
+
)
|
|
564
|
+
);
|
|
565
|
+
const halfRetreatAmount = Math.floor(retreatAmount / 2);
|
|
566
|
+
if (baseAssetAmountWithAmm.gt(ZERO)) {
|
|
567
|
+
longSpread += retreatAmount;
|
|
568
|
+
shortSpread += halfRetreatAmount;
|
|
569
|
+
} else if (baseAssetAmountWithAmm.lt(ZERO)) {
|
|
570
|
+
longSpread += halfRetreatAmount;
|
|
571
|
+
shortSpread += retreatAmount;
|
|
572
|
+
} else {
|
|
573
|
+
longSpread += halfRetreatAmount;
|
|
574
|
+
shortSpread += halfRetreatAmount;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
553
578
|
const totalSpread = longSpread + shortSpread;
|
|
554
579
|
if (totalSpread > maxTargetSpread) {
|
|
555
580
|
if (longSpread > shortSpread) {
|
|
556
|
-
longSpread = Math.
|
|
581
|
+
longSpread = Math.ceil((longSpread * maxTargetSpread) / totalSpread);
|
|
557
582
|
shortSpread = maxTargetSpread - longSpread;
|
|
558
583
|
} else {
|
|
559
|
-
shortSpread = Math.
|
|
584
|
+
shortSpread = Math.ceil((shortSpread * maxTargetSpread) / totalSpread);
|
|
560
585
|
longSpread = maxTargetSpread - shortSpread;
|
|
561
586
|
}
|
|
562
587
|
}
|
|
@@ -566,11 +591,10 @@ export function calculateSpreadBN(
|
|
|
566
591
|
|
|
567
592
|
export function calculateSpread(
|
|
568
593
|
amm: AMM,
|
|
569
|
-
direction: PositionDirection,
|
|
570
594
|
oraclePriceData: OraclePriceData
|
|
571
|
-
): number {
|
|
595
|
+
): [number, number] {
|
|
572
596
|
if (amm.baseSpread == 0 || amm.curveUpdateIntensity == 0) {
|
|
573
|
-
return amm.baseSpread / 2;
|
|
597
|
+
return [amm.baseSpread / 2, amm.baseSpread / 2];
|
|
574
598
|
}
|
|
575
599
|
|
|
576
600
|
const reservePrice = calculatePrice(
|
|
@@ -604,6 +628,7 @@ export function calculateSpread(
|
|
|
604
628
|
amm.baseAssetAmountWithAmm,
|
|
605
629
|
reservePrice,
|
|
606
630
|
amm.totalFeeMinusDistributions,
|
|
631
|
+
amm.netRevenueSinceLastFunding,
|
|
607
632
|
amm.baseAssetReserve,
|
|
608
633
|
amm.minBaseAssetReserve,
|
|
609
634
|
amm.maxBaseAssetReserve,
|
|
@@ -614,50 +639,59 @@ export function calculateSpread(
|
|
|
614
639
|
amm.volume24H
|
|
615
640
|
);
|
|
616
641
|
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
if (isVariant(direction, 'long')) {
|
|
620
|
-
spread = longSpread;
|
|
621
|
-
} else {
|
|
622
|
-
spread = shortSpread;
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
return spread;
|
|
642
|
+
return [longSpread, shortSpread];
|
|
626
643
|
}
|
|
627
644
|
|
|
628
645
|
export function calculateSpreadReserves(
|
|
629
646
|
amm: AMM,
|
|
630
|
-
direction: PositionDirection,
|
|
631
647
|
oraclePriceData: OraclePriceData
|
|
632
|
-
)
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
648
|
+
) {
|
|
649
|
+
function calculateSpreadReserve(
|
|
650
|
+
spread: number,
|
|
651
|
+
direction: PositionDirection,
|
|
652
|
+
amm: AMM
|
|
653
|
+
): {
|
|
654
|
+
baseAssetReserve;
|
|
655
|
+
quoteAssetReserve;
|
|
656
|
+
} {
|
|
657
|
+
if (spread === 0) {
|
|
658
|
+
return {
|
|
659
|
+
baseAssetReserve: amm.baseAssetReserve,
|
|
660
|
+
quoteAssetReserve: amm.quoteAssetReserve,
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
const quoteAssetReserveDelta = amm.quoteAssetReserve.div(
|
|
665
|
+
BID_ASK_SPREAD_PRECISION.div(new BN(spread / 2))
|
|
666
|
+
);
|
|
667
|
+
|
|
668
|
+
let quoteAssetReserve;
|
|
669
|
+
if (isVariant(direction, 'long')) {
|
|
670
|
+
quoteAssetReserve = amm.quoteAssetReserve.add(quoteAssetReserveDelta);
|
|
671
|
+
} else {
|
|
672
|
+
quoteAssetReserve = amm.quoteAssetReserve.sub(quoteAssetReserveDelta);
|
|
673
|
+
}
|
|
637
674
|
|
|
638
|
-
|
|
675
|
+
const baseAssetReserve = amm.sqrtK.mul(amm.sqrtK).div(quoteAssetReserve);
|
|
639
676
|
return {
|
|
640
|
-
baseAssetReserve
|
|
641
|
-
quoteAssetReserve
|
|
677
|
+
baseAssetReserve,
|
|
678
|
+
quoteAssetReserve,
|
|
642
679
|
};
|
|
643
680
|
}
|
|
644
681
|
|
|
645
|
-
const
|
|
646
|
-
|
|
682
|
+
const [longSpread, shortSpread] = calculateSpread(amm, oraclePriceData);
|
|
683
|
+
const askReserves = calculateSpreadReserve(
|
|
684
|
+
longSpread,
|
|
685
|
+
PositionDirection.LONG,
|
|
686
|
+
amm
|
|
687
|
+
);
|
|
688
|
+
const bidReserves = calculateSpreadReserve(
|
|
689
|
+
shortSpread,
|
|
690
|
+
PositionDirection.SHORT,
|
|
691
|
+
amm
|
|
647
692
|
);
|
|
648
693
|
|
|
649
|
-
|
|
650
|
-
if (isVariant(direction, 'long')) {
|
|
651
|
-
quoteAssetReserve = amm.quoteAssetReserve.add(quoteAsserReserveDelta);
|
|
652
|
-
} else {
|
|
653
|
-
quoteAssetReserve = amm.quoteAssetReserve.sub(quoteAsserReserveDelta);
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
const baseAssetReserve = amm.sqrtK.mul(amm.sqrtK).div(quoteAssetReserve);
|
|
657
|
-
return {
|
|
658
|
-
baseAssetReserve,
|
|
659
|
-
quoteAssetReserve,
|
|
660
|
-
};
|
|
694
|
+
return [bidReserves, askReserves];
|
|
661
695
|
}
|
|
662
696
|
|
|
663
697
|
/**
|
|
@@ -749,12 +783,14 @@ export function calculateMaxBaseAssetAmountToTrade(
|
|
|
749
783
|
.div(PEG_PRECISION);
|
|
750
784
|
|
|
751
785
|
const newBaseAssetReserve = squareRootBN(newBaseAssetReserveSquared);
|
|
752
|
-
|
|
753
|
-
const baseAssetReserveBefore = calculateSpreadReserves(
|
|
786
|
+
const [shortSpreadReserves, longSpreadReserves] = calculateSpreadReserves(
|
|
754
787
|
amm,
|
|
755
|
-
direction,
|
|
756
788
|
oraclePriceData
|
|
757
|
-
)
|
|
789
|
+
);
|
|
790
|
+
|
|
791
|
+
const baseAssetReserveBefore: BN = isVariant(direction, 'long')
|
|
792
|
+
? longSpreadReserves.baseAssetReserve
|
|
793
|
+
: shortSpreadReserves.baseAssetReserve;
|
|
758
794
|
|
|
759
795
|
if (newBaseAssetReserve.gt(baseAssetReserveBefore)) {
|
|
760
796
|
return [
|
package/src/math/utils.ts
CHANGED
|
@@ -4,7 +4,7 @@ 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
|
-
export const squareRootBN = (n, closeness = new BN(1)) => {
|
|
7
|
+
export const squareRootBN = (n, closeness = new BN(1)): BN => {
|
|
8
8
|
// Assuming the sqrt of n as n only
|
|
9
9
|
let x = n;
|
|
10
10
|
|
package/src/events/eventList.js
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.EventList = void 0;
|
|
4
|
-
class Node {
|
|
5
|
-
constructor(event, next, prev) {
|
|
6
|
-
this.event = event;
|
|
7
|
-
this.next = next;
|
|
8
|
-
this.prev = prev;
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
class EventList {
|
|
12
|
-
constructor(eventType, maxSize, sortFn, orderDirection) {
|
|
13
|
-
this.eventType = eventType;
|
|
14
|
-
this.maxSize = maxSize;
|
|
15
|
-
this.sortFn = sortFn;
|
|
16
|
-
this.orderDirection = orderDirection;
|
|
17
|
-
this.size = 0;
|
|
18
|
-
}
|
|
19
|
-
insert(event) {
|
|
20
|
-
this.size++;
|
|
21
|
-
const newNode = new Node(event);
|
|
22
|
-
if (this.head === undefined) {
|
|
23
|
-
this.head = this.tail = newNode;
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
if (this.sortFn(this.head.event, newNode.event) ===
|
|
27
|
-
(this.orderDirection === 'asc' ? 'less than' : 'greater than')) {
|
|
28
|
-
this.head.prev = newNode;
|
|
29
|
-
newNode.next = this.head;
|
|
30
|
-
this.head = newNode;
|
|
31
|
-
}
|
|
32
|
-
else {
|
|
33
|
-
let currentNode = this.head;
|
|
34
|
-
while (currentNode.next !== undefined &&
|
|
35
|
-
this.sortFn(currentNode.next.event, newNode.event) !==
|
|
36
|
-
(this.orderDirection === 'asc' ? 'less than' : 'greater than')) {
|
|
37
|
-
currentNode = currentNode.next;
|
|
38
|
-
}
|
|
39
|
-
newNode.next = currentNode.next;
|
|
40
|
-
if (currentNode.next !== undefined) {
|
|
41
|
-
newNode.next.prev = newNode;
|
|
42
|
-
}
|
|
43
|
-
currentNode.next = newNode;
|
|
44
|
-
newNode.prev = currentNode;
|
|
45
|
-
}
|
|
46
|
-
if (this.size > this.maxSize) {
|
|
47
|
-
this.detach();
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
detach() {
|
|
51
|
-
const node = this.tail;
|
|
52
|
-
if (node.prev !== undefined) {
|
|
53
|
-
node.prev.next = node.next;
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
this.head = node.next;
|
|
57
|
-
}
|
|
58
|
-
if (node.next !== undefined) {
|
|
59
|
-
node.next.prev = node.prev;
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
this.tail = node.prev;
|
|
63
|
-
}
|
|
64
|
-
this.size--;
|
|
65
|
-
}
|
|
66
|
-
toArray() {
|
|
67
|
-
return Array.from(this);
|
|
68
|
-
}
|
|
69
|
-
*[Symbol.iterator]() {
|
|
70
|
-
let node = this.head;
|
|
71
|
-
while (node) {
|
|
72
|
-
yield node.event;
|
|
73
|
-
node = node.next;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
exports.EventList = EventList;
|