@orderly.network/perp 1.0.28 → 2.0.0

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/dist/index.js CHANGED
@@ -31,9 +31,9 @@ module.exports = __toCommonJS(src_exports);
31
31
  // src/version.ts
32
32
  if (typeof window !== "undefined") {
33
33
  window.__ORDERLY_VERSION__ = window.__ORDERLY_VERSION__ || {};
34
- window.__ORDERLY_VERSION__["@orderly.network/perp"] = "1.0.28";
34
+ window.__ORDERLY_VERSION__["@orderly.network/perp"] = "2.0.0";
35
35
  }
36
- var version_default = "1.0.28";
36
+ var version_default = "2.0.0";
37
37
 
38
38
  // src/positions.ts
39
39
  var positions_exports = {};
@@ -82,21 +82,25 @@ function totalUnrealizedPnL(positions) {
82
82
  }, 0);
83
83
  }
84
84
  function liqPrice(inputs) {
85
- const { markPrice, totalCollateral: totalCollateral2, positionQty, MMR: MMR2 } = inputs;
86
- const totalNotional2 = notional(positionQty, markPrice);
85
+ const { markPrice, totalCollateral: totalCollateral2, positions, positionQty, MMR: MMR3 } = inputs;
87
86
  if (positionQty === 0) {
88
87
  return 0;
89
88
  }
89
+ const totalNotional2 = positions.reduce((acc, cur) => {
90
+ return acc.add(
91
+ new import_utils.Decimal(notional(cur.position_qty, cur.mark_price)).mul(cur.mmr)
92
+ );
93
+ }, import_utils.zero);
90
94
  return Math.max(
91
95
  new import_utils.Decimal(markPrice).add(
92
- new import_utils.Decimal(totalCollateral2).sub(new import_utils.Decimal(totalNotional2).mul(MMR2)).div(new import_utils.Decimal(positionQty).abs().mul(MMR2).sub(positionQty))
96
+ new import_utils.Decimal(totalCollateral2).sub(totalNotional2).div(new import_utils.Decimal(positionQty).abs().mul(MMR3).sub(positionQty))
93
97
  ).toNumber(),
94
98
  0
95
99
  );
96
100
  }
97
101
  function maintenanceMargin(inputs) {
98
- const { positionQty, markPrice, MMR: MMR2 } = inputs;
99
- return new import_utils.Decimal(positionQty).mul(markPrice).mul(MMR2).abs().toNumber();
102
+ const { positionQty, markPrice, MMR: MMR3 } = inputs;
103
+ return new import_utils.Decimal(positionQty).mul(markPrice).mul(MMR3).abs().toNumber();
100
104
  }
