@d8x/perpetuals-sdk 0.1.3 → 0.1.4

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/src/marketData.ts CHANGED
@@ -212,11 +212,13 @@ export default class MarketData extends PerpetualDataHandler {
212
212
  if (this.proxyContract == null) {
213
213
  throw Error("no proxy contract initialized. Use createProxyInstance().");
214
214
  }
215
+ let obj = await this.priceFeedGetter.fetchPricesForPerpetual(symbol);
215
216
  let mgnAcct = await PerpetualDataHandler.getMarginAccount(
216
217
  traderAddr,
217
218
  symbol,
218
219
  this.symbolToPerpStaticInfo,
219
- this.proxyContract
220
+ this.proxyContract,
221
+ [obj.idxPrices[0], obj.idxPrices[1]]
220
222
  );
221
223
  return mgnAcct;
222
224
  }
@@ -225,48 +227,149 @@ export default class MarketData extends PerpetualDataHandler {
225
227
  * Estimates what the position risk will be if a given order is executed.
226
228
  * @param traderAddr Address of trader
227
229
  * @param order Order to be submitted
228
- * @param currentPositionRisk Position risk before trade
230
+ * @param account Position risk before trade
231
+ * @param indexPriceInfo Index prices and market status (open/closed)
229
232
  * @returns {MarginAccount} Position risk after trade
230
233
  */
231
234
  public async positionRiskOnTrade(
232
235
  traderAddr: string,
233
236
  order: Order,
234
- currentPositionRisk?: MarginAccount,
237
+ account?: MarginAccount,
235
238
  indexPriceInfo?: [number, number, boolean, boolean]
236
- ): Promise<MarginAccount> {
239
+ ): Promise<{ newPositionRisk: MarginAccount; orderCost: number }> {
237
240
  if (this.proxyContract == null) {
238
241
  throw Error("no proxy contract initialized. Use createProxyInstance().");
239
242
  }
240
- if (currentPositionRisk == undefined) {
241
- currentPositionRisk = await this.positionRisk(traderAddr, order.symbol);
243
+ // fetch undefined data
244
+ if (account == undefined) {
245
+ account = await this.positionRisk(traderAddr, order.symbol);
242
246
  }
243
247
  if (indexPriceInfo == undefined) {
244
- let obj = await this.priceFeedGetter.fetchPricesForPerpetual(currentPositionRisk.symbol);
248
+ let obj = await this.priceFeedGetter.fetchPricesForPerpetual(account.symbol);
245
249
  indexPriceInfo = [obj.idxPrices[0], obj.idxPrices[1], obj.mktClosed[0], obj.mktClosed[1]];
246
250
  }
247
- let poolId = PerpetualDataHandler._getPoolIdFromSymbol(order.symbol, this.poolStaticInfos);
248
- // price for this order = limit price (conservative) if given, else the current perp price
249
- let tradeAmount = Math.abs(order.quantity) * (order.side == BUY_SIDE ? 1 : -1);
250
- let tradePrice = order.limitPrice ?? (await this.getPerpetualPrice(order.symbol, tradeAmount));
251
- // total fee rate = exchange fee + broker fee
252
- let feeRate =
253
- ((await this.proxyContract.queryExchangeFee(poolId, traderAddr, order.brokerAddr ?? ZERO_ADDRESS)) +
254
- (order.brokerFeeTbps ?? 0)) /
255
- 100_000;
251
+
252
+ let lotSizeBC = MarketData._getLotSize(account.symbol, this.symbolToPerpStaticInfo);
253
+ // Too small, no change to account
254
+ if (Math.abs(order.quantity) < lotSizeBC) {
255
+ return { newPositionRisk: account, orderCost: 0 };
256
+ }
257
+
258
+ // Current state:
259
+ // perp (for FXs and such)
256
260
  let perpetualState = await this.getPerpetualState(order.symbol, indexPriceInfo);
261
+ let [S2, S3, Sm] = [perpetualState.indexPrice, perpetualState.collToQuoteIndexPrice, perpetualState.markPrice];
262
+ // cash in margin account: upon trading, unpaid funding will be realized
263
+ let currentMarginCashCC = account.collateralCC;
264
+ // signed position, still correct if side is closed (==0)
265
+ let currentPositionBC = (account.side == BUY_SIDE ? 1 : -1) * account.positionNotionalBaseCCY;
266
+ // signed locked-in value
267
+ let currentLockedInQC = account.entryPrice * currentPositionBC;
268
+
269
+ // New trader state:
270
+ // signed trade amount
271
+ let tradeAmountBC = Math.abs(order.quantity) * (order.side == BUY_SIDE ? 1 : -1);
272
+ // signed position
273
+ let newPositionBC = currentPositionBC + tradeAmountBC;
274
+ if (Math.abs(newPositionBC) < 10 * lotSizeBC) {
275
+ // fully closed
276
+ tradeAmountBC = -currentPositionBC;
277
+ newPositionBC = 0;
278
+ }
279
+ let newSide = newPositionBC > 0 ? BUY_SIDE : newPositionBC < 0 ? SELL_SIDE : CLOSED_SIDE;
257
280
 
258
- return MarketData._positionRiskOnAccountAction(
259
- order.symbol,
260
- tradeAmount,
261
- 0,
262
- order.leverage,
263
- order.keepPositionLvg,
264
- tradePrice,
265
- feeRate,
266
- perpetualState,
267
- currentPositionRisk,
281
+ // price for this order = limit price (conservative) if given, else the current perp price
282
+ let tradePrice = order.limitPrice ?? (await this.getPerpetualPrice(order.symbol, tradeAmountBC));
283
+
284
+ // fees
285
+ let poolId = PerpetualDataHandler._getPoolIdFromSymbol(order.symbol, this.poolStaticInfos);
286
+ let exchangeFeeTbps = await this.proxyContract.queryExchangeFee(
287
+ poolId,
288
+ traderAddr,
289
+ order.brokerAddr ?? ZERO_ADDRESS
290
+ );
291
+ let exchangeFeeCC = (Math.abs(tradeAmountBC) * exchangeFeeTbps * 1e-5 * S2) / S3;
292
+ let brokerFeeCC = (Math.abs(tradeAmountBC) * (order.brokerFeeTbps ?? 0) * 1e-5 * S2) / S3;
293
+
294
+ // Trade type:
295
+ let isClose = newPositionBC == 0 || newPositionBC * tradeAmountBC < 0;
296
+ let isOpen = newPositionBC != 0 && (currentPositionBC == 0 || newPositionBC * currentPositionBC > 0); // regular open, no flip
297
+ let isFlip = Math.abs(newPositionBC) > Math.abs(currentPositionBC) && !isOpen; // flip position sign, not fully closed
298
+ let keepPositionLvgOnClose = (order.keepPositionLvg ?? false) && !isOpen;
299
+
300
+ // Contract: _doMarginCollateralActions
301
+ // No collateral actions if
302
+ // 1) leverage is not set or
303
+ // 2) fully closed after trade or
304
+ // 3) is a partial closing, it doesn't flip, and keep lvg flag is not set
305
+ let traderDepositCC: number;
306
+ let targetLvg: number;
307
+ if (order.leverage == undefined || newPositionBC == 0 || (!isOpen && !isFlip && !keepPositionLvgOnClose)) {
308
+ traderDepositCC = 0;
309
+ targetLvg = 0;
310
+ } else {
311
+ // 1) opening and flipping trades need to specify a leverage: default to max if not given
312
+ // 2) for others it's ignored, set target to 0
313
+ let initialMarginRate = this.symbolToPerpStaticInfo.get(account.symbol)!.initialMarginRate;
314
+ targetLvg = isFlip || isOpen ? order.leverage ?? 1 / initialMarginRate : 0;
315
+ let [b0, pos0] = isOpen ? [0, 0] : [account.collateralCC, currentPositionBC];
316
+ traderDepositCC = getDepositAmountForLvgTrade(b0, pos0, tradeAmountBC, targetLvg, tradePrice, S3, Sm);
317
+ console.log("deposit for trget lvg:", traderDepositCC);
318
+ // fees are paid from wallet in this case
319
+ // referral rebate??
320
+ traderDepositCC += exchangeFeeCC + brokerFeeCC;
321
+ }
322
+
323
+ // Contract: _executeTrade
324
+ let deltaCashCC = (-tradeAmountBC * (tradePrice - S2)) / S3;
325
+ let deltaLockedQC = tradeAmountBC * S2;
326
+ if (isClose) {
327
+ let pnl = account.entryPrice * tradeAmountBC - deltaLockedQC;
328
+ deltaLockedQC += pnl;
329
+ deltaCashCC += pnl / S3;
330
+ }
331
+ // funding and fees
332
+ deltaCashCC = deltaCashCC + account.unrealizedFundingCollateralCCY - exchangeFeeCC - brokerFeeCC;
333
+
334
+ // New cash, locked-in, entry price & leverage after trade
335
+ let newLockedInValueQC = currentLockedInQC + deltaLockedQC;
336
+ let newMarginCashCC = currentMarginCashCC + deltaCashCC + traderDepositCC;
337
+ let newEntryPrice = newPositionBC == 0 ? 0 : Math.abs(newLockedInValueQC / newPositionBC);
338
+ let newMarginBalanceCC = newMarginCashCC + (newPositionBC * Sm - newLockedInValueQC) / S3;
339
+ let newLeverage =
340
+ newPositionBC == 0
341
+ ? 0
342
+ : newMarginBalanceCC <= 0
343
+ ? Infinity
344
+ : (Math.abs(newPositionBC) * Sm) / S3 / newMarginBalanceCC;
345
+
346
+ // Liquidation params
347
+ let [S2Liq, S3Liq, tau] = MarketData._getLiquidationParams(
348
+ account.symbol,
349
+ newLockedInValueQC,
350
+ newPositionBC,
351
+ newMarginCashCC,
352
+ Sm,
353
+ S3,
268
354
  this.symbolToPerpStaticInfo
269
355
  );
356
+
357
+ // New position risk
358
+ let newPositionRisk: MarginAccount = {
359
+ symbol: account.symbol,
360
+ positionNotionalBaseCCY: Math.abs(newPositionBC),
361
+ side: newSide,
362
+ entryPrice: newEntryPrice,
363
+ leverage: newLeverage,
364
+ markPrice: Sm,
365
+ unrealizedPnlQuoteCCY: newPositionBC * Sm - newLockedInValueQC,
366
+ unrealizedFundingCollateralCCY: 0,
367
+ collateralCC: newMarginCashCC,
368
+ collToQuoteConversion: S3,
369
+ liquidationPrice: [S2Liq, S3Liq],
370
+ liquidationLvg: 1 / tau,
371
+ };
372
+ return { newPositionRisk: newPositionRisk, orderCost: traderDepositCC };
270
373
  }
271
374
 
272
375
  /**
@@ -278,167 +381,121 @@ export default class MarketData extends PerpetualDataHandler {
278
381
  */
279
382
  public async positionRiskOnCollateralAction(
280
383
  deltaCollateral: number,
281
- currentPositionRisk: MarginAccount,
384
+ account: MarginAccount,
282
385
  indexPriceInfo?: [number, number, boolean, boolean]
283
386
  ): Promise<MarginAccount> {
284
387
  if (this.proxyContract == null) {
285
388
  throw Error("no proxy contract initialized. Use createProxyInstance().");
286
389
  }
390
+ if (deltaCollateral + account.collateralCC + account.unrealizedFundingCollateralCCY < 0) {
391
+ throw Error("not enough margin to remove");
392
+ }
287
393
  if (indexPriceInfo == undefined) {
288
- let obj = await this.priceFeedGetter.fetchPricesForPerpetual(currentPositionRisk.symbol);
394
+ let obj = await this.priceFeedGetter.fetchPricesForPerpetual(account.symbol);
289
395
  indexPriceInfo = [obj.idxPrices[0], obj.idxPrices[1], obj.mktClosed[0], obj.mktClosed[1]];
290
396
  }
291
- let perpetualState = await this.getPerpetualState(currentPositionRisk.symbol, indexPriceInfo);
397
+ let perpetualState = await this.getPerpetualState(account.symbol, indexPriceInfo);
398
+ let [S2, S3, Sm] = [perpetualState.indexPrice, perpetualState.collToQuoteIndexPrice, perpetualState.markPrice];
399
+
400
+ // no position: just increase collateral and kill liquidation vars
401
+ if (account.positionNotionalBaseCCY == 0) {
402
+ return {
403
+ symbol: account.symbol,
404
+ positionNotionalBaseCCY: account.positionNotionalBaseCCY,
405
+ side: account.side,
406
+ entryPrice: account.entryPrice,
407
+ leverage: account.leverage,
408
+ markPrice: Sm,
409
+ unrealizedPnlQuoteCCY: account.unrealizedPnlQuoteCCY,
410
+ unrealizedFundingCollateralCCY: account.unrealizedFundingCollateralCCY,
411
+ collateralCC: account.collateralCC + deltaCollateral,
412
+ collToQuoteConversion: S3,
413
+ liquidationPrice: [0, undefined],
414
+ liquidationLvg: Infinity,
415
+ };
416
+ }
292
417
 
293
- return MarketData._positionRiskOnAccountAction(
294
- currentPositionRisk.symbol,
295
- 0,
296
- deltaCollateral,
297
- undefined,
298
- false,
299
- 0,
300
- 0,
301
- perpetualState,
302
- currentPositionRisk,
418
+ let positionBC = account.positionNotionalBaseCCY * (account.side == BUY_SIDE ? 1 : -1);
419
+ let lockedInQC = account.entryPrice * positionBC;
420
+ let newMarginCashCC = account.collateralCC + deltaCollateral;
421
+ let newMarginBalanceCC =
422
+ newMarginCashCC + account.unrealizedFundingCollateralCCY + (positionBC * Sm - lockedInQC) / S3;
423
+ if (newMarginBalanceCC <= 0) {
424
+ return {
425
+ symbol: account.symbol,
426
+ positionNotionalBaseCCY: account.positionNotionalBaseCCY,
427
+ side: account.side,
428
+ entryPrice: account.entryPrice,
429
+ leverage: Infinity,
430
+ markPrice: Sm,
431
+ unrealizedPnlQuoteCCY: account.unrealizedPnlQuoteCCY,
432
+ unrealizedFundingCollateralCCY: account.unrealizedFundingCollateralCCY,
433
+ collateralCC: newMarginCashCC,
434
+ collToQuoteConversion: S3,
435
+ liquidationPrice: [S2, S3],
436
+ liquidationLvg: 0,
437
+ };
438
+ }
439
+ let newLeverage = (Math.abs(positionBC) * Sm) / S3 / newMarginBalanceCC;
440
+
441
+ // Liquidation params
442
+ let [S2Liq, S3Liq, tau] = MarketData._getLiquidationParams(
443
+ account.symbol,
444
+ lockedInQC,
445
+ positionBC,
446
+ newMarginCashCC,
447
+ Sm,
448
+ S3,
303
449
  this.symbolToPerpStaticInfo
304
450
  );
451
+
452
+ // New position risk
453
+ let newPositionRisk: MarginAccount = {
454
+ symbol: account.symbol,
455
+ positionNotionalBaseCCY: account.positionNotionalBaseCCY,
456
+ side: account.side,
457
+ entryPrice: account.entryPrice,
458
+ leverage: newLeverage,
459
+ markPrice: Sm,
460
+ unrealizedPnlQuoteCCY: account.unrealizedPnlQuoteCCY,
461
+ unrealizedFundingCollateralCCY: account.unrealizedFundingCollateralCCY,
462
+ collateralCC: newMarginCashCC,
463
+ collToQuoteConversion: S3,
464
+ liquidationPrice: [S2Liq, S3Liq],
465
+ liquidationLvg: 1 / tau,
466
+ };
467
+ return newPositionRisk;
305
468
  }
306
469
 
307
- protected static _positionRiskOnAccountAction(
470
+ protected static _getLiquidationParams(
308
471
  symbol: string,
309
- tradeAmount: number,
310
- marginDeposit: number,
311
- tradeLeverage: number | undefined,
312
- keepPositionLvg: boolean | undefined,
313
- tradePrice: number,
314
- feeRate: number,
315
- perpetualState: PerpetualState,
316
- currentPositionRisk: MarginAccount,
472
+ lockedInQC: number,
473
+ signedPositionBC: number,
474
+ marginCashCC: number,
475
+ markPrice: number,
476
+ collToQuoteConversion: number,
317
477
  symbolToPerpStaticInfo: Map<string, PerpetualStaticInfo>
318
- ): MarginAccount {
319
- let currentSide = currentPositionRisk.side;
320
- let currentPosition = (currentSide == BUY_SIDE ? 1 : -1) * currentPositionRisk.positionNotionalBaseCCY;
321
- let newPosition = currentPosition + tradeAmount;
322
- let newSide = newPosition > 0 ? BUY_SIDE : newPosition < 0 ? SELL_SIDE : CLOSED_SIDE;
323
- let lockedInValue = currentPositionRisk.entryPrice * currentPosition;
324
- let newLockedInValue = lockedInValue + tradeAmount * tradePrice;
325
- let newEntryPrice = newPosition == 0 ? 0 : Math.abs(newLockedInValue / newPosition);
326
- if (tradeAmount == 0) {
327
- keepPositionLvg = false;
328
- }
329
- let isOpen = newPosition != 0 && (tradeAmount == 0 || currentPosition == 0 || tradeAmount * currentPosition > 0);
330
- let isFlip = Math.abs(tradeAmount) > Math.abs(currentPosition) && !isOpen;
331
- let keepPositionLvgOnClose = keepPositionLvg && !isOpen;
332
- // need these for leverage/margin calculations
333
- let [markPrice, indexPriceS2, indexPriceS3] = [
334
- perpetualState.markPrice,
335
- perpetualState.indexPrice,
336
- perpetualState.collToQuoteIndexPrice,
337
- ];
338
- let newCollateral: number;
339
- let newLeverage: number;
340
- if (keepPositionLvg) {
341
- // we have a target leverage for the resulting position
342
- // this gives us the total margin needed in the account so that it satisfies the leverage condition
343
- newCollateral = getMarginRequiredForLeveragedTrade(
344
- currentPositionRisk.leverage,
345
- currentPosition,
346
- lockedInValue,
347
- tradeAmount,
348
- markPrice,
349
- indexPriceS2,
350
- indexPriceS3,
351
- tradePrice,
352
- feeRate
353
- );
354
- // the new leverage follows from the updated margin and position
355
- newLeverage = getNewPositionLeverage(
356
- tradeAmount,
357
- newCollateral,
358
- currentPosition,
359
- lockedInValue,
360
- tradePrice,
361
- indexPriceS3,
362
- markPrice
363
- );
364
- } else if (tradeAmount != 0) {
365
- let deltaCash: number;
366
- if (!isOpen && !isFlip && !keepPositionLvgOnClose) {
367
- // cash comes from realized pnl
368
- deltaCash = (tradeAmount * (tradePrice - currentPositionRisk.entryPrice)) / indexPriceS3;
369
- newLockedInValue = lockedInValue + currentPositionRisk.entryPrice * tradeAmount;
370
- } else {
371
- // target lvg will default current lvg if not specified
372
- let targetLvg = isFlip || isOpen ? tradeLeverage ?? 0 : 0;
373
- let b0, pos0;
374
- [b0, pos0] = isOpen ? [0, 0] : [currentPositionRisk.collateralCC, currentPosition];
375
- // cash comes from trader wallet
376
- deltaCash = getDepositAmountForLvgTrade(b0, pos0, tradeAmount, targetLvg, tradePrice, indexPriceS3, markPrice);
377
- // premium/instantaneous pnl
378
- // deltaCash -= (tradeAmount * (tradePrice - indexPriceS2)) / indexPriceS3;
379
- newLockedInValue = lockedInValue + tradeAmount * tradePrice;
380
- }
381
- newCollateral = currentPositionRisk.collateralCC + deltaCash; // - (feeRate * Math.abs(tradeAmount) * indexPriceS2) / indexPriceS3;
382
- // the new leverage corresponds to increasing the position and collateral according to the order
383
- newLeverage = getNewPositionLeverage(
384
- 0,
385
- newCollateral,
386
- newPosition,
387
- newLockedInValue,
388
- tradePrice,
389
- indexPriceS3,
390
- markPrice
391
- );
392
- } else {
393
- // there is no order, adding/removing collateral
394
- newCollateral = currentPositionRisk.collateralCC + marginDeposit;
395
- newLeverage = getNewPositionLeverage(
396
- 0,
397
- newCollateral,
398
- currentPosition,
399
- lockedInValue,
400
- indexPriceS2,
401
- indexPriceS3,
402
- markPrice
403
- );
404
- }
405
-
406
- // liquidation vars
478
+ ): [number, number | undefined, number] {
407
479
  let S2Liq: number, S3Liq: number | undefined;
408
480
  let tau = symbolToPerpStaticInfo.get(symbol)!.maintenanceMarginRate;
409
481
  let ccyType = symbolToPerpStaticInfo.get(symbol)!.collateralCurrencyType;
410
482
  if (ccyType == CollaterlCCY.BASE) {
411
- S2Liq = calculateLiquidationPriceCollateralBase(newLockedInValue, newPosition, newCollateral, tau);
483
+ S2Liq = calculateLiquidationPriceCollateralBase(lockedInQC, signedPositionBC, marginCashCC, tau);
412
484
  S3Liq = S2Liq;
413
485
  } else if (ccyType == CollaterlCCY.QUANTO) {
414
- S3Liq = indexPriceS3;
486
+ S3Liq = collToQuoteConversion;
415
487
  S2Liq = calculateLiquidationPriceCollateralQuanto(
416
- newLockedInValue,
417
- newPosition,
418
- newCollateral,
488
+ lockedInQC,
489
+ signedPositionBC,
490
+ marginCashCC,
419
491
  tau,
420
- indexPriceS3,
492
+ collToQuoteConversion,
421
493
  markPrice
422
494
  );
423
495
  } else {
424
- S2Liq = calculateLiquidationPriceCollateralQuote(newLockedInValue, newPosition, newCollateral, tau);
496
+ S2Liq = calculateLiquidationPriceCollateralQuote(lockedInQC, signedPositionBC, marginCashCC, tau);
425
497
  }
426
-
427
- let newPositionRisk: MarginAccount = {
428
- symbol: currentPositionRisk.symbol,
429
- positionNotionalBaseCCY: Math.abs(newPosition),
430
- side: newSide,
431
- entryPrice: newEntryPrice,
432
- leverage: newLeverage,
433
- markPrice: markPrice,
434
- unrealizedPnlQuoteCCY: newPosition * markPrice - newLockedInValue,
435
- unrealizedFundingCollateralCCY: currentPositionRisk.unrealizedFundingCollateralCCY,
436
- collateralCC: newCollateral,
437
- collToQuoteConversion: indexPriceS3,
438
- liquidationPrice: [S2Liq, S3Liq],
439
- liquidationLvg: 1 / tau,
440
- };
441
- return newPositionRisk;
498
+ return [S2Liq, S3Liq, tau];
442
499
  }
443
500
 
444
501
  /**
@@ -727,17 +784,19 @@ export default class MarketData extends PerpetualDataHandler {
727
784
  if (this.proxyContract == null) {
728
785
  throw Error("no proxy contract initialized. Use createProxyInstance().");
729
786
  }
730
- let mgnAcct = await PerpetualDataHandler.getMarginAccount(
731
- traderAddr,
732
- symbol,
733
- this.symbolToPerpStaticInfo,
734
- this.proxyContract
735
- );
787
+
736
788
  if (indexPrices == undefined) {
737
789
  // fetch from API
738
790
  let obj = await this.priceFeedGetter.fetchPricesForPerpetual(symbol);
739
791
  indexPrices = [obj.idxPrices[0], obj.idxPrices[1]];
740
792
  }
793
+ let mgnAcct = await PerpetualDataHandler.getMarginAccount(
794
+ traderAddr,
795
+ symbol,
796
+ this.symbolToPerpStaticInfo,
797
+ this.proxyContract,
798
+ [indexPrices[0], indexPrices[1]]
799
+ );
741
800
  let S2 = indexPrices[0];
742
801
  let ccyType = this.getPerpetualStaticInfo(symbol).collateralCurrencyType;
743
802
  let S3 = ccyType == COLLATERAL_CURRENCY_QUANTO ? indexPrices[1] : ccyType == COLLATERAL_CURRENCY_QUOTE ? 1 : S2;
@@ -352,23 +352,19 @@ export default class PerpetualDataHandler {
352
352
  symbol: string,
353
353
  symbolToPerpStaticInfo: Map<string, PerpetualStaticInfo>,
354
354
  _proxyContract: ethers.Contract,
355
- _pxS2S3?: [number, number | undefined]
355
+ _pxS2S3: [number, number]
356
356
  ): Promise<MarginAccount> {
357
357
  let perpId = Number(symbol);
358
358
  if (isNaN(perpId)) {
359
359
  perpId = PerpetualDataHandler.symbolToPerpetualId(symbol, symbolToPerpStaticInfo);
360
360
  }
361
- // TODO: correct numbers using actual S2, S3
362
- // if (_pxS2S3 == undefined) {
363
- // // fetch s2,s3
364
- // }
365
361
  const idx_cash = 3;
366
362
  const idx_notional = 4;
367
363
  const idx_locked_in = 5;
368
364
  const idx_mark_price = 8;
369
365
  const idx_lvg = 7;
370
366
  const idx_s3 = 9;
371
- let traderState = await _proxyContract.getTraderState(perpId, traderAddr);
367
+ let traderState = await _proxyContract.getTraderState(perpId, traderAddr, _pxS2S3.map(x=>floatToABK64x64(x)));
372
368
  let isEmpty = traderState[idx_notional] == 0;
373
369
  let cash = ABK64x64ToFloat(traderState[idx_cash]);
374
370
  let S2Liq = 0,
@@ -383,6 +379,7 @@ export default class PerpetualDataHandler {
383
379
  [S2Liq, S3Liq, tau, pnl, unpaidFundingCC] = PerpetualDataHandler._calculateLiquidationPrice(
384
380
  symbol,
385
381
  traderState,
382
+ _pxS2S3[0],
386
383
  symbolToPerpStaticInfo
387
384
  );
388
385
  fLockedIn = traderState[idx_locked_in];
@@ -469,12 +466,14 @@ export default class PerpetualDataHandler {
469
466
  * Liquidation price
470
467
  * @param symbol symbol of the form BTC-USD-MATIC
471
468
  * @param traderState BigInt array according to smart contract
469
+ * @param S2 number, index price S2
472
470
  * @param symbolToPerpStaticInfo mapping symbol->PerpStaticInfo
473
471
  * @returns liquidation mark-price, corresponding collateral/quote conversion
474
472
  */
475
473
  protected static _calculateLiquidationPrice(
476
474
  symbol: string,
477
475
  traderState: BigNumber[],
476
+ S2: number,
478
477
  symbolToPerpStaticInfo: Map<string, PerpetualStaticInfo>
479
478
  ): [number, number, number, number, number] {
480
479
  const idx_availableCashCC = 2;
@@ -501,7 +500,7 @@ export default class PerpetualDataHandler {
501
500
  if (perpInfo.collateralCurrencyType == CollaterlCCY.BASE) {
502
501
  S2Liq = calculateLiquidationPriceCollateralBase(lockedInValueQC, position, cashCC, tau);
503
502
  S3Liq = S2Liq;
504
- unpaidFunding = unpaidFunding / ABK64x64ToFloat(traderState[idx_s2]);
503
+ unpaidFunding = unpaidFunding / S2;
505
504
  } else if (perpInfo.collateralCurrencyType == CollaterlCCY.QUANTO) {
506
505
  let S3 = S3Liq;
507
506
  S3Liq = S3;
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const D8X_SDK_VERSION = "0.1.3";
1
+ export const D8X_SDK_VERSION = "0.1.4";