@d8x/perpetuals-sdk 0.0.41 → 0.0.43

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.
@@ -148,7 +148,20 @@ export default class MarketData extends PerpetualDataHandler {
148
148
  */
149
149
  positionRiskOnCollateralAction(deltaCollateral: number, currentPositionRisk: MarginAccount): Promise<MarginAccount>;
150
150
  protected static _positionRiskOnAccountAction(symbol: string, tradeAmount: number, marginDeposit: number, tradeLeverage: number | undefined, keepPositionLvg: boolean | undefined, tradePrice: number, feeRate: number, perpetualState: PerpetualState, currentPositionRisk: MarginAccount, symbolToPerpStaticInfo: Map<string, PerpetualStaticInfo>): MarginAccount;
151
- maxOrderSizeForTrader(side: string, positionRisk: MarginAccount, perpetualState: PerpetualState): number;
151
+ /**
152
+ * Gets the pool index (in exchangeInfo) corresponding to a given symbol.
153
+ * @param symbol Symbol of the form ETH-USD-MATIC
154
+ * @returns
155
+ */
156
+ getPoolIndexFromSymbol(symbol: string): number;
157
+ /**
158
+ * Gets the wallet balance in the collateral currency corresponding to a given perpetual symbol.
159
+ * @param address Address to check
160
+ * @param symbol Symbol of the form ETH-USD-MATIC.
161
+ * @returns Balance
162
+ */
163
+ getWalletBalance(address: string, symbol: string): Promise<number>;
164
+ maxOrderSizeForTrader(side: string, positionRisk: MarginAccount, perpetualState: PerpetualState, walletBalance?: number): Promise<number>;
152
165
  /**
153
166
  * Uses the Oracle(s) in the exchange to get the latest price of a given index in a given currency, if a route exists.
154
167
  * @param {string} base Index name, e.g. ETH.
@@ -214,8 +214,9 @@ class MarketData extends perpetualDataHandler_1.default {
214
214
  let tradeAmount = Math.abs(order.quantity) * (order.side == nodeSDKTypes_1.BUY_SIDE ? 1 : -1);
215
215
  let tradePrice = (_a = order.limitPrice) !== null && _a !== void 0 ? _a : (yield this.getPerpetualPrice(order.symbol, tradeAmount));
216
216
  // total fee rate = exchange fee + broker fee
217
- let feeRate = (yield this.proxyContract.queryExchangeFee(poolId, traderAddr, (_b = order.brokerAddr) !== null && _b !== void 0 ? _b : nodeSDKTypes_1.ZERO_ADDRESS)) +
218
- ((_c = order.brokerFeeTbps) !== null && _c !== void 0 ? _c : 0) / 100000;
217
+ let feeRate = ((yield this.proxyContract.queryExchangeFee(poolId, traderAddr, (_b = order.brokerAddr) !== null && _b !== void 0 ? _b : nodeSDKTypes_1.ZERO_ADDRESS)) +
218
+ ((_c = order.brokerFeeTbps) !== null && _c !== void 0 ? _c : 0)) /
219
+ 100000;
219
220
  let perpetualState = yield this.getPerpetualState(order.symbol);
220
221
  return MarketData._positionRiskOnAccountAction(order.symbol, tradeAmount, 0, order.leverage, order.keepPositionLvg, tradePrice, feeRate, perpetualState, currentPositionRisk, this.symbolToPerpStaticInfo);
221
222
  });
@@ -303,11 +304,49 @@ class MarketData extends perpetualDataHandler_1.default {
303
304
  };
304
305
  return newPositionRisk;
305
306
  }
306
- maxOrderSizeForTrader(side, positionRisk, perpetualState) {
307
- let initialMarginRate = this.symbolToPerpStaticInfo.get(positionRisk.symbol).initialMarginRate;
308
- // fees not considered here
309
- let maxPosition = (0, d8XMath_1.getMaxSignedPositionSize)(positionRisk.collateralCC, positionRisk.positionNotionalBaseCCY, positionRisk.entryPrice * positionRisk.positionNotionalBaseCCY, side == nodeSDKTypes_1.BUY_SIDE ? 1 : -1, perpetualState.markPrice, initialMarginRate, 0, perpetualState.markPrice, perpetualState.indexPrice, perpetualState.collToQuoteIndexPrice);
310
- return maxPosition - positionRisk.positionNotionalBaseCCY;
307
+ /**
308
+ * Gets the pool index (in exchangeInfo) corresponding to a given symbol.
309
+ * @param symbol Symbol of the form ETH-USD-MATIC
310
+ * @returns
311
+ */
312
+ getPoolIndexFromSymbol(symbol) {
313
+ let pools = this.poolStaticInfos;
314
+ let poolId = this.getPoolIdFromSymbol(symbol);
315
+ let k = 0;
316
+ while (k < pools.length) {
317
+ if (pools[k].poolId == poolId) {
318
+ // pool found
319
+ return k;
320
+ }
321
+ k++;
322
+ }
323
+ return -1;
324
+ }
325
+ /**
326
+ * Gets the wallet balance in the collateral currency corresponding to a given perpetual symbol.
327
+ * @param address Address to check
328
+ * @param symbol Symbol of the form ETH-USD-MATIC.
329
+ * @returns Balance
330
+ */
331
+ getWalletBalance(address, symbol) {
332
+ return __awaiter(this, void 0, void 0, function* () {
333
+ let poolIdx = this.getPoolIndexFromSymbol(symbol);
334
+ let marginTokenAddr = this.poolStaticInfos[poolIdx].poolMarginTokenAddr;
335
+ let token = new ethers_1.ethers.Contract(marginTokenAddr, nodeSDKTypes_1.ERC20_ABI, this.provider);
336
+ let walletBalanceDec18 = yield token.balanceOf(address);
337
+ return walletBalanceDec18 / Math.pow(10, 18);
338
+ });
339
+ }
340
+ maxOrderSizeForTrader(side, positionRisk, perpetualState, walletBalance) {
341
+ return __awaiter(this, void 0, void 0, function* () {
342
+ if (walletBalance != undefined) {
343
+ positionRisk = yield this.positionRiskOnCollateralAction(walletBalance, positionRisk);
344
+ }
345
+ let initialMarginRate = this.symbolToPerpStaticInfo.get(positionRisk.symbol).initialMarginRate;
346
+ // fees not considered here
347
+ let maxPosition = (0, d8XMath_1.getMaxSignedPositionSize)(positionRisk.collateralCC, positionRisk.positionNotionalBaseCCY, positionRisk.entryPrice * positionRisk.positionNotionalBaseCCY, side == nodeSDKTypes_1.BUY_SIDE ? 1 : -1, perpetualState.markPrice, initialMarginRate, 0, perpetualState.markPrice, perpetualState.indexPrice, perpetualState.collToQuoteIndexPrice);
348
+ return maxPosition - positionRisk.positionNotionalBaseCCY;
349
+ });
311
350
  }
312
351
  /**
313
352
  * Uses the Oracle(s) in the exchange to get the latest price of a given index in a given currency, if a route exists.
@@ -237,7 +237,7 @@ class PerpetualDataHandler {
237
237
  }
238
238
  let mgn = {
239
239
  symbol: symbol,
240
- positionNotionalBaseCCY: isEmpty ? 0 : (0, d8XMath_1.ABK64x64ToFloat)(traderState[idx_notional]),
240
+ positionNotionalBaseCCY: isEmpty ? 0 : (0, d8XMath_1.ABK64x64ToFloat)(traderState[idx_notional].abs()),
241
241
  side: isEmpty ? nodeSDKTypes_1.CLOSED_SIDE : side,
242
242
  entryPrice: isEmpty ? 0 : entryPrice,
243
243
  leverage: isEmpty ? 0 : (0, d8XMath_1.ABK64x64ToFloat)(traderState[idx_lvg]),
package/package.json CHANGED
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "name": "@d8x/perpetuals-sdk",
34
34
  "description": "Node TypeScript SDK for D8X Perpetual Futures",
35
- "version": "0.0.41",
35
+ "version": "0.0.43",
36
36
  "main": "./dist/index.js",
37
37
  "types": "./dist/index.d.ts",
38
38
  "directories": {
package/src/marketData.ts CHANGED
@@ -4,6 +4,7 @@ import {
4
4
  calculateLiquidationPriceCollateralBase,
5
5
  calculateLiquidationPriceCollateralQuanto,
6
6
  calculateLiquidationPriceCollateralQuote,
7
+ floatToABK64x64,
7
8
  getMarginRequiredForLeveragedTrade,
8
9
  getMaxSignedPositionSize,
9
10
  getNewPositionLeverage,
@@ -15,6 +16,7 @@ import {
15
16
  COLLATERAL_CURRENCY_BASE,
16
17
  COLLATERAL_CURRENCY_QUANTO,
17
18
  CollaterlCCY,
19
+ ERC20_ABI,
18
20
  ExchangeInfo,
19
21
  MarginAccount,
20
22
  NodeSDKConfig,
@@ -234,8 +236,9 @@ export default class MarketData extends PerpetualDataHandler {
234
236
  let tradePrice = order.limitPrice ?? (await this.getPerpetualPrice(order.symbol, tradeAmount));
235
237
  // total fee rate = exchange fee + broker fee
236
238
  let feeRate =
237
- (await this.proxyContract.queryExchangeFee(poolId, traderAddr, order.brokerAddr ?? ZERO_ADDRESS)) +
238
- (order.brokerFeeTbps ?? 0) / 100_000;
239
+ ((await this.proxyContract.queryExchangeFee(poolId, traderAddr, order.brokerAddr ?? ZERO_ADDRESS)) +
240
+ (order.brokerFeeTbps ?? 0)) /
241
+ 100_000;
239
242
  let perpetualState = await this.getPerpetualState(order.symbol);
240
243
 
241
244
  return MarketData._positionRiskOnAccountAction(
@@ -400,9 +403,9 @@ export default class MarketData extends PerpetualDataHandler {
400
403
  }
401
404
  let newPositionRisk: MarginAccount = {
402
405
  symbol: currentPositionRisk.symbol,
403
- positionNotionalBaseCCY: newPosition,
406
+ positionNotionalBaseCCY: Math.abs(newPosition),
404
407
  side: side,
405
- entryPrice: Math.abs(newLockedInValue / newPosition),
408
+ entryPrice: newPosition == 0 ? 0 : Math.abs(newLockedInValue / newPosition),
406
409
  leverage: newLeverage,
407
410
  markPrice: markPrice,
408
411
  unrealizedPnlQuoteCCY: currentPositionRisk.unrealizedPnlQuoteCCY + tradeAmount * (markPrice - tradePrice),
@@ -415,7 +418,56 @@ export default class MarketData extends PerpetualDataHandler {
415
418
  return newPositionRisk;
416
419
  }
417
420
 
418
- public maxOrderSizeForTrader(side: string, positionRisk: MarginAccount, perpetualState: PerpetualState): number {
421
+ /**
422
+ * Gets the pool index (in exchangeInfo) corresponding to a given symbol.
423
+ * @param symbol Symbol of the form ETH-USD-MATIC
424
+ * @returns Pool index
425
+ */
426
+ public getPoolIndexFromSymbol(symbol: string): number {
427
+ let pools = this.poolStaticInfos!;
428
+ let poolId = this.getPoolIdFromSymbol(symbol);
429
+ let k = 0;
430
+ while (k < pools.length) {
431
+ if (pools[k].poolId == poolId) {
432
+ // pool found
433
+ return k;
434
+ }
435
+ k++;
436
+ }
437
+ return -1;
438
+ }
439
+
440
+ /**
441
+ * Gets the wallet balance in the collateral currency corresponding to a given perpetual symbol.
442
+ * @param address Address to check
443
+ * @param symbol Symbol of the form ETH-USD-MATIC.
444
+ * @returns Balance
445
+ */
446
+ public async getWalletBalance(address: string, symbol: string): Promise<number> {
447
+ let poolIdx = this.getPoolIndexFromSymbol(symbol);
448
+ let marginTokenAddr = this.poolStaticInfos[poolIdx].poolMarginTokenAddr;
449
+ let token = new ethers.Contract(marginTokenAddr, ERC20_ABI, this.provider!);
450
+ let walletBalanceDec18 = await token.balanceOf(address);
451
+ return walletBalanceDec18 / 10 ** 18;
452
+ }
453
+
454
+ /**
455
+ * Gets the maximal order size considering the existing position, state of the perpetual, and optionally any additional collateral to be posted.
456
+ * @param side BUY or SELL
457
+ * @param positionRisk Current position risk (as seen in positionRisk)
458
+ * @param perpetualState Current perpetual state (as seen in exchangeInfo)
459
+ * @param walletBalance Optional wallet balance to consider in the calculation
460
+ * @returns Maximal trade size, not signed
461
+ */
462
+ public async maxOrderSizeForTrader(
463
+ side: string,
464
+ positionRisk: MarginAccount,
465
+ perpetualState: PerpetualState,
466
+ walletBalance?: number
467
+ ): Promise<number> {
468
+ if (walletBalance != undefined) {
469
+ positionRisk = await this.positionRiskOnCollateralAction(walletBalance, positionRisk);
470
+ }
419
471
  let initialMarginRate = this.symbolToPerpStaticInfo.get(positionRisk.symbol)!.initialMarginRate;
420
472
  // fees not considered here
421
473
  let maxPosition = getMaxSignedPositionSize(
@@ -430,7 +482,15 @@ export default class MarketData extends PerpetualDataHandler {
430
482
  perpetualState.indexPrice,
431
483
  perpetualState.collToQuoteIndexPrice
432
484
  );
433
- return maxPosition - positionRisk.positionNotionalBaseCCY;
485
+ let curPosition = side == BUY_SIDE ? positionRisk.positionNotionalBaseCCY : -positionRisk.positionNotionalBaseCCY;
486
+ let tradeAmount = maxPosition - curPosition;
487
+ let perpId = this.getPerpIdFromSymbol(positionRisk.symbol);
488
+ let perpMaxPositionABK = await this.proxyContract!.getMaxSignedTradeSizeForPos(
489
+ perpId,
490
+ floatToABK64x64(curPosition),
491
+ floatToABK64x64(tradeAmount)
492
+ );
493
+ return ABK64x64ToFloat(perpMaxPositionABK.abs());
434
494
  }
435
495
 
436
496
  /**
@@ -315,7 +315,7 @@ export default class PerpetualDataHandler {
315
315
  }
316
316
  let mgn: MarginAccount = {
317
317
  symbol: symbol,
318
- positionNotionalBaseCCY: isEmpty ? 0 : ABK64x64ToFloat(traderState[idx_notional]),
318
+ positionNotionalBaseCCY: isEmpty ? 0 : ABK64x64ToFloat(traderState[idx_notional].abs()),
319
319
  side: isEmpty ? CLOSED_SIDE : side,
320
320
  entryPrice: isEmpty ? 0 : entryPrice,
321
321
  leverage: isEmpty ? 0 : ABK64x64ToFloat(traderState[idx_lvg]),