101
105
  function unsettlementPnL(inputs) {
102
106
  const {
@@ -141,6 +145,7 @@ function MMR(inputs) {
141
145
  var account_exports = {};
142
146
  __export(account_exports, {
143
147
  IMR: () => IMR,
148
+ MMR: () => MMR2,
144
149
  availableBalance: () => availableBalance,
145
150
  buyOrdersFilter_by_symbol: () => buyOrdersFilter_by_symbol,
146
151
  currentLeverage: () => currentLeverage,
@@ -174,7 +179,8 @@ function totalValue(inputs) {
174
179
  return nonUSDCHoldingValue.add(USDCHolding).add(totalUnsettlementPnL2);
175
180
  }
176
181
  function freeCollateral(inputs) {
177
- return inputs.totalCollateral.sub(inputs.totalInitialMarginWithOrders);
182
+ const value = inputs.totalCollateral.sub(inputs.totalInitialMarginWithOrders);
183
+ return value.isNegative() ? import_utils2.zero : value;
178
184
  }
179
185
  function totalCollateral(inputs) {
180
186
  const { USDCHolding, nonUSDCHolding } = inputs;
@@ -366,7 +372,7 @@ function maxQty(side, inputs, options) {
366
372
  }
367
373
  return maxQtyByShort(inputs);
368
374
  }
369
- function maxQtyByLong(inputs) {
375
+ function maxQtyByLong(inputs, options) {
370
376
  try {
371
377
  const {
372
378
  baseMaxQty,
@@ -398,7 +404,7 @@ function maxQtyByLong(inputs) {
398
404
  return 0;
399
405
  }
400
406
  }
401
- function maxQtyByShort(inputs) {
407
+ function maxQtyByShort(inputs, options) {
402
408
  try {
403
409
  const {
404
410
  baseMaxQty,
@@ -457,19 +463,108 @@ function availableBalance(inputs) {
457
463
  const { USDCHolding, unsettlementPnL: unsettlementPnL2 } = inputs;
458
464
  return new import_utils2.Decimal(USDCHolding).add(unsettlementPnL2).toNumber();
459
465
  }
466
+ function MMR2(inputs) {
467
+ if (inputs.positionsNotional === 0) {
468
+ return null;
469
+ }
470
+ return new import_utils2.Decimal(inputs.positionsMMR).div(inputs.positionsNotional).toNumber();
471
+ }
460
472
 
461
473
  // src/order.ts
462
474
  var order_exports = {};
463
475
  __export(order_exports, {
476
+ estLeverage: () => estLeverage,
477
+ estLiqPrice: () => estLiqPrice,
464
478
  maxPrice: () => maxPrice,
465
- minPrice: () => minPrice
479
+ minPrice: () => minPrice,
480
+ scropePrice: () => scropePrice
466
481
  });
482
+ var import_utils3 = require("@orderly.network/utils");
467
483
  function maxPrice(markprice, range) {
468
484
  return markprice * (1 + range);
469
485
  }
470
486
  function minPrice(markprice, range) {
471
487
  return markprice * (1 - range);
472
488
  }
489
+ function scropePrice(price, scrope, side) {
490
+ if (side === "BUY") {
491
+ return price * (1 - scrope);
492
+ }
493
+ return price * (1 + scrope);
494
+ }
495
+ function estLiqPrice(inputs) {
496
+ var _a;
497
+ const {
498
+ positions,
499
+ newOrder,
500
+ totalCollateral: totalCollateral2,
501
+ markPrice,
502
+ baseIMR,
503
+ baseMMR,
504
+ IMR_Factor
505
+ } = inputs;
506
+ let currentPosition = void 0;
507
+ let newTotalMM = import_utils3.zero;
508
+ const newOrderNotional = new import_utils3.Decimal(newOrder.qty).mul(newOrder.price);
509
+ for (let index = 0; index < positions.length; index++) {
510
+ const position = positions[index];
511
+ let notional2 = new import_utils3.Decimal(position.position_qty).mul(position.mark_price);
512
+ if (newOrder.symbol === position.symbol) {
513
+ currentPosition = position;
514
+ notional2 = notional2.add(newOrderNotional);
515
+ }
516
+ newTotalMM = newTotalMM.add(notional2.abs().mul(position.mmr));
517
+ }
518
+ const newMMR = Math.max(
519
+ baseMMR,
520
+ new import_utils3.Decimal(baseMMR).div(baseIMR).mul(IMR_Factor).mul(
521
+ newOrderNotional.add(
522
+ !!currentPosition ? new import_utils3.Decimal(currentPosition.position_qty).mul(
523
+ currentPosition.mark_price
524
+ ) : import_utils3.zero
525
+ ).abs()
526
+ ).toPower(4 / 5).toNumber()
527
+ );
528
+ const newQty = new import_utils3.Decimal(newOrder.qty).add(
529
+ (_a = currentPosition == null ? void 0 : currentPosition.position_qty) != null ? _a : 0
530
+ );
531
+ if (newQty.eq(0)) {
532
+ return 0;
533
+ }
534
+ const price = new import_utils3.Decimal(markPrice).add(
535
+ new import_utils3.Decimal(totalCollateral2).sub(newTotalMM).div(newQty.abs().mul(newMMR).sub(newQty))
536
+ ).toNumber();
537
+ return Math.max(0, price);
538
+ }
539
+ function estLeverage(inputs) {
540
+ const { totalCollateral: totalCollateral2, positions, newOrder } = inputs;
541
+ if (totalCollateral2 <= 0) {
542
+ return null;
543
+ }
544
+ let hasPosition = false;
545
+ let sumPositionNotional = positions.reduce((acc, cur) => {
546
+ acc = acc.add(
547
+ new import_utils3.Decimal(new import_utils3.Decimal(cur.position_qty).mul(cur.mark_price).abs())
548
+ );
549
+ if (cur.symbol === newOrder.symbol) {
550
+ hasPosition = true;
551
+ acc = acc.add(new import_utils3.Decimal(newOrder.qty).mul(newOrder.price));
552
+ }
553
+ return acc;
554
+ }, import_utils3.zero);
555
+ if (!hasPosition) {
556
+ sumPositionNotional = sumPositionNotional.add(
557
+ new import_utils3.Decimal(newOrder.qty).mul(newOrder.price).abs()
558
+ );
559
+ }
560
+ if (sumPositionNotional.eq(import_utils3.zero)) {
561
+ return null;
562
+ }
563
+ const totalMarginRatio2 = new import_utils3.Decimal(totalCollateral2).div(
564
+ sumPositionNotional
565
+ );
566
+ return new import_utils3.Decimal(1).div(totalMarginRatio2).toDecimalPlaces(2, import_utils3.Decimal.ROUND_HALF_EVEN).toNumber();
567
+ }
473
568
  // Annotate the CommonJS export names for ESM import in node:
474
569
  0 && (module.exports = {
475
570
  account,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/version.ts","../src/positions.ts","../src/constants.ts","../src/account.ts","../src/order.ts"],"sourcesContent":["export { default as version } from \"./version\";\nexport * as positions from \"./positions\";\nexport * as account from \"./account\";\nexport * as orderUtils from \"./order\";\n\nexport * as order from \"./order\";\n","\ndeclare global {\n interface Window {\n __ORDERLY_VERSION__?: {\n [key: string]: string;\n };\n }\n}\nif(typeof window !== 'undefined') {\n window.__ORDERLY_VERSION__ = window.__ORDERLY_VERSION__ || {};\n window.__ORDERLY_VERSION__[\"@orderly.network/perp\"] = \"1.0.28\";\n};\n\nexport default \"1.0.28\";\n","import { API } from \"@orderly.network/types\";\nimport { Decimal } from \"@orderly.network/utils\";\nimport { IMRFactorPower } from \"./constants\";\n\n/**\n * Calculates the notional value of a single position.\n * @param qty The quantity of the position.\n * @param mark_price The price of the position.\n * @returns The notional value of the position.\n */\nexport function notional(qty: number, mark_price: number): number {\n return new Decimal(qty).mul(mark_price).abs().toNumber();\n}\n\n/**\n * Calculates the total notional value of all positions.\n * @param positions The array of positions.\n * @returns The total notional value of all positions.\n * @link https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Total-Notional\n */\nexport function totalNotional(positions: API.Position[]): number {\n return positions.reduce((acc, cur) => {\n return acc + notional(cur.position_qty, cur.mark_price);\n }, 0);\n}\n\nexport type UnrealPnLInputs = {\n markPrice: number;\n openPrice: number;\n qty: number;\n};\n\n/**\n * Calculates the unrealized profit or loss of a single position.\n * @param inputs The inputs for calculating the unrealized profit or loss.\n * @returns The unrealized profit or loss of the position.\n */\nexport function unrealizedPnL(inputs: UnrealPnLInputs): number {\n return new Decimal(inputs.qty)\n .mul(inputs.markPrice - inputs.openPrice)\n .toNumber();\n}\n\nexport type UnrealPnLROIInputs = {\n positionQty: number;\n openPrice: number;\n IMR: number;\n unrealizedPnL: number;\n};\n\n/**\n * Calculates the return on investment (ROI) of a single position's unrealized profit or loss.\n * @param inputs The inputs for calculating the ROI.\n * @returns The ROI of the position's unrealized profit or loss.\n */\nexport function unrealizedPnLROI(inputs: UnrealPnLROIInputs): number {\n const { openPrice, IMR } = inputs;\n\n if (\n inputs.unrealizedPnL === 0 ||\n inputs.positionQty === 0 ||\n openPrice === 0 ||\n IMR === 0\n )\n return 0;\n\n return new Decimal(inputs.unrealizedPnL)\n .div(new Decimal(inputs.positionQty).mul(openPrice).mul(IMR))\n .toNumber();\n}\n\n/**\n * Calculates the total unrealized profit or loss of all positions.\n * @param positions The array of positions.\n * @returns The total unrealized profit or loss of all positions.\n */\nexport function totalUnrealizedPnL(positions: API.Position[]): number {\n return positions.reduce((acc, cur) => {\n return (\n acc +\n unrealizedPnL({\n qty: cur.position_qty,\n openPrice: cur.average_open_price,\n markPrice: cur.mark_price,\n })\n );\n }, 0);\n}\n\nexport type LiqPriceInputs = {\n markPrice: number;\n totalCollateral: number;\n positionQty: number;\n MMR: number;\n};\n\n/**\n * Calculates the liquidation price of a single position.\n * @param inputs The inputs for calculating the liquidation price.\n * @returns The liquidation price of the position.\n * @see {@link https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Position-Liq.-Price}\n */\nexport function liqPrice(inputs: LiqPriceInputs): number {\n const { markPrice, totalCollateral, positionQty, MMR } = inputs;\n const totalNotional = notional(positionQty, markPrice);\n\n if (positionQty === 0) {\n return 0;\n }\n\n return Math.max(\n new Decimal(markPrice)\n .add(\n new Decimal(totalCollateral)\n .sub(new Decimal(totalNotional).mul(MMR))\n .div(new Decimal(positionQty).abs().mul(MMR).sub(positionQty))\n )\n .toNumber(),\n 0\n );\n}\n\nexport type MMInputs = {\n positionQty: number;\n markPrice: number;\n MMR: number;\n};\n\n/**\n * Calculates the maintenance margin of a position.\n * @param inputs The inputs for calculating the maintenance margin.\n * @returns The maintenance margin of the position.\n */\nexport function maintenanceMargin(inputs: MMInputs) {\n const { positionQty, markPrice, MMR } = inputs;\n\n return new Decimal(positionQty).mul(markPrice).mul(MMR).abs().toNumber();\n}\n\nexport type UnsettlementPnLInputs = {\n positionQty: number;\n markPrice: number;\n costPosition: number;\n sumUnitaryFunding: number;\n lastSumUnitaryFunding: number;\n};\n\n/**\n * Calculates the unrealized profit or loss of each position.\n * @param inputs The inputs for calculating the unrealized profit or loss.\n * @returns The unrealized profit or loss of each position.\n * @link https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Total-Unsettlement-PNL-%5BinlineExtension%5D\n */\nexport function unsettlementPnL(inputs: UnsettlementPnLInputs): number {\n const {\n positionQty,\n markPrice,\n costPosition,\n sumUnitaryFunding,\n lastSumUnitaryFunding,\n } = inputs;\n\n const qty = new Decimal(positionQty);\n\n return qty\n .mul(markPrice)\n .sub(costPosition)\n .sub(qty.mul(new Decimal(sumUnitaryFunding).sub(lastSumUnitaryFunding)))\n .toNumber();\n}\n\nexport type TotalUnsettlementPnLInputs = {\n positions: (API.Position & {\n sum_unitary_funding: number;\n })[];\n sumUnitaryFunding: number;\n};\n\n/**\n * Calculates the total unrealized profit or loss of all positions.\n * @param positions The array of positions.\n * @returns The total unrealized profit or loss of all positions.\n * @link https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Total-Unsettlement-PNL-%5BinlineExtension%5D\n */\nexport function totalUnsettlementPnL(\n positions: (API.Position & {\n sum_unitary_funding: number;\n })[]\n): number {\n if (!Array.isArray(positions) || positions.length === 0) {\n return 0;\n }\n\n return positions.reduce((acc, cur) => {\n return (\n acc +\n unsettlementPnL({\n positionQty: cur.position_qty,\n markPrice: cur.mark_price,\n costPosition: cur.cost_position,\n sumUnitaryFunding: cur.sum_unitary_funding,\n lastSumUnitaryFunding: cur.last_sum_unitary_funding,\n })\n );\n }, 0);\n}\n\n/**\n * Calculates the maintenance margin requirement (MMR) of a position.\n * @param inputs The inputs for calculating the MMR.\n * @returns The MMR of the position.\n */\nexport function MMR(inputs: {\n baseMMR: number;\n baseIMR: number;\n IMRFactor: number;\n positionNotional: number;\n IMR_factor_power: number;\n}): number {\n const {\n baseMMR,\n baseIMR,\n IMRFactor,\n positionNotional,\n IMR_factor_power = IMRFactorPower,\n } = inputs;\n return Math.max(\n baseMMR,\n new Decimal(baseMMR)\n .div(baseIMR)\n .mul(IMRFactor)\n .mul(Math.abs(positionNotional))\n .toPower(IMR_factor_power)\n .toNumber()\n );\n}\n","/**\n * The power of the IMR factor.\n * @constant\n * @default\n */\nexport const IMRFactorPower = 4 / 5;\n","import { Decimal, zero } from \"@orderly.network/utils\";\nimport { IMRFactorPower } from \"./constants\";\nimport {\n API,\n OrderSide,\n OrderType,\n type WSMessage,\n} from \"@orderly.network/types\";\n\nexport type ResultOptions = {\n dp: number;\n};\n\nexport type TotalValueInputs = {\n totalUnsettlementPnL: number;\n\n USDCHolding: number;\n nonUSDCHolding: {\n holding: number;\n markPrice: number;\n //保證金替代率 暂时默认0\n discount: number;\n }[];\n};\n/**\n * 用戶總資產價值 (USDC計價),包含無法作為保證金的資產\n * @see {@link https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Total-Value}\n */\nexport function totalValue(inputs: TotalValueInputs): Decimal {\n const { totalUnsettlementPnL, USDCHolding, nonUSDCHolding } = inputs;\n\n const nonUSDCHoldingValue = nonUSDCHolding.reduce((acc, cur) => {\n return new Decimal(cur.holding).mul(cur.markPrice).add(acc);\n }, zero);\n\n return nonUSDCHoldingValue.add(USDCHolding).add(totalUnsettlementPnL);\n}\n\n/**\n * 用戶帳戶當前可用保證金的價值總和 (USDC計價)\n *\n * @see {@link https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Free-collateral}\n */\nexport type FreeCollateralInputs = {\n // 总保证金\n totalCollateral: Decimal;\n // 总初始保证金\n totalInitialMarginWithOrders: number;\n};\n/**\n * 计算可用保证金\n */\nexport function freeCollateral(inputs: FreeCollateralInputs): Decimal {\n return inputs.totalCollateral.sub(inputs.totalInitialMarginWithOrders);\n}\n\nexport type TotalCollateralValueInputs = {\n // USDC 的 holding 數量\n USDCHolding: number;\n nonUSDCHolding: {\n holding: number;\n markPrice: number;\n //保證金替代率 暂时默认0\n discount: number;\n }[];\n // 未结算盈亏\n unsettlementPnL: number;\n};\n/**\n * 计算总保证金\n * @see {@link https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Total-collateral-%5BinlineExtension%5D}\n */\nexport function totalCollateral(inputs: TotalCollateralValueInputs): Decimal {\n const { USDCHolding, nonUSDCHolding } = inputs;\n const nonUSDCHoldingValue = nonUSDCHolding.reduce((acc, cur) => {\n return (\n acc +\n new Decimal(cur.holding).mul(cur.markPrice).mul(cur.discount).toNumber()\n );\n }, 0);\n\n return new Decimal(USDCHolding)\n .add(nonUSDCHoldingValue)\n .add(inputs.unsettlementPnL);\n}\n\nexport function initialMarginWithOrder() {}\n\nexport type PositionNotionalWithOrderInputs = {\n markPrice: number;\n positionQtyWithOrders: number;\n};\n/**\n * 單一 Symbol position / orders notional 加總\n */\nexport function positionNotionalWithOrder_by_symbol(\n inputs: PositionNotionalWithOrderInputs\n): Decimal {\n return new Decimal(inputs.markPrice).mul(inputs.positionQtyWithOrders);\n}\n\nexport type PositionQtyWithOrderInputs = {\n positionQty: number;\n // 单个Symbol的所有买单合计\n buyOrdersQty: number;\n // 单个Symbol的所有卖单合计\n sellOrdersQty: number;\n};\n/**\n * 單一 Symbol position / orders qty 加總\n */\nexport function positionQtyWithOrders_by_symbol(\n inputs: PositionQtyWithOrderInputs\n): number {\n const { positionQty, buyOrdersQty, sellOrdersQty } = inputs;\n const positionQtyDecimal = new Decimal(positionQty);\n const qty = Math.max(\n positionQtyDecimal.add(buyOrdersQty).abs().toNumber(),\n positionQtyDecimal.sub(sellOrdersQty).abs().toNumber()\n );\n\n return qty;\n}\n\nexport type IMRInputs = {\n maxLeverage: number;\n baseIMR: number;\n IMR_Factor: number;\n positionNotional: number;\n ordersNotional: number;\n IMR_factor_power?: number;\n};\n\n/**\n * 單一 Symbol 初始保證金率\n * Max(1 / Max Account Leverage, Base IMR i, IMR Factor i * Abs(Position Notional i + Order Notional i)^(4/5))\n */\nexport function IMR(inputs: IMRInputs): number {\n const {\n maxLeverage,\n baseIMR,\n IMR_Factor,\n positionNotional,\n ordersNotional: orderNotional,\n IMR_factor_power = IMRFactorPower,\n } = inputs;\n return Math.max(\n 1 / maxLeverage,\n baseIMR,\n new Decimal(IMR_Factor)\n .mul(\n new Decimal(positionNotional)\n .add(orderNotional)\n .abs()\n .toPower(IMR_factor_power)\n )\n .toNumber()\n );\n}\n\nexport function buyOrdersFilter_by_symbol(\n orders: API.Order[],\n symbol: string\n): API.Order[] {\n return orders.filter(\n (item) => item.symbol === symbol && item.side === OrderSide.BUY\n );\n}\n\nexport function sellOrdersFilter_by_symbol(\n orders: API.Order[],\n symbol: string\n): API.Order[] {\n return orders.filter(\n (item) => item.symbol === symbol && item.side === OrderSide.SELL\n );\n}\n\n/**\n * 从仓位列表中获取指定symbol的仓位数量\n */\nexport function getQtyFromPositions(\n positions: API.Position[],\n symbol: string\n): number {\n if (!positions) {\n return 0;\n }\n const position = positions.find((item) => item.symbol === symbol);\n return position?.position_qty || 0;\n}\n\n/**\n * 从订单列表中获取指定symbol的看多,看空订单数量,\n */\nexport function getQtyFromOrdersBySide(\n orders: API.Order[],\n symbol: string,\n side: OrderSide\n): number {\n const ordersBySide =\n side === OrderSide.SELL\n ? sellOrdersFilter_by_symbol(orders, symbol)\n : buyOrdersFilter_by_symbol(orders, symbol);\n return ordersBySide.reduce((acc, cur) => {\n return acc + cur.quantity;\n }, 0);\n}\n\nexport function getPositonsAndOrdersNotionalBySymbol(inputs: {\n positions: API.Position[];\n orders: API.Order[];\n symbol: string;\n markPrice: number;\n}): number {\n const { positions, orders, symbol, markPrice } = inputs;\n const positionQty = getQtyFromPositions(positions, symbol);\n const buyOrdersQty = getQtyFromOrdersBySide(orders, symbol, OrderSide.BUY);\n const sellOrdersQty = getQtyFromOrdersBySide(orders, symbol, OrderSide.SELL);\n\n const markPriceDecimal = new Decimal(markPrice);\n\n return markPriceDecimal\n .mul(positionQty)\n .add(markPriceDecimal.mul(new Decimal(buyOrdersQty).add(sellOrdersQty)))\n .abs()\n .toNumber();\n}\n\nexport type TotalInitialMarginWithOrdersInputs = {\n positions: API.Position[];\n orders: API.Order[];\n // account: API.AccountInfo;\n markPrices: { [key: string]: number };\n symbolInfo: any;\n IMR_Factors: { [key: string]: number };\n} & Pick<IMRInputs, \"maxLeverage\">;\n\n/**\n * 计算用戶已使用初始保證金加總 ( 包含 position / orders )\n */\nexport function totalInitialMarginWithOrders(\n inputs: TotalInitialMarginWithOrdersInputs\n): number {\n const {\n positions,\n orders,\n markPrices,\n IMR_Factors,\n maxLeverage,\n symbolInfo,\n } = inputs;\n\n const symbols = extractSymbols(positions, orders);\n\n const total_initial_margin_with_orders = symbols.reduce((acc, cur) => {\n const symbol = cur;\n const positionQty = getQtyFromPositions(positions, symbol);\n const buyOrdersQty = getQtyFromOrdersBySide(orders, symbol, OrderSide.BUY);\n const sellOrdersQty = getQtyFromOrdersBySide(\n orders,\n symbol,\n OrderSide.SELL\n );\n\n const markPrice = markPrices[symbol] || 0;\n\n //---\n const positionQtyWithOrders = positionQtyWithOrders_by_symbol({\n positionQty,\n buyOrdersQty,\n sellOrdersQty,\n });\n\n //---\n const position_notional_with_orders = positionNotionalWithOrder_by_symbol({\n markPrice,\n positionQtyWithOrders,\n });\n\n //----\n const markPriceDecimal = new Decimal(markPrice);\n\n const imr = IMR({\n positionNotional: markPriceDecimal.mul(positionQty).toNumber(),\n ordersNotional: markPriceDecimal\n .mul(new Decimal(buyOrdersQty).add(sellOrdersQty))\n .toNumber(),\n maxLeverage,\n IMR_Factor: IMR_Factors[symbol],\n baseIMR: symbolInfo[symbol](\"base_imr\", 0),\n });\n\n return position_notional_with_orders.mul(imr).add(acc).toNumber();\n }, 0);\n\n return total_initial_margin_with_orders;\n}\n\n/**\n * 把订单按照symbol分组, 因为一个symbol可以有多个挂单\n */\nexport function groupOrdersBySymbol(orders: API.Order[]) {\n const symbols: { [key: string]: API.Order[] } = {};\n\n orders.forEach((item) => {\n if (!symbols[item.symbol]) {\n symbols[item.symbol] = [];\n }\n\n symbols[item.symbol].push(item);\n });\n\n return symbols;\n}\n\n/**\n * Extracts all unique symbols from positions and orders.\n * @param positions - An array of position objects.\n * @param orders - An array of order objects.\n * @returns An array of unique symbols.\n */\nexport function extractSymbols(\n positions: Pick<API.Position, \"symbol\">[],\n orders: Pick<API.Order, \"symbol\">[]\n): string[] {\n const symbols = new Set<string>();\n\n positions.forEach((item) => {\n symbols.add(item.symbol);\n });\n\n orders.forEach((item) => {\n symbols.add(item.symbol);\n });\n\n return Array.from(symbols);\n}\n\n//=========== max qty ==================\n\n// function otherIM(inputs: {}): number {}\n\nexport type OtherIMsInputs = {\n // 传入除当前symbol外的其他symbol的仓位列表\n positions: API.Position[];\n // 传入除当前symbol外的其他symbol的订单列表\n orders: API.Order[];\n\n markPrices: { [key: string]: number };\n maxLeverage: number;\n symbolInfo: any;\n IMR_Factors: { [key: string]: number };\n};\n/**\n * 除当前symbol外的其他symbol已占用的总保证金\n */\nexport function otherIMs(inputs: OtherIMsInputs): number {\n const {\n orders,\n positions,\n maxLeverage,\n IMR_Factors,\n symbolInfo,\n markPrices,\n } = inputs;\n\n const symbols = extractSymbols(positions, orders);\n\n return symbols\n .reduce((acc, cur) => {\n const symbol = cur;\n\n if (typeof markPrices[symbol] === \"undefined\") {\n console.warn(\"markPrices[%s] is undefined\", symbol);\n return acc;\n }\n\n const markPriceDecimal = new Decimal(markPrices[symbol] || 0);\n\n const positionQty = getQtyFromPositions(positions, symbol);\n const positionNotional = markPriceDecimal.mul(positionQty).toNumber();\n\n const buyOrdersQty = getQtyFromOrdersBySide(\n orders,\n symbol,\n OrderSide.BUY\n );\n const sellOrdersQty = getQtyFromOrdersBySide(\n orders,\n symbol,\n OrderSide.SELL\n );\n\n const ordersNotional = markPriceDecimal\n .mul(new Decimal(buyOrdersQty).add(sellOrdersQty))\n .toNumber();\n\n const IMR_Factor = IMR_Factors[symbol];\n\n if (!IMR_Factor) {\n console.warn(\"IMR_Factor is not found:\", symbol);\n return acc;\n }\n\n const imr = IMR({\n maxLeverage,\n\n IMR_Factor,\n baseIMR: symbolInfo[symbol](\"base_imr\", 0),\n positionNotional,\n ordersNotional,\n });\n\n const positionQtyWithOrders = positionQtyWithOrders_by_symbol({\n positionQty,\n buyOrdersQty,\n sellOrdersQty,\n });\n\n const positionNotionalWithOrders = positionNotionalWithOrder_by_symbol({\n markPrice: markPrices[symbol] || 0,\n positionQtyWithOrders,\n });\n\n return acc.add(positionNotionalWithOrders.mul(imr));\n }, zero)\n .toNumber();\n}\n\nexport type MaxQtyInputs = {\n symbol: string;\n\n //單次開倉最大 Qty 限制, /v1/public/info.base_max\n baseMaxQty: number;\n /**\n * 用户保证金总额(USDC 计价), 可以由 totalCollateral 计算得出\n * @see totalCollateral\n */\n totalCollateral: number;\n maxLeverage: number;\n baseIMR: number;\n /**\n * @see otherIMs\n */\n otherIMs: number;\n markPrice: number;\n // 已开仓数量\n positionQty: number;\n // 已挂多单数量\n buyOrdersQty: number;\n // 已挂空单数量\n sellOrdersQty: number;\n\n IMR_Factor: number;\n\n takerFeeRate: number;\n};\n\n/**\n * 最大可下单数量\n * @see {@link https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Max-Order-QTY}\n */\nexport function maxQty(\n side: OrderSide,\n inputs: MaxQtyInputs,\n options?: ResultOptions\n): number {\n if (side === OrderSide.BUY) {\n return maxQtyByLong(inputs);\n }\n return maxQtyByShort(inputs);\n}\n\nexport function maxQtyByLong(inputs: Omit<MaxQtyInputs, \"side\">): number {\n try {\n const {\n baseMaxQty,\n totalCollateral,\n otherIMs,\n maxLeverage,\n baseIMR,\n markPrice,\n IMR_Factor,\n positionQty,\n buyOrdersQty,\n takerFeeRate,\n } = inputs;\n\n if (totalCollateral === 0) {\n return 0;\n }\n\n const totalCollateralDecimal = new Decimal(totalCollateral);\n\n const factor_1 = totalCollateralDecimal\n .sub(otherIMs)\n .div(\n new Decimal(takerFeeRate)\n .mul(2)\n .mul(0.0001)\n .add(Math.max(1 / maxLeverage, baseIMR))\n )\n .div(markPrice)\n .mul(0.995)\n .sub(new Decimal(positionQty).add(buyOrdersQty))\n .toNumber();\n\n if (positionQty === 0 && buyOrdersQty === 0) {\n return Math.min(baseMaxQty, factor_1);\n }\n\n const factor_2 = totalCollateralDecimal\n .sub(otherIMs)\n .div(IMR_Factor)\n .toPower(1 / 1.8)\n .div(markPrice)\n .sub(\n new Decimal(positionQty)\n .add(buyOrdersQty)\n // .abs()\n .div(new Decimal(takerFeeRate).mul(2).mul(0.0001).add(1))\n )\n .mul(0.995)\n .toNumber();\n\n return Math.min(baseMaxQty, factor_1, factor_2);\n } catch (error) {\n return 0;\n }\n}\n\nexport function maxQtyByShort(inputs: Omit<MaxQtyInputs, \"side\">): number {\n try {\n const {\n baseMaxQty,\n totalCollateral,\n otherIMs,\n maxLeverage,\n baseIMR,\n markPrice,\n IMR_Factor,\n positionQty,\n buyOrdersQty,\n sellOrdersQty,\n takerFeeRate,\n } = inputs;\n\n const totalCollateralDecimal = new Decimal(totalCollateral);\n\n const factor_1 = totalCollateralDecimal\n .sub(otherIMs)\n .div(\n new Decimal(takerFeeRate)\n .mul(2)\n .mul(0.0001)\n .add(Math.max(1 / maxLeverage, baseIMR))\n )\n .div(markPrice)\n .mul(0.995)\n .add(new Decimal(positionQty).add(sellOrdersQty))\n\n .toNumber();\n\n if (positionQty === 0 && buyOrdersQty === 0) {\n return Math.min(baseMaxQty, factor_1);\n }\n\n const factor_2 = totalCollateralDecimal\n .sub(otherIMs)\n .div(IMR_Factor)\n .toPower(1 / 1.8)\n .div(markPrice)\n .add(\n new Decimal(positionQty)\n .add(sellOrdersQty)\n // .abs()\n .div(new Decimal(takerFeeRate).mul(2).mul(0.0001).add(1))\n )\n .mul(0.995)\n .toNumber();\n\n return Math.min(baseMaxQty, factor_1, factor_2);\n } catch (error) {\n return 0;\n }\n}\n\nexport type TotalMarginRatioInputs = {\n totalCollateral: number;\n markPrices: { [key: string]: number };\n positions: API.Position[];\n};\n/**\n * @see {@link https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Total-Margin-Ratio}\n */\nexport function totalMarginRatio(\n inputs: TotalMarginRatioInputs,\n dp?: number\n): number {\n const { totalCollateral, markPrices, positions } = inputs;\n\n if (totalCollateral === 0) {\n return 0;\n }\n\n const totalCollateralDecimal = new Decimal(totalCollateral);\n\n const totalPositionNotional = positions.reduce((acc, cur) => {\n const markPrice = markPrices[cur.symbol] || 0;\n return acc.add(new Decimal(cur.position_qty).mul(markPrice).abs());\n }, zero);\n\n if (totalPositionNotional.eq(zero)) {\n return 0;\n }\n\n return totalCollateralDecimal.div(totalPositionNotional).toNumber();\n}\n\nexport type TotalUnrealizedROIInputs = {\n totalUnrealizedPnL: number;\n totalValue: number;\n};\n\n/**\n * totalUnrealizedROI\n * @see {@link https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Total-Unrealized-ROI}\n */\nexport function totalUnrealizedROI(inputs: TotalUnrealizedROIInputs) {\n const { totalUnrealizedPnL, totalValue } = inputs;\n\n return new Decimal(totalUnrealizedPnL)\n .div(totalValue - totalUnrealizedPnL)\n .toNumber();\n}\n\n/**\n * @see {@link https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Current-account-leverage}\n */\nexport function currentLeverage(totalMarginRatio: number) {\n if (totalMarginRatio === 0) {\n return 0;\n }\n return 1 / totalMarginRatio;\n}\n\nexport type AvailableBalanceInputs = {\n USDCHolding: number;\n unsettlementPnL: number;\n};\nexport function availableBalance(inputs: AvailableBalanceInputs) {\n const { USDCHolding, unsettlementPnL } = inputs;\n\n return new Decimal(USDCHolding).add(unsettlementPnL).toNumber();\n}\n","/**\n * 下单时的最高价格\n * @see https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Max-price\n */\nexport function maxPrice(markprice: number, range: number) {\n return markprice * (1 + range);\n}\n\n/**\n * 下单时的最低价格\n * @see https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Min-price\n */\nexport function minPrice(markprice: number, range: number) {\n return markprice * (1 - range);\n}\n"],"mappings":"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","names":["IMR","totalCollateral","MMR","totalNotional","import_utils","totalUnsettlementPnL","totalCollateral","otherIMs","totalUnrealizedPnL","totalValue","totalMarginRatio","unsettlementPnL"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/version.ts","../src/positions.ts","../src/constants.ts","../src/account.ts","../src/order.ts"],"sourcesContent":["export { default as version } from \"./version\";\nexport * as positions from \"./positions\";\nexport * as account from \"./account\";\nexport * as orderUtils from \"./order\";\n\nexport * as order from \"./order\";\n","\ndeclare global {\n interface Window {\n __ORDERLY_VERSION__?: {\n [key: string]: string;\n };\n }\n}\nif(typeof window !== 'undefined') {\n window.__ORDERLY_VERSION__ = window.__ORDERLY_VERSION__ || {};\n window.__ORDERLY_VERSION__[\"@orderly.network/perp\"] = \"2.0.0\";\n};\n\nexport default \"2.0.0\";\n","import { API } from \"@orderly.network/types\";\nimport { Decimal, zero } from \"@orderly.network/utils\";\nimport { IMRFactorPower } from \"./constants\";\n\n/**\n * Calculates the notional value of a single position.\n * @param qty The quantity of the position.\n * @param mark_price The price of the position.\n * @returns The notional value of the position.\n */\nexport function notional(qty: number, mark_price: number): number {\n return new Decimal(qty).mul(mark_price).abs().toNumber();\n}\n\n/**\n * Calculates the total notional value of all positions.\n * @param positions The array of positions.\n * @returns The total notional value of all positions.\n * @link https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Total-Notional\n */\nexport function totalNotional(positions: API.Position[]): number {\n return positions.reduce((acc, cur) => {\n return acc + notional(cur.position_qty, cur.mark_price);\n }, 0);\n}\n\nexport type UnrealPnLInputs = {\n markPrice: number;\n openPrice: number;\n qty: number;\n};\n\n/**\n * Calculates the unrealized profit or loss of a single position.\n * @param inputs The inputs for calculating the unrealized profit or loss.\n * @returns The unrealized profit or loss of the position.\n */\nexport function unrealizedPnL(inputs: UnrealPnLInputs): number {\n return new Decimal(inputs.qty)\n .mul(inputs.markPrice - inputs.openPrice)\n .toNumber();\n}\n\nexport type UnrealPnLROIInputs = {\n positionQty: number;\n openPrice: number;\n IMR: number;\n unrealizedPnL: number;\n};\n\n/**\n * Calculates the return on investment (ROI) of a single position's unrealized profit or loss.\n * @param inputs The inputs for calculating the ROI.\n * @returns The ROI of the position's unrealized profit or loss.\n */\nexport function unrealizedPnLROI(inputs: UnrealPnLROIInputs): number {\n const { openPrice, IMR } = inputs;\n\n if (\n inputs.unrealizedPnL === 0 ||\n inputs.positionQty === 0 ||\n openPrice === 0 ||\n IMR === 0\n )\n return 0;\n\n return new Decimal(inputs.unrealizedPnL)\n .div(new Decimal(inputs.positionQty).mul(openPrice).mul(IMR))\n .toNumber();\n}\n\n/**\n * Calculates the total unrealized profit or loss of all positions.\n * @param positions The array of positions.\n * @returns The total unrealized profit or loss of all positions.\n */\nexport function totalUnrealizedPnL(positions: API.Position[]): number {\n return positions.reduce((acc, cur) => {\n return (\n acc +\n unrealizedPnL({\n qty: cur.position_qty,\n openPrice: cur.average_open_price,\n markPrice: cur.mark_price,\n })\n );\n }, 0);\n}\n\nexport type LiqPriceInputs = {\n markPrice: number;\n totalCollateral: number;\n positionQty: number;\n positions: Pick<API.PositionExt, \"position_qty\" | \"mark_price\" | \"mmr\">[];\n MMR: number;\n};\n\n/**\n * Calculates the liquidation price of a single position.\n * @param inputs The inputs for calculating the liquidation price.\n * @returns The liquidation price of the position.\n * @see {@link https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Position-Liq.-Price}\n */\nexport function liqPrice(inputs: LiqPriceInputs): number {\n const { markPrice, totalCollateral, positions, positionQty, MMR } = inputs;\n\n if (positionQty === 0) {\n return 0;\n }\n\n // totalNotional of all poisitions\n const totalNotional: Decimal = positions.reduce((acc, cur) => {\n return acc.add(\n new Decimal(notional(cur.position_qty, cur.mark_price)).mul(cur.mmr)\n );\n }, zero);\n\n return Math.max(\n new Decimal(markPrice)\n .add(\n new Decimal(totalCollateral)\n .sub(totalNotional)\n .div(new Decimal(positionQty).abs().mul(MMR).sub(positionQty))\n )\n .toNumber(),\n 0\n );\n}\n\nexport type MMInputs = {\n positionQty: number;\n markPrice: number;\n MMR: number;\n};\n\n/**\n * Calculates the maintenance margin of a position.\n * @param inputs The inputs for calculating the maintenance margin.\n * @returns The maintenance margin of the position.\n */\nexport function maintenanceMargin(inputs: MMInputs) {\n const { positionQty, markPrice, MMR } = inputs;\n\n return new Decimal(positionQty).mul(markPrice).mul(MMR).abs().toNumber();\n}\n\nexport type UnsettlementPnLInputs = {\n positionQty: number;\n markPrice: number;\n costPosition: number;\n sumUnitaryFunding: number;\n lastSumUnitaryFunding: number;\n};\n\n/**\n * Calculates the unrealized profit or loss of each position.\n * @param inputs The inputs for calculating the unrealized profit or loss.\n * @returns The unrealized profit or loss of each position.\n * @link https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Total-Unsettlement-PNL-%5BinlineExtension%5D\n */\nexport function unsettlementPnL(inputs: UnsettlementPnLInputs): number {\n const {\n positionQty,\n markPrice,\n costPosition,\n sumUnitaryFunding,\n lastSumUnitaryFunding,\n } = inputs;\n\n const qty = new Decimal(positionQty);\n\n return qty\n .mul(markPrice)\n .sub(costPosition)\n .sub(qty.mul(new Decimal(sumUnitaryFunding).sub(lastSumUnitaryFunding)))\n .toNumber();\n}\n\nexport type TotalUnsettlementPnLInputs = {\n positions: (API.Position & {\n sum_unitary_funding: number;\n })[];\n sumUnitaryFunding: number;\n};\n\n/**\n * Calculates the total unrealized profit or loss of all positions.\n * @param positions The array of positions.\n * @returns The total unrealized profit or loss of all positions.\n * @link https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Total-Unsettlement-PNL-%5BinlineExtension%5D\n */\nexport function totalUnsettlementPnL(\n positions: (API.Position & {\n sum_unitary_funding: number;\n })[]\n): number {\n if (!Array.isArray(positions) || positions.length === 0) {\n return 0;\n }\n\n return positions.reduce((acc, cur) => {\n return (\n acc +\n unsettlementPnL({\n positionQty: cur.position_qty,\n markPrice: cur.mark_price,\n costPosition: cur.cost_position,\n sumUnitaryFunding: cur.sum_unitary_funding,\n lastSumUnitaryFunding: cur.last_sum_unitary_funding,\n })\n );\n }, 0);\n}\n\nexport type MMRInputs = {\n baseMMR: number;\n baseIMR: number;\n IMRFactor: number;\n positionNotional: number;\n IMR_factor_power: number;\n};\n\n/**\n * Calculates the maintenance margin requirement (MMR) of a position.\n * @param inputs The inputs for calculating the MMR.\n * @returns The MMR of the position.\n */\nexport function MMR(inputs: MMRInputs): number {\n const {\n baseMMR,\n baseIMR,\n IMRFactor,\n positionNotional,\n IMR_factor_power = IMRFactorPower,\n } = inputs;\n return Math.max(\n baseMMR,\n new Decimal(baseMMR)\n .div(baseIMR)\n .mul(IMRFactor)\n .mul(Math.abs(positionNotional))\n .toPower(IMR_factor_power)\n .toNumber()\n );\n}\n","/**\n * The power of the IMR factor.\n * @constant\n * @default\n */\nexport const IMRFactorPower = 4 / 5;\n","import { Decimal, zero } from \"@orderly.network/utils\";\nimport { IMRFactorPower } from \"./constants\";\nimport {\n API,\n OrderSide,\n OrderType,\n type WSMessage,\n} from \"@orderly.network/types\";\n\nexport type ResultOptions = {\n dp: number;\n};\n\nexport type TotalValueInputs = {\n totalUnsettlementPnL: number;\n\n USDCHolding: number;\n nonUSDCHolding: {\n holding: number;\n markPrice: number;\n //保證金替代率 暂时默认0\n discount: number;\n }[];\n};\n/**\n * 用戶總資產價值 (USDC計價),包含無法作為保證金的資產\n * @see {@link https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Total-Value}\n */\nexport function totalValue(inputs: TotalValueInputs): Decimal {\n const { totalUnsettlementPnL, USDCHolding, nonUSDCHolding } = inputs;\n\n const nonUSDCHoldingValue = nonUSDCHolding.reduce((acc, cur) => {\n return new Decimal(cur.holding).mul(cur.markPrice).add(acc);\n }, zero);\n\n return nonUSDCHoldingValue.add(USDCHolding).add(totalUnsettlementPnL);\n}\n\n/**\n * 用戶帳戶當前可用保證金的價值總和 (USDC計價)\n *\n * @see {@link https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Free-collateral}\n */\nexport type FreeCollateralInputs = {\n // 总保证金\n totalCollateral: Decimal;\n // 总初始保证金\n totalInitialMarginWithOrders: number;\n};\n/**\n * 计算可用保证金\n */\nexport function freeCollateral(inputs: FreeCollateralInputs): Decimal {\n const value = inputs.totalCollateral.sub(inputs.totalInitialMarginWithOrders);\n // free collateral cannot be less than 0\n return value.isNegative() ? zero : value;\n}\n\nexport type TotalCollateralValueInputs = {\n // USDC 的 holding 數量\n USDCHolding: number;\n nonUSDCHolding: {\n holding: number;\n markPrice: number;\n //保證金替代率 暂时默认0\n discount: number;\n }[];\n // 未结算盈亏\n unsettlementPnL: number;\n};\n/**\n * 计算总保证金\n * @see {@link https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Total-collateral-%5BinlineExtension%5D}\n */\nexport function totalCollateral(inputs: TotalCollateralValueInputs): Decimal {\n const { USDCHolding, nonUSDCHolding } = inputs;\n const nonUSDCHoldingValue = nonUSDCHolding.reduce((acc, cur) => {\n return (\n acc +\n new Decimal(cur.holding).mul(cur.markPrice).mul(cur.discount).toNumber()\n );\n }, 0);\n\n return new Decimal(USDCHolding)\n .add(nonUSDCHoldingValue)\n .add(inputs.unsettlementPnL);\n}\n\nexport function initialMarginWithOrder() {}\n\nexport type PositionNotionalWithOrderInputs = {\n markPrice: number;\n positionQtyWithOrders: number;\n};\n/**\n * 單一 Symbol position / orders notional 加總\n */\nexport function positionNotionalWithOrder_by_symbol(\n inputs: PositionNotionalWithOrderInputs\n): Decimal {\n return new Decimal(inputs.markPrice).mul(inputs.positionQtyWithOrders);\n}\n\nexport type PositionQtyWithOrderInputs = {\n positionQty: number;\n // 单个Symbol的所有买单合计\n buyOrdersQty: number;\n // 单个Symbol的所有卖单合计\n sellOrdersQty: number;\n};\n/**\n * 單一 Symbol position / orders qty 加總\n */\nexport function positionQtyWithOrders_by_symbol(\n inputs: PositionQtyWithOrderInputs\n): number {\n const { positionQty, buyOrdersQty, sellOrdersQty } = inputs;\n const positionQtyDecimal = new Decimal(positionQty);\n const qty = Math.max(\n positionQtyDecimal.add(buyOrdersQty).abs().toNumber(),\n positionQtyDecimal.sub(sellOrdersQty).abs().toNumber()\n );\n\n return qty;\n}\n\nexport type IMRInputs = {\n maxLeverage: number;\n baseIMR: number;\n IMR_Factor: number;\n positionNotional: number;\n ordersNotional: number;\n IMR_factor_power?: number;\n};\n\n/**\n * 單一 Symbol 初始保證金率\n * Max(1 / Max Account Leverage, Base IMR i, IMR Factor i * Abs(Position Notional i + Order Notional i)^(4/5))\n */\nexport function IMR(inputs: IMRInputs): number {\n const {\n maxLeverage,\n baseIMR,\n IMR_Factor,\n positionNotional,\n ordersNotional: orderNotional,\n IMR_factor_power = IMRFactorPower,\n } = inputs;\n return Math.max(\n 1 / maxLeverage,\n baseIMR,\n new Decimal(IMR_Factor)\n .mul(\n new Decimal(positionNotional)\n .add(orderNotional)\n .abs()\n .toPower(IMR_factor_power)\n )\n .toNumber()\n );\n}\n\nexport function buyOrdersFilter_by_symbol(\n orders: API.Order[],\n symbol: string\n): API.Order[] {\n return orders.filter(\n (item) => item.symbol === symbol && item.side === OrderSide.BUY\n );\n}\n\nexport function sellOrdersFilter_by_symbol(\n orders: API.Order[],\n symbol: string\n): API.Order[] {\n return orders.filter(\n (item) => item.symbol === symbol && item.side === OrderSide.SELL\n );\n}\n\n/**\n * 从仓位列表中获取指定symbol的仓位数量\n */\nexport function getQtyFromPositions(\n positions: API.Position[],\n symbol: string\n): number {\n if (!positions) {\n return 0;\n }\n const position = positions.find((item) => item.symbol === symbol);\n return position?.position_qty || 0;\n}\n\n/**\n * 从订单列表中获取指定symbol的看多,看空订单数量,\n */\nexport function getQtyFromOrdersBySide(\n orders: API.Order[],\n symbol: string,\n side: OrderSide\n): number {\n const ordersBySide =\n side === OrderSide.SELL\n ? sellOrdersFilter_by_symbol(orders, symbol)\n : buyOrdersFilter_by_symbol(orders, symbol);\n return ordersBySide.reduce((acc, cur) => {\n return acc + cur.quantity;\n }, 0);\n}\n\nexport function getPositonsAndOrdersNotionalBySymbol(inputs: {\n positions: API.Position[];\n orders: API.Order[];\n symbol: string;\n markPrice: number;\n}): number {\n const { positions, orders, symbol, markPrice } = inputs;\n const positionQty = getQtyFromPositions(positions, symbol);\n const buyOrdersQty = getQtyFromOrdersBySide(orders, symbol, OrderSide.BUY);\n const sellOrdersQty = getQtyFromOrdersBySide(orders, symbol, OrderSide.SELL);\n\n const markPriceDecimal = new Decimal(markPrice);\n\n return markPriceDecimal\n .mul(positionQty)\n .add(markPriceDecimal.mul(new Decimal(buyOrdersQty).add(sellOrdersQty)))\n .abs()\n .toNumber();\n}\n\nexport type TotalInitialMarginWithOrdersInputs = {\n positions: API.Position[];\n orders: API.Order[];\n // account: API.AccountInfo;\n markPrices: { [key: string]: number };\n symbolInfo: any;\n IMR_Factors: { [key: string]: number };\n} & Pick<IMRInputs, \"maxLeverage\">;\n\n/**\n * 计算用戶已使用初始保證金加總 ( 包含 position / orders )\n */\nexport function totalInitialMarginWithOrders(\n inputs: TotalInitialMarginWithOrdersInputs\n): number {\n const {\n positions,\n orders,\n markPrices,\n IMR_Factors,\n maxLeverage,\n symbolInfo,\n } = inputs;\n\n const symbols = extractSymbols(positions, orders);\n\n const total_initial_margin_with_orders = symbols.reduce((acc, cur) => {\n const symbol = cur;\n const positionQty = getQtyFromPositions(positions, symbol);\n const buyOrdersQty = getQtyFromOrdersBySide(orders, symbol, OrderSide.BUY);\n const sellOrdersQty = getQtyFromOrdersBySide(\n orders,\n symbol,\n OrderSide.SELL\n );\n\n const markPrice = markPrices[symbol] || 0;\n\n //---\n const positionQtyWithOrders = positionQtyWithOrders_by_symbol({\n positionQty,\n buyOrdersQty,\n sellOrdersQty,\n });\n\n //---\n const position_notional_with_orders = positionNotionalWithOrder_by_symbol({\n markPrice,\n positionQtyWithOrders,\n });\n\n //----\n const markPriceDecimal = new Decimal(markPrice);\n\n const imr = IMR({\n positionNotional: markPriceDecimal.mul(positionQty).toNumber(),\n ordersNotional: markPriceDecimal\n .mul(new Decimal(buyOrdersQty).add(sellOrdersQty))\n .toNumber(),\n maxLeverage,\n IMR_Factor: IMR_Factors[symbol],\n baseIMR: symbolInfo[symbol](\"base_imr\", 0),\n });\n\n return position_notional_with_orders.mul(imr).add(acc).toNumber();\n }, 0);\n\n return total_initial_margin_with_orders;\n}\n\n/**\n * 把订单按照symbol分组, 因为一个symbol可以有多个挂单\n */\nexport function groupOrdersBySymbol(orders: API.Order[]) {\n const symbols: { [key: string]: API.Order[] } = {};\n\n orders.forEach((item) => {\n if (!symbols[item.symbol]) {\n symbols[item.symbol] = [];\n }\n\n symbols[item.symbol].push(item);\n });\n\n return symbols;\n}\n\n/**\n * Extracts all unique symbols from positions and orders.\n * @param positions - An array of position objects.\n * @param orders - An array of order objects.\n * @returns An array of unique symbols.\n */\nexport function extractSymbols(\n positions: Pick<API.Position, \"symbol\">[],\n orders: Pick<API.Order, \"symbol\">[]\n): string[] {\n const symbols = new Set<string>();\n\n positions.forEach((item) => {\n symbols.add(item.symbol);\n });\n\n orders.forEach((item) => {\n symbols.add(item.symbol);\n });\n\n return Array.from(symbols);\n}\n\n//=========== max qty ==================\n\n// function otherIM(inputs: {}): number {}\n\nexport type OtherIMsInputs = {\n // 传入除当前symbol外的其他symbol的仓位列表\n positions: API.Position[];\n // 传入除当前symbol外的其他symbol的订单列表\n orders: API.Order[];\n\n markPrices: { [key: string]: number };\n maxLeverage: number;\n symbolInfo: any;\n IMR_Factors: { [key: string]: number };\n};\n/**\n * 除当前symbol外的其他symbol已占用的总保证金\n */\nexport function otherIMs(inputs: OtherIMsInputs): number {\n const {\n orders,\n positions,\n maxLeverage,\n IMR_Factors,\n symbolInfo,\n markPrices,\n } = inputs;\n\n const symbols = extractSymbols(positions, orders);\n\n return symbols\n .reduce((acc, cur) => {\n const symbol = cur;\n\n if (typeof markPrices[symbol] === \"undefined\") {\n console.warn(\"markPrices[%s] is undefined\", symbol);\n return acc;\n }\n\n const markPriceDecimal = new Decimal(markPrices[symbol] || 0);\n\n const positionQty = getQtyFromPositions(positions, symbol);\n const positionNotional = markPriceDecimal.mul(positionQty).toNumber();\n\n const buyOrdersQty = getQtyFromOrdersBySide(\n orders,\n symbol,\n OrderSide.BUY\n );\n const sellOrdersQty = getQtyFromOrdersBySide(\n orders,\n symbol,\n OrderSide.SELL\n );\n\n const ordersNotional = markPriceDecimal\n .mul(new Decimal(buyOrdersQty).add(sellOrdersQty))\n .toNumber();\n\n const IMR_Factor = IMR_Factors[symbol];\n\n if (!IMR_Factor) {\n console.warn(\"IMR_Factor is not found:\", symbol);\n return acc;\n }\n\n const imr = IMR({\n maxLeverage,\n\n IMR_Factor,\n baseIMR: symbolInfo[symbol](\"base_imr\", 0),\n positionNotional,\n ordersNotional,\n });\n\n const positionQtyWithOrders = positionQtyWithOrders_by_symbol({\n positionQty,\n buyOrdersQty,\n sellOrdersQty,\n });\n\n const positionNotionalWithOrders = positionNotionalWithOrder_by_symbol({\n markPrice: markPrices[symbol] || 0,\n positionQtyWithOrders,\n });\n\n return acc.add(positionNotionalWithOrders.mul(imr));\n }, zero)\n .toNumber();\n}\n\nexport type MaxQtyInputs = {\n symbol: string;\n\n //單次開倉最大 Qty 限制, /v1/public/info.base_max\n baseMaxQty: number;\n /**\n * 用户保证金总额(USDC 计价), 可以由 totalCollateral 计算得出\n * @see totalCollateral\n */\n totalCollateral: number;\n maxLeverage: number;\n baseIMR: number;\n /**\n * @see otherIMs\n */\n otherIMs: number;\n markPrice: number;\n // 已开仓数量\n positionQty: number;\n // 已挂多单数量\n buyOrdersQty: number;\n // 已挂空单数量\n sellOrdersQty: number;\n\n IMR_Factor: number;\n\n takerFeeRate: number;\n};\n\n/**\n * 最大可下单数量\n * @see {@link https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Max-Order-QTY}\n */\nexport function maxQty(\n side: OrderSide,\n inputs: MaxQtyInputs,\n options?: ResultOptions\n): number {\n if (side === OrderSide.BUY) {\n return maxQtyByLong(inputs);\n }\n return maxQtyByShort(inputs);\n}\n\nexport function maxQtyByLong(\n inputs: Omit<MaxQtyInputs, \"side\">,\n options?: ResultOptions\n): number {\n try {\n const {\n baseMaxQty,\n totalCollateral,\n otherIMs,\n maxLeverage,\n baseIMR,\n markPrice,\n IMR_Factor,\n positionQty,\n buyOrdersQty,\n takerFeeRate,\n } = inputs;\n\n if (totalCollateral === 0) {\n return 0;\n }\n\n const totalCollateralDecimal = new Decimal(totalCollateral);\n\n const factor_1 = totalCollateralDecimal\n .sub(otherIMs)\n .div(\n new Decimal(takerFeeRate)\n .mul(2)\n .mul(0.0001)\n .add(Math.max(1 / maxLeverage, baseIMR))\n )\n .div(markPrice)\n .mul(0.995)\n .sub(new Decimal(positionQty).add(buyOrdersQty))\n .toNumber();\n\n if (positionQty === 0 && buyOrdersQty === 0) {\n return Math.min(baseMaxQty, factor_1);\n }\n\n const factor_2 = totalCollateralDecimal\n .sub(otherIMs)\n .div(IMR_Factor)\n .toPower(1 / 1.8)\n .div(markPrice)\n .sub(\n new Decimal(positionQty)\n .add(buyOrdersQty)\n // .abs()\n .div(new Decimal(takerFeeRate).mul(2).mul(0.0001).add(1))\n )\n .mul(0.995)\n .toNumber();\n\n return Math.min(baseMaxQty, factor_1, factor_2);\n } catch (error) {\n return 0;\n }\n}\n\nexport function maxQtyByShort(\n inputs: Omit<MaxQtyInputs, \"side\">,\n options?: ResultOptions\n): number {\n try {\n const {\n baseMaxQty,\n totalCollateral,\n otherIMs,\n maxLeverage,\n baseIMR,\n markPrice,\n IMR_Factor,\n positionQty,\n buyOrdersQty,\n sellOrdersQty,\n takerFeeRate,\n } = inputs;\n\n const totalCollateralDecimal = new Decimal(totalCollateral);\n\n const factor_1 = totalCollateralDecimal\n .sub(otherIMs)\n .div(\n new Decimal(takerFeeRate)\n .mul(2)\n .mul(0.0001)\n .add(Math.max(1 / maxLeverage, baseIMR))\n )\n .div(markPrice)\n .mul(0.995)\n .add(new Decimal(positionQty).add(sellOrdersQty))\n\n .toNumber();\n\n if (positionQty === 0 && buyOrdersQty === 0) {\n return Math.min(baseMaxQty, factor_1);\n }\n\n const factor_2 = totalCollateralDecimal\n .sub(otherIMs)\n .div(IMR_Factor)\n .toPower(1 / 1.8)\n .div(markPrice)\n .add(\n new Decimal(positionQty)\n .add(sellOrdersQty)\n // .abs()\n .div(new Decimal(takerFeeRate).mul(2).mul(0.0001).add(1))\n )\n .mul(0.995)\n .toNumber();\n\n return Math.min(baseMaxQty, factor_1, factor_2);\n } catch (error) {\n return 0;\n }\n}\n\nexport type TotalMarginRatioInputs = {\n totalCollateral: number;\n markPrices: { [key: string]: number };\n positions: API.Position[];\n};\n/**\n * @see {@link https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Total-Margin-Ratio}\n */\nexport function totalMarginRatio(\n inputs: TotalMarginRatioInputs,\n dp?: number\n): number {\n const { totalCollateral, markPrices, positions } = inputs;\n\n if (totalCollateral === 0) {\n return 0;\n }\n\n const totalCollateralDecimal = new Decimal(totalCollateral);\n\n const totalPositionNotional = positions.reduce((acc, cur) => {\n const markPrice = markPrices[cur.symbol] || 0;\n return acc.add(new Decimal(cur.position_qty).mul(markPrice).abs());\n }, zero);\n\n if (totalPositionNotional.eq(zero)) {\n return 0;\n }\n\n return totalCollateralDecimal.div(totalPositionNotional).toNumber();\n}\n\nexport type TotalUnrealizedROIInputs = {\n totalUnrealizedPnL: number;\n totalValue: number;\n};\n\n/**\n * totalUnrealizedROI\n * @see {@link https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Total-Unrealized-ROI}\n */\nexport function totalUnrealizedROI(inputs: TotalUnrealizedROIInputs) {\n const { totalUnrealizedPnL, totalValue } = inputs;\n\n return new Decimal(totalUnrealizedPnL)\n .div(totalValue - totalUnrealizedPnL)\n .toNumber();\n}\n\n/**\n * @see {@link https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Current-account-leverage}\n */\nexport function currentLeverage(totalMarginRatio: number) {\n if (totalMarginRatio === 0) {\n return 0;\n }\n return 1 / totalMarginRatio;\n}\n\nexport type AvailableBalanceInputs = {\n USDCHolding: number;\n unsettlementPnL: number;\n};\nexport function availableBalance(inputs: AvailableBalanceInputs) {\n const { USDCHolding, unsettlementPnL } = inputs;\n\n return new Decimal(USDCHolding).add(unsettlementPnL).toNumber();\n}\n\nexport type AccountMMRInputs = {\n // Total Maintenance Margin of all positions of the user (USDC)\n positionsMMR: number;\n /**\n * Notional sum of all positions,\n * positions.totalNotional()\n */\n positionsNotional: number;\n};\n\n/**\n * total maintenance margin ratio\n * @param inputs AccountMMRInputs\n * @returns number|null\n */\nexport function MMR(inputs: AccountMMRInputs): number | null {\n // If the user does not have any positions, return null\n if (inputs.positionsNotional === 0) {\n return null;\n }\n return new Decimal(inputs.positionsMMR)\n .div(inputs.positionsNotional)\n .toNumber();\n}\n","import { API } from \"@orderly.network/types\";\nimport { Decimal, zero } from \"@orderly.network/utils\";\nimport { notional } from \"./positions\";\n\n/**\n * Maximum price when placing an order\n * @see https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Max-price\n */\nexport function maxPrice(markprice: number, range: number) {\n return markprice * (1 + range);\n}\n\n/**\n * Minimum price when placing an order\n * @see https://wootraders.atlassian.net/wiki/spaces/WOOFI/pages/346030144/v2#Min-price\n */\nexport function minPrice(markprice: number, range: number) {\n return markprice * (1 - range);\n}\n\n/**\n * Scrope price when placing an order\n * @returns number\n */\nexport function scropePrice(\n price: number,\n scrope: number,\n side: \"BUY\" | \"SELL\"\n): number {\n if (side === \"BUY\") {\n return price * (1 - scrope);\n }\n return price * (1 + scrope);\n}\n\nexport type EstimatedLiquidationPriceInputs = {\n totalCollateral: number;\n markPrice: number;\n baseMMR: number;\n baseIMR: number;\n IMR_Factor: number;\n positions: Pick<\n API.PositionExt,\n \"position_qty\" | \"mark_price\" | \"symbol\" | \"mmr\"\n >[];\n newOrder: {\n symbol: string;\n qty: number;\n price: number;\n };\n};\n\n/**\n * Estimated liquidation price\n * @param inputs\n * @returns\n */\nexport function estLiqPrice(inputs: EstimatedLiquidationPriceInputs): number {\n const {\n positions,\n newOrder,\n totalCollateral,\n markPrice,\n baseIMR,\n baseMMR,\n IMR_Factor,\n } = inputs;\n // opened positions for the symbol\n let currentPosition:\n | Pick<API.PositionExt, \"position_qty\" | \"mark_price\" | \"symbol\" | \"mmr\">\n | undefined = undefined;\n\n let newTotalMM = zero;\n\n const newOrderNotional = new Decimal(newOrder.qty).mul(newOrder.price);\n\n for (let index = 0; index < positions.length; index++) {\n const position = positions[index];\n let notional = new Decimal(position.position_qty).mul(position.mark_price);\n if (newOrder.symbol === position.symbol) {\n currentPosition = position;\n notional = notional.add(newOrderNotional);\n }\n\n newTotalMM = newTotalMM.add(notional.abs().mul(position.mmr));\n }\n\n const newMMR = Math.max(\n baseMMR,\n new Decimal(baseMMR)\n .div(baseIMR)\n .mul(IMR_Factor)\n .mul(\n newOrderNotional\n .add(\n !!currentPosition\n ? new Decimal(currentPosition.position_qty).mul(\n currentPosition.mark_price\n )\n : zero\n )\n .abs()\n )\n .toPower(4 / 5)\n .toNumber()\n );\n\n const newQty = new Decimal(newOrder.qty).add(\n currentPosition?.position_qty ?? 0\n );\n\n if (newQty.eq(0)) {\n return 0;\n }\n\n const price = new Decimal(markPrice)\n .add(\n new Decimal(totalCollateral)\n .sub(newTotalMM)\n .div(newQty.abs().mul(newMMR).sub(newQty))\n )\n .toNumber();\n\n return Math.max(0, price);\n}\n\nexport type EstimatedLeverageInputs = {\n totalCollateral: number;\n positions: Pick<API.PositionExt, \"position_qty\" | \"mark_price\" | \"symbol\">[];\n newOrder: {\n symbol: string;\n qty: number;\n price: number;\n };\n};\n\n/**\n * Estimated leverage\n * @param inputs EstimtedLeverageInputs\n * @returns number\n */\nexport function estLeverage(inputs: EstimatedLeverageInputs): number | null {\n const { totalCollateral, positions, newOrder } = inputs;\n if (totalCollateral <= 0) {\n return null;\n }\n let hasPosition = false;\n let sumPositionNotional = positions.reduce((acc, cur) => {\n acc = acc.add(\n new Decimal(new Decimal(cur.position_qty).mul(cur.mark_price).abs())\n );\n\n if (cur.symbol === newOrder.symbol) {\n hasPosition = true;\n acc = acc.add(new Decimal(newOrder.qty).mul(newOrder.price));\n }\n\n return acc;\n }, zero);\n\n if (!hasPosition) {\n sumPositionNotional = sumPositionNotional.add(\n new Decimal(newOrder.qty).mul(newOrder.price).abs()\n );\n }\n\n if (sumPositionNotional.eq(zero)) {\n return null;\n }\n\n const totalMarginRatio = new Decimal(totalCollateral).div(\n sumPositionNotional\n );\n\n return new Decimal(1)\n .div(totalMarginRatio)\n .toDecimalPlaces(2, Decimal.ROUND_HALF_EVEN)\n .toNumber();\n}\n"],"mappings":"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","names":["IMR","totalCollateral","MMR","totalNotional","MMR","import_utils","totalUnsettlementPnL","totalCollateral","otherIMs","totalUnrealizedPnL","totalValue","totalMarginRatio","unsettlementPnL","MMR","import_utils","totalCollateral","notional","totalMarginRatio"]}
package/dist/index.mjs CHANGED
@@ -7,9 +7,9 @@ var __export = (target, all) => {
7
7
  // src/version.ts
8
8
  if (typeof window !== "undefined") {
9
9
  window.__ORDERLY_VERSION__ = window.__ORDERLY_VERSION__ || {};
10
- window.__ORDERLY_VERSION__["@orderly.network/perp"] = "1.0.28";
10
+ window.__ORDERLY_VERSION__["@orderly.network/perp"] = "2.0.0";
11
11
  }
12
- var version_default = "1.0.28";
12
+ var version_default = "2.0.0";
13
13
 
14
14
  // src/positions.ts
15
15
  var positions_exports = {};
@@ -25,7 +25,7 @@ __export(positions_exports, {
25
25
  unrealizedPnLROI: () => unrealizedPnLROI,
26
26
  unsettlementPnL: () => unsettlementPnL
27
27
  });
28
- import { Decimal } from "@orderly.network/utils";
28
+ import { Decimal, zero } from "@orderly.network/utils";
29
29
 
30
30
  // src/constants.ts
31
31
  var IMRFactorPower = 4 / 5;
@@ -58,21 +58,25 @@ function totalUnrealizedPnL(positions) {
58
58
  }, 0);
59
59
  }
60
60
  function liqPrice(inputs) {
61
- const { markPrice, totalCollateral: totalCollateral2, positionQty, MMR: MMR2 } = inputs;
62
- const totalNotional2 = notional(positionQty, markPrice);
61
+ const { markPrice, totalCollateral: totalCollateral2, positions, positionQty, MMR: MMR3 } = inputs;
63
62
  if (positionQty === 0) {
64
63
  return 0;
65
64
  }
65
+ const totalNotional2 = positions.reduce((acc, cur) => {
66
+ return acc.add(
67
+ new Decimal(notional(cur.position_qty, cur.mark_price)).mul(cur.mmr)
68
+ );
69
+ }, zero);
66
70
  return Math.max(
67
71
  new Decimal(markPrice).add(
68
- new Decimal(totalCollateral2).sub(new Decimal(totalNotional2).mul(MMR2)).div(new Decimal(positionQty).abs().mul(MMR2).sub(positionQty))
72
+ new Decimal(totalCollateral2).sub(totalNotional2).div(new Decimal(positionQty).abs().mul(MMR3).sub(positionQty))
69
73
  ).toNumber(),
70
74
  0
71
75
  );
72
76
  }
73
77
  function maintenanceMargin(inputs) {
74
- const { positionQty, markPrice, MMR: MMR2 } = inputs;
75
- return new Decimal(positionQty).mul(markPrice).mul(MMR2).abs().toNumber();
78
+ const { positionQty, markPrice, MMR: MMR3 } = inputs;
79
+ return new Decimal(positionQty).mul(markPrice).mul(MMR3).abs().toNumber();
76
80
  }
77
81
  function unsettlementPnL(inputs) {
78
82
  const {
@@ -117,6 +121,7 @@ function MMR(inputs) {
117
121
  var account_exports = {};
118
122
  __export(account_exports, {
119
123
  IMR: () => IMR,
124
+ MMR: () => MMR2,
120
125
  availableBalance: () => availableBalance,
121
126
  buyOrdersFilter_by_symbol: () => buyOrdersFilter_by_symbol,
122
127
  currentLeverage: () => currentLeverage,
@@ -140,7 +145,7 @@ __export(account_exports, {
140
145
  totalUnrealizedROI: () => totalUnrealizedROI,
141
146
  totalValue: () => totalValue
142
147
  });
143
- import { Decimal as Decimal2, zero } from "@orderly.network/utils";
148
+ import { Decimal as Decimal2, zero as zero2 } from "@orderly.network/utils";
144
149
  import {
145
150
  OrderSide
146
151
  } from "@orderly.network/types";
@@ -148,11 +153,12 @@ function totalValue(inputs) {
148
153
  const { totalUnsettlementPnL: totalUnsettlementPnL2, USDCHolding, nonUSDCHolding } = inputs;
149
154
  const nonUSDCHoldingValue = nonUSDCHolding.reduce((acc, cur) => {
150
155
  return new Decimal2(cur.holding).mul(cur.markPrice).add(acc);
151
- }, zero);
156
+ }, zero2);
152
157
  return nonUSDCHoldingValue.add(USDCHolding).add(totalUnsettlementPnL2);
153
158
  }
154
159
  function freeCollateral(inputs) {
155
- return inputs.totalCollateral.sub(inputs.totalInitialMarginWithOrders);
160
+ const value = inputs.totalCollateral.sub(inputs.totalInitialMarginWithOrders);
161
+ return value.isNegative() ? zero2 : value;
156
162
  }
157
163
  function totalCollateral(inputs) {
158
164
  const { USDCHolding, nonUSDCHolding } = inputs;
@@ -336,7 +342,7 @@ function otherIMs(inputs) {
336
342
  positionQtyWithOrders
337
343
  });
338
344
  return acc.add(positionNotionalWithOrders.mul(imr));
339
- }, zero).toNumber();
345
+ }, zero2).toNumber();
340
346
  }
341
347
  function maxQty(side, inputs, options) {
342
348
  if (side === OrderSide.BUY) {
@@ -344,7 +350,7 @@ function maxQty(side, inputs, options) {
344
350
  }
345
351
  return maxQtyByShort(inputs);
346
352
  }
347
- function maxQtyByLong(inputs) {
353
+ function maxQtyByLong(inputs, options) {
348
354
  try {
349
355
  const {
350
356
  baseMaxQty,
@@ -376,7 +382,7 @@ function maxQtyByLong(inputs) {
376
382
  return 0;
377
383
  }
378
384
  }
379
- function maxQtyByShort(inputs) {
385
+ function maxQtyByShort(inputs, options) {
380
386
  try {
381
387
  const {
382
388
  baseMaxQty,
@@ -415,8 +421,8 @@ function totalMarginRatio(inputs, dp) {
415
421
  const totalPositionNotional = positions.reduce((acc, cur) => {
416
422
  const markPrice = markPrices[cur.symbol] || 0;
417
423
  return acc.add(new Decimal2(cur.position_qty).mul(markPrice).abs());
418
- }, zero);
419
- if (totalPositionNotional.eq(zero)) {
424
+ }, zero2);
425
+ if (totalPositionNotional.eq(zero2)) {
420
426
  return 0;
421
427
  }
422
428
  return totalCollateralDecimal.div(totalPositionNotional).toNumber();
@@ -435,19 +441,108 @@ function availableBalance(inputs) {
435
441
  const { USDCHolding, unsettlementPnL: unsettlementPnL2 } = inputs;
436
442
  return new Decimal2(USDCHolding).add(unsettlementPnL2).toNumber();
437
443
  }
444
+ function MMR2(inputs) {
445
+ if (inputs.positionsNotional === 0) {
446
+ return null;
447
+ }
448
+ return new Decimal2(inputs.positionsMMR).div(inputs.positionsNotional).toNumber();
449
+ }
438
450
 
439
451
  // src/order.ts
440
452
  var order_exports = {};
441
453
  __export(order_exports, {
454
+ estLeverage: () => estLeverage,
455
+ estLiqPrice: () => estLiqPrice,
442
456
  maxPrice: () => maxPrice,
443
- minPrice: () => minPrice
457
+ minPrice: () => minPrice,
458
+ scropePrice: () => scropePrice
444
459
  });
460
+ import { Decimal as Decimal3, zero as zero3 } from "@orderly.network/utils";
445
461
  function maxPrice(markprice, range) {
446
462
  return markprice * (1 + range);
447
463
  }
448
464
  function minPrice(markprice, range) {
449
465
  return markprice * (1 - range);
450
466
  }
467
+ function scropePrice(price, scrope, side) {
468
+ if (side === "BUY") {
469
+ return price * (1 - scrope);
470
+ }
471
+ return price * (1 + scrope);
472
+ }
473
+ function estLiqPrice(inputs) {
474
+ var _a;
475
+ const {
476
+ positions,
477
+ newOrder,
478
+ totalCollateral: totalCollateral2,
479
+ markPrice,
480
+ baseIMR,
481
+ baseMMR,
482
+ IMR_Factor
483
+ } = inputs;
484
+ let currentPosition = void 0;
485
+ let newTotalMM = zero3;
486
+ const newOrderNotional = new Decimal3(newOrder.qty).mul(newOrder.price);
487
+ for (let index = 0; index < positions.length; index++) {
488
+ const position = positions[index];
489
+ let notional2 = new Decimal3(position.position_qty).mul(position.mark_price);
490
+ if (newOrder.symbol === position.symbol) {
491
+ currentPosition = position;
492
+ notional2 = notional2.add(newOrderNotional);
493
+ }
494
+ newTotalMM = newTotalMM.add(notional2.abs().mul(position.mmr));
495
+ }
496
+ const newMMR = Math.max(
497
+ baseMMR,
498
+ new Decimal3(baseMMR).div(baseIMR).mul(IMR_Factor).mul(
499
+ newOrderNotional.add(
500
+ !!currentPosition ? new Decimal3(currentPosition.position_qty).mul(
501
+ currentPosition.mark_price
502
+ ) : zero3
503
+ ).abs()
504
+ ).toPower(4 / 5).toNumber()
505
+ );
506
+ const newQty = new Decimal3(newOrder.qty).add(
507
+ (_a = currentPosition == null ? void 0 : currentPosition.position_qty) != null ? _a : 0
508
+ );
509
+ if (newQty.eq(0)) {
510
+ return 0;
511
+ }
512
+ const price = new Decimal3(markPrice).add(
513
+ new Decimal3(totalCollateral2).sub(newTotalMM).div(newQty.abs().mul(newMMR).sub(newQty))
514
+ ).toNumber();
515
+ return Math.max(0, price);
516
+ }
517
+ function estLeverage(inputs) {
518
+ const { totalCollateral: totalCollateral2, positions, newOrder } = inputs;
519
+ if (totalCollateral2 <= 0) {
520
+ return null;
521
+ }
522
+ let hasPosition = false;
523
+ let sumPositionNotional = positions.reduce((acc, cur) => {
524
+ acc = acc.add(
525
+ new Decimal3(new Decimal3(cur.position_qty).mul(cur.mark_price).abs())
526
+ );
527
+ if (cur.symbol === newOrder.symbol) {
528
+ hasPosition = true;
529
+ acc = acc.add(new Decimal3(newOrder.qty).mul(newOrder.price));
530
+ }
531
+ return acc;
532
+ }, zero3);
533
+ if (!hasPosition) {
534
+ sumPositionNotional = sumPositionNotional.add(
535
+ new Decimal3(newOrder.qty).mul(newOrder.price).abs()
536
+ );
537
+ }
538
+ if (sumPositionNotional.eq(zero3)) {
539
+ return null;
540
+ }
541
+ const totalMarginRatio2 = new Decimal3(totalCollateral2).div(
542
+ sumPositionNotional
543
+ );
544
+ return new Decimal3(1).div(totalMarginRatio2).toDecimalPlaces(2, Decimal3.ROUND_HALF_EVEN).toNumber();
545
+ }
451
546
  export {
452
547
  account_exports as account,
453
548
  order_exports as order,