@orderly.network/perp 4.10.2 → 5.0.0-beta.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.mjs CHANGED
@@ -1,3 +1,6 @@
1
+ import { Decimal, zero, getTPSLDirection } from '@orderly.network/utils';
2
+ import { OrderSide, MarginMode, OrderType } from '@orderly.network/types';
3
+
1
4
  var __defProp = Object.defineProperty;
2
5
  var __export = (target, all) => {
3
6
  for (var name in all)
@@ -7,11 +10,11 @@ var __export = (target, all) => {
7
10
  // src/version.ts
8
11
  if (typeof window !== "undefined") {
9
12
  window.__ORDERLY_VERSION__ = window.__ORDERLY_VERSION__ || {};
10
- window.__ORDERLY_VERSION__["@orderly.network/perp"] = "4.10.2";
13
+ window.__ORDERLY_VERSION__["@orderly.network/perp"] = "5.0.0-beta.0";
11
14
  }
12
- var version_default = "4.10.2";
15
+ var version_default = "5.0.0-beta.0";
13
16
 
14
- // src/positions.ts
17
+ // src/positions/index.ts
15
18
  var positions_exports = {};
16
19
  __export(positions_exports, {
17
20
  MMR: () => MMR,
@@ -21,6 +24,7 @@ __export(positions_exports, {
21
24
  estPriceForTP: () => estPriceForTP,
22
25
  estPriceFromOffsetForTP: () => estPriceFromOffsetForTP,
23
26
  liqPrice: () => liqPrice,
27
+ liquidationPriceIsolated: () => liquidationPriceIsolated,
24
28
  maintenanceMargin: () => maintenanceMargin,
25
29
  maxPositionLeverage: () => maxPositionLeverage,
26
30
  maxPositionNotional: () => maxPositionNotional,
@@ -32,34 +36,8 @@ __export(positions_exports, {
32
36
  unrealizedPnLROI: () => unrealizedPnLROI,
33
37
  unsettlementPnL: () => unsettlementPnL
34
38
  });
35
- import { Decimal as Decimal2, zero } from "@orderly.network/utils";
36
-
37
- // src/constants.ts
38
- var IMRFactorPower = 4 / 5;
39
-
40
- // src/utils.ts
41
- import { Decimal } from "@orderly.network/utils";
42
- var DMax = (...values) => {
43
- if (values.length === 0) {
44
- throw new Error("DMax requires at least one argument");
45
- }
46
- const decimals = values.map(
47
- (val) => val instanceof Decimal ? val : new Decimal(val)
48
- );
49
- let max = decimals[0];
50
- for (let i = 1; i < decimals.length; i++) {
51
- if (decimals[i].gte(max)) {
52
- max = decimals[i];
53
- }
54
- }
55
- return max;
56
- };
57
-
58
- // src/positions.ts
59
- var MaxIterates = 30;
60
- var CONVERGENCE_THRESHOLD = 1e-4;
61
39
  function notional(qty, mark_price) {
62
- return new Decimal2(qty).mul(mark_price).abs().toNumber();
40
+ return new Decimal(qty).mul(mark_price).abs().toNumber();
63
41
  }
64
42
  function totalNotional(positions) {
65
43
  return positions.reduce((acc, cur) => {
@@ -67,13 +45,13 @@ function totalNotional(positions) {
67
45
  }, 0);
68
46
  }
69
47
  function unrealizedPnL(inputs) {
70
- return new Decimal2(inputs.qty).mul(inputs.markPrice - inputs.openPrice).toNumber();
48
+ return new Decimal(inputs.qty).mul(inputs.markPrice - inputs.openPrice).toNumber();
71
49
  }
72
50
  function unrealizedPnLROI(inputs) {
73
- const { openPrice, IMR: IMR2 } = inputs;
74
- if (inputs.unrealizedPnL === 0 || inputs.positionQty === 0 || openPrice === 0 || IMR2 === 0)
51
+ const { openPrice, IMR: IMR4 } = inputs;
52
+ if (inputs.unrealizedPnL === 0 || inputs.positionQty === 0 || openPrice === 0 || IMR4 === 0)
75
53
  return 0;
76
- return new Decimal2(inputs.unrealizedPnL).div(new Decimal2(Math.abs(inputs.positionQty)).mul(openPrice).mul(IMR2)).toNumber();
54
+ return new Decimal(inputs.unrealizedPnL).div(new Decimal(Math.abs(inputs.positionQty)).mul(openPrice).mul(IMR4)).toNumber();
77
55
  }
78
56
  function totalUnrealizedPnL(positions) {
79
57
  return positions.reduce((acc, cur) => {
@@ -84,18 +62,40 @@ function totalUnrealizedPnL(positions) {
84
62
  });
85
63
  }, 0);
86
64
  }
65
+
66
+ // src/constants.ts
67
+ var IMRFactorPower = 4 / 5;
68
+ var DMax = (...values) => {
69
+ if (values.length === 0) {
70
+ throw new Error("DMax requires at least one argument");
71
+ }
72
+ const decimals = values.map(
73
+ (val) => val instanceof Decimal ? val : new Decimal(val)
74
+ );
75
+ let max = decimals[0];
76
+ for (let i = 1; i < decimals.length; i++) {
77
+ if (decimals[i].gte(max)) {
78
+ max = decimals[i];
79
+ }
80
+ }
81
+ return max;
82
+ };
83
+
84
+ // src/positions/liqPrice.ts
85
+ var MaxIterates = 30;
86
+ var CONVERGENCE_THRESHOLD = 1e-4;
87
87
  var mmForOtherSymbols = (positions) => {
88
88
  return positions.reduce((acc, cur) => {
89
89
  return acc.add(
90
- new Decimal2(cur.position_qty).abs().mul(cur.mark_price).mul(cur.mmr)
90
+ new Decimal(cur.position_qty).abs().mul(cur.mark_price).mul(cur.mmr)
91
91
  );
92
92
  }, zero);
93
93
  };
94
94
  var calculateLiqPrice = (markPrice, positionQty, MMR3, totalCollateral2, positions) => {
95
- const decimalMarkPrice = new Decimal2(markPrice);
96
- const absQty = new Decimal2(positionQty).abs();
95
+ const decimalMarkPrice = new Decimal(markPrice);
96
+ const absQty = new Decimal(positionQty).abs();
97
97
  const denominator = absQty.mul(MMR3).sub(positionQty);
98
- const liqPrice2 = new Decimal2(totalCollateral2).sub(absQty.mul(decimalMarkPrice).mul(MMR3)).sub(mmForOtherSymbols(positions)).div(denominator).add(decimalMarkPrice);
98
+ const liqPrice2 = new Decimal(totalCollateral2).sub(absQty.mul(decimalMarkPrice).mul(MMR3)).sub(mmForOtherSymbols(positions)).div(denominator).add(decimalMarkPrice);
99
99
  return DMax(liqPrice2, zero);
100
100
  };
101
101
  var compareCollateralWithMM = (inputs) => {
@@ -109,18 +109,18 @@ var compareCollateralWithMM = (inputs) => {
109
109
  IMRFactor,
110
110
  positions
111
111
  } = inputs;
112
- const decimalPositionQty = new Decimal2(positionQty);
113
- const collateral = new Decimal2(totalCollateral2).sub(decimalPositionQty.mul(markPrice)).add(decimalPositionQty.mul(price));
112
+ const decimalPositionQty = new Decimal(positionQty);
113
+ const collateral = new Decimal(totalCollateral2).sub(decimalPositionQty.mul(markPrice)).add(decimalPositionQty.mul(price));
114
114
  const mm = decimalPositionQty.abs().mul(price).mul(
115
115
  Math.max(
116
116
  baseMMR,
117
- new Decimal2(baseMMR).div(baseIMR).mul(IMRFactor).mul(decimalPositionQty.mul(price).abs().toPower(IMRFactorPower)).toNumber()
117
+ new Decimal(baseMMR).div(baseIMR).mul(IMRFactor).mul(decimalPositionQty.mul(price).abs().toPower(IMRFactorPower)).toNumber()
118
118
  )
119
119
  ).add(mmForOtherSymbols(positions));
120
120
  return collateral.gte(mm);
121
121
  };
122
122
  };
123
- var liqPrice = (inputs) => {
123
+ function liqPrice(inputs) {
124
124
  const {
125
125
  positionQty,
126
126
  markPrice,
@@ -165,7 +165,7 @@ var liqPrice = (inputs) => {
165
165
  if (liqPriceLeft.gte(liqPriceRight)) {
166
166
  return liqPriceRight.toNumber();
167
167
  }
168
- const mid = new Decimal2(liqPriceLeft).add(liqPriceRight).div(2);
168
+ const mid = new Decimal(liqPriceLeft).add(liqPriceRight).div(2);
169
169
  if (compareCollateralWithMMFunc(mid)) {
170
170
  liqPriceRight = mid;
171
171
  } else {
@@ -189,8 +189,8 @@ var liqPrice = (inputs) => {
189
189
  positionQty,
190
190
  Math.max(
191
191
  baseIMR,
192
- new Decimal2(baseMMR).div(baseIMR).mul(IMRFactor).mul(
193
- new Decimal2(positionQty).mul(liqPriceRight).abs().toPower(IMRFactorPower)
192
+ new Decimal(baseMMR).div(baseIMR).mul(IMRFactor).mul(
193
+ new Decimal(positionQty).mul(liqPriceRight).abs().toPower(IMRFactorPower)
194
194
  ).toNumber()
195
195
  ),
196
196
  totalCollateral2,
@@ -221,10 +221,10 @@ var liqPrice = (inputs) => {
221
221
  }
222
222
  return liqPriceLeft.toNumber();
223
223
  }
224
- };
224
+ }
225
225
  function maintenanceMargin(inputs) {
226
226
  const { positionQty, markPrice, MMR: MMR3 } = inputs;
227
- return new Decimal2(positionQty).mul(markPrice).mul(MMR3).abs().toNumber();
227
+ return new Decimal(positionQty).mul(markPrice).mul(MMR3).abs().toNumber();
228
228
  }
229
229
  function unsettlementPnL(inputs) {
230
230
  const {
@@ -234,8 +234,8 @@ function unsettlementPnL(inputs) {
234
234
  sumUnitaryFunding,
235
235
  lastSumUnitaryFunding
236
236
  } = inputs;
237
- const qty = new Decimal2(positionQty);
238
- return qty.mul(markPrice).sub(costPosition).sub(qty.mul(new Decimal2(sumUnitaryFunding).sub(lastSumUnitaryFunding))).toNumber();
237
+ const qty = new Decimal(positionQty);
238
+ return qty.mul(markPrice).sub(costPosition).sub(qty.mul(new Decimal(sumUnitaryFunding).sub(lastSumUnitaryFunding))).toNumber();
239
239
  }
240
240
  function totalUnsettlementPnL(positions) {
241
241
  if (!Array.isArray(positions) || positions.length === 0) {
@@ -261,56 +261,127 @@ function MMR(inputs) {
261
261
  } = inputs;
262
262
  return Math.max(
263
263
  baseMMR,
264
- new Decimal2(baseMMR).div(baseIMR).mul(IMRFactor).mul(Math.pow(Math.abs(positionNotional), IMR_factor_power)).toNumber()
264
+ new Decimal(baseMMR).div(baseIMR).mul(IMRFactor).mul(Math.pow(Math.abs(positionNotional), IMR_factor_power)).toNumber()
265
265
  );
266
266
  }
267
267
  function estPnLForTP(inputs) {
268
- return new Decimal2(inputs.positionQty).mul(new Decimal2(inputs.price).sub(inputs.entryPrice)).toNumber();
268
+ return new Decimal(inputs.positionQty).mul(new Decimal(inputs.price).sub(inputs.entryPrice)).toNumber();
269
269
  }
270
270
  function estPriceForTP(inputs) {
271
- return new Decimal2(inputs.pnl).div(inputs.positionQty).add(inputs.entryPrice).toNumber();
271
+ return new Decimal(inputs.pnl).div(inputs.positionQty).add(inputs.entryPrice).toNumber();
272
272
  }
273
273
  function estOffsetForTP(inputs) {
274
- return new Decimal2(inputs.price).div(inputs.entryPrice).toNumber();
274
+ return new Decimal(inputs.price).div(inputs.entryPrice).toNumber();
275
275
  }
276
276
  function estPriceFromOffsetForTP(inputs) {
277
- return new Decimal2(inputs.offset).add(inputs.entryPrice).toNumber();
277
+ return new Decimal(inputs.offset).add(inputs.entryPrice).toNumber();
278
278
  }
279
279
  function estPnLForSL(inputs) {
280
280
  return 0;
281
281
  }
282
282
  function maxPositionNotional(inputs) {
283
283
  const { leverage, IMRFactor } = inputs;
284
- return new Decimal2(1).div(new Decimal2(leverage).mul(IMRFactor)).pow(1 / 0.8).toNumber();
284
+ return new Decimal(1).div(new Decimal(leverage).mul(IMRFactor)).pow(1 / 0.8).toNumber();
285
285
  }
286
286
  function maxPositionLeverage(inputs) {
287
287
  const { IMRFactor, notional: notional2 } = inputs;
288
- return new Decimal2(1).div(new Decimal2(IMRFactor).mul(new Decimal2(notional2).pow(0.8))).toNumber();
288
+ return new Decimal(1).div(new Decimal(IMRFactor).mul(new Decimal(notional2).pow(0.8))).toNumber();
289
+ }
290
+ function liquidationPriceIsolated(inputs) {
291
+ const {
292
+ isolatedPositionMargin,
293
+ costPosition,
294
+ positionQty,
295
+ sumUnitaryFunding,
296
+ lastSumUnitaryFunding,
297
+ baseMMR,
298
+ baseIMR,
299
+ IMRFactor,
300
+ referencePrice,
301
+ orderSide,
302
+ orderQty = 0,
303
+ leverage
304
+ } = inputs;
305
+ const refPrice = referencePrice != null ? referencePrice : 0;
306
+ if (refPrice <= 0 && orderQty !== 0) {
307
+ return null;
308
+ }
309
+ const orderSideMultiplier = orderSide === "BUY" ? 1 : orderSide === "SELL" ? -1 : 0;
310
+ const newPositionQty = positionQty + orderSideMultiplier * orderQty;
311
+ if (newPositionQty === 0) {
312
+ return null;
313
+ }
314
+ let newIsolatedPositionMargin;
315
+ let newCostPosition;
316
+ if (orderQty === 0) {
317
+ newIsolatedPositionMargin = new Decimal(isolatedPositionMargin);
318
+ newCostPosition = new Decimal(costPosition);
319
+ } else if (positionQty === 0 || orderSideMultiplier > 0 && positionQty > 0 || orderSideMultiplier < 0 && positionQty < 0) {
320
+ newIsolatedPositionMargin = new Decimal(isolatedPositionMargin).add(
321
+ new Decimal(orderQty).mul(refPrice).div(leverage)
322
+ );
323
+ newCostPosition = new Decimal(costPosition).add(
324
+ new Decimal(orderSideMultiplier).mul(orderQty).mul(refPrice)
325
+ );
326
+ } else {
327
+ const signPositionQty = positionQty > 0 ? 1 : -1;
328
+ const signNewPositionQty = newPositionQty > 0 ? 1 : -1;
329
+ if (signNewPositionQty === signPositionQty) {
330
+ newIsolatedPositionMargin = new Decimal(isolatedPositionMargin).mul(newPositionQty).div(positionQty);
331
+ newCostPosition = new Decimal(costPosition).add(
332
+ new Decimal(orderSideMultiplier).mul(orderQty).mul(refPrice)
333
+ );
334
+ } else {
335
+ newIsolatedPositionMargin = new Decimal(Math.abs(newPositionQty)).mul(refPrice).div(leverage);
336
+ newCostPosition = new Decimal(newPositionQty).mul(refPrice);
337
+ }
338
+ }
339
+ const fundingAdjustment = new Decimal(newPositionQty).mul(
340
+ new Decimal(sumUnitaryFunding).sub(lastSumUnitaryFunding)
341
+ );
342
+ const newPositionNotional = new Decimal(Math.abs(newPositionQty)).mul(
343
+ refPrice
344
+ );
345
+ const dynamicMMR = new Decimal(baseMMR).div(baseIMR).mul(IMRFactor).mul(newPositionNotional.toPower(IMRFactorPower)).toNumber();
346
+ const newMMR = Math.max(baseMMR, dynamicMMR);
347
+ const denominator = new Decimal(Math.abs(newPositionQty)).mul(newMMR).sub(newPositionQty);
348
+ if (denominator.isZero()) {
349
+ return null;
350
+ }
351
+ const numerator = newIsolatedPositionMargin.sub(newCostPosition).sub(fundingAdjustment);
352
+ const liquidationPrice = numerator.div(denominator).toNumber();
353
+ if (liquidationPrice <= 0) {
354
+ return null;
355
+ }
356
+ return liquidationPrice;
289
357
  }
290
358
 
291
- // src/account.ts
359
+ // src/account/index.ts
292
360
  var account_exports = {};
293
361
  __export(account_exports, {
294
362
  IMR: () => IMR,
295
363
  LTV: () => LTV,
296
364
  MMR: () => MMR2,
297
365
  availableBalance: () => availableBalance,
366
+ availableBalanceForIsolatedMargin: () => availableBalanceForIsolatedMargin,
298
367
  buyOrdersFilter_by_symbol: () => buyOrdersFilter_by_symbol,
299
368
  calcMinimumReceived: () => calcMinimumReceived,
300
369
  collateralContribution: () => collateralContribution,
301
370
  collateralRatio: () => collateralRatio,
302
371
  currentLeverage: () => currentLeverage,
303
- extractSymbols: () => extractSymbols,
372
+ extractSymbols: () => extractSymbols2,
304
373
  freeCollateral: () => freeCollateral,
374
+ freeCollateralUSDCOnly: () => freeCollateralUSDCOnly,
305
375
  getPositonsAndOrdersNotionalBySymbol: () => getPositonsAndOrdersNotionalBySymbol,
306
376
  getQtyFromOrdersBySide: () => getQtyFromOrdersBySide,
307
377
  getQtyFromPositions: () => getQtyFromPositions,
308
378
  groupOrdersBySymbol: () => groupOrdersBySymbol,
309
- initialMarginWithOrder: () => initialMarginWithOrder,
310
- maxLeverage: () => maxLeverage,
379
+ maxAdd: () => maxAdd,
311
380
  maxQty: () => maxQty,
312
381
  maxQtyByLong: () => maxQtyByLong,
313
382
  maxQtyByShort: () => maxQtyByShort,
383
+ maxQtyForIsolatedMargin: () => maxQtyForIsolatedMargin,
384
+ maxReduce: () => maxReduce,
314
385
  maxWithdrawalOtherCollateral: () => maxWithdrawalOtherCollateral,
315
386
  maxWithdrawalUSDC: () => maxWithdrawalUSDC,
316
387
  otherIMs: () => otherIMs,
@@ -318,42 +389,61 @@ __export(account_exports, {
318
389
  positionQtyWithOrders_by_symbol: () => positionQtyWithOrders_by_symbol,
319
390
  sellOrdersFilter_by_symbol: () => sellOrdersFilter_by_symbol,
320
391
  totalCollateral: () => totalCollateral,
321
- totalInitialMarginWithOrders: () => totalInitialMarginWithOrders,
322
392
  totalInitialMarginWithQty: () => totalInitialMarginWithQty,
323
393
  totalMarginRatio: () => totalMarginRatio,
324
394
  totalUnrealizedROI: () => totalUnrealizedROI,
325
395
  totalValue: () => totalValue
326
396
  });
327
- import { OrderSide } from "@orderly.network/types";
328
- import { Decimal as Decimal3, zero as zero2 } from "@orderly.network/utils";
329
397
  function totalValue(inputs) {
330
- const { totalUnsettlementPnL: totalUnsettlementPnL2, USDCHolding, nonUSDCHolding } = inputs;
398
+ const {
399
+ totalUnsettlementPnL: totalUnsettlementPnL2,
400
+ USDCHolding,
401
+ nonUSDCHolding,
402
+ totalIsolatedPositionMargin = 0
403
+ } = inputs;
331
404
  const nonUSDCHoldingValue = nonUSDCHolding.reduce((acc, cur) => {
332
- return new Decimal3(cur.holding).mul(cur.indexPrice).add(acc);
333
- }, zero2);
334
- return nonUSDCHoldingValue.add(USDCHolding).add(totalUnsettlementPnL2);
405
+ return new Decimal(cur.holding).mul(cur.indexPrice).add(acc);
406
+ }, zero);
407
+ return nonUSDCHoldingValue.add(USDCHolding).add(totalIsolatedPositionMargin).add(totalUnsettlementPnL2);
335
408
  }
336
409
  function freeCollateral(inputs) {
337
410
  const value = inputs.totalCollateral.sub(inputs.totalInitialMarginWithOrders);
338
- return value.isNegative() ? zero2 : value;
411
+ return value.isNegative() ? zero : value;
412
+ }
413
+ function freeCollateralUSDCOnly(inputs) {
414
+ const { freeCollateral: freeCollateral2, nonUSDCHolding } = inputs;
415
+ const nonUSDCHoldingValue = nonUSDCHolding.reduce((acc, cur) => {
416
+ const finalHolding = Math.min(cur.holding, cur.collateralCap);
417
+ const value2 = new Decimal(finalHolding).mul(cur.collateralRatio).mul(cur.indexPrice);
418
+ return acc.add(value2);
419
+ }, zero);
420
+ const value = freeCollateral2.sub(nonUSDCHoldingValue);
421
+ return value.isNegative() ? zero : value;
339
422
  }
340
423
  function totalCollateral(inputs) {
341
- const { USDCHolding, nonUSDCHolding, unsettlementPnL: unsettlementPnL2 } = inputs;
424
+ const {
425
+ USDCHolding,
426
+ nonUSDCHolding,
427
+ unsettlementPnL: unsettlementPnL2,
428
+ usdcBalancePendingShortQty = 0,
429
+ usdcBalanceIsolatedOrderFrozen = 0,
430
+ totalCrossUnsettledPnL
431
+ } = inputs;
432
+ const usdcPart = new Decimal(USDCHolding).add(usdcBalancePendingShortQty).sub(Math.abs(usdcBalanceIsolatedOrderFrozen));
342
433
  const nonUSDCHoldingValue = nonUSDCHolding.reduce((acc, cur) => {
343
434
  const finalHolding = Math.min(cur.holding, cur.collateralCap);
344
- const value = new Decimal3(finalHolding).mul(cur.collateralRatio).mul(cur.indexPrice);
435
+ const value = new Decimal(finalHolding).mul(cur.collateralRatio).mul(cur.indexPrice);
345
436
  return acc.add(value);
346
- }, zero2);
347
- return new Decimal3(USDCHolding).add(nonUSDCHoldingValue).add(unsettlementPnL2);
348
- }
349
- function initialMarginWithOrder() {
437
+ }, zero);
438
+ const pnl = totalCrossUnsettledPnL !== void 0 ? totalCrossUnsettledPnL : unsettlementPnL2;
439
+ return usdcPart.add(nonUSDCHoldingValue).add(pnl);
350
440
  }
351
441
  function positionNotionalWithOrder_by_symbol(inputs) {
352
- return new Decimal3(inputs.markPrice).mul(inputs.positionQtyWithOrders);
442
+ return new Decimal(inputs.markPrice).mul(inputs.positionQtyWithOrders);
353
443
  }
354
444
  function positionQtyWithOrders_by_symbol(inputs) {
355
445
  const { positionQty, buyOrdersQty, sellOrdersQty } = inputs;
356
- const positionQtyDecimal = new Decimal3(positionQty);
446
+ const positionQtyDecimal = new Decimal(positionQty);
357
447
  const qty = Math.max(
358
448
  positionQtyDecimal.add(buyOrdersQty).abs().toNumber(),
359
449
  positionQtyDecimal.sub(sellOrdersQty).abs().toNumber()
@@ -362,7 +452,7 @@ function positionQtyWithOrders_by_symbol(inputs) {
362
452
  }
363
453
  function IMR(inputs) {
364
454
  const {
365
- maxLeverage: maxLeverage2,
455
+ maxLeverage,
366
456
  baseIMR,
367
457
  IMR_Factor,
368
458
  positionNotional,
@@ -370,10 +460,10 @@ function IMR(inputs) {
370
460
  IMR_factor_power = IMRFactorPower
371
461
  } = inputs;
372
462
  return Math.max(
373
- 1 / maxLeverage2,
463
+ 1 / maxLeverage,
374
464
  baseIMR,
375
- new Decimal3(IMR_Factor).mul(
376
- new Decimal3(positionNotional).add(orderNotional).abs().toPower(IMR_factor_power)
465
+ new Decimal(IMR_Factor).mul(
466
+ new Decimal(positionNotional).add(orderNotional).abs().toPower(IMR_factor_power)
377
467
  ).toNumber()
378
468
  );
379
469
  }
@@ -405,85 +495,117 @@ function getPositonsAndOrdersNotionalBySymbol(inputs) {
405
495
  const positionQty = getQtyFromPositions(positions, symbol);
406
496
  const buyOrdersQty = getQtyFromOrdersBySide(orders, symbol, OrderSide.BUY);
407
497
  const sellOrdersQty = getQtyFromOrdersBySide(orders, symbol, OrderSide.SELL);
408
- const markPriceDecimal = new Decimal3(markPrice);
409
- return markPriceDecimal.mul(positionQty).add(markPriceDecimal.mul(new Decimal3(buyOrdersQty).add(sellOrdersQty))).abs().toNumber();
498
+ const markPriceDecimal = new Decimal(markPrice);
499
+ return markPriceDecimal.mul(positionQty).add(markPriceDecimal.mul(new Decimal(buyOrdersQty).add(sellOrdersQty))).abs().toNumber();
410
500
  }
411
- function totalInitialMarginWithOrders(inputs) {
501
+ function calculateSymbolInitialMargin(params) {
502
+ const {
503
+ symbol,
504
+ positionQty,
505
+ buyOrdersQty,
506
+ sellOrdersQty,
507
+ markPrice,
508
+ IMR_Factors,
509
+ symbolInfo,
510
+ symbolMaxLeverage
511
+ } = params;
512
+ const positionQtyWithOrders = positionQtyWithOrders_by_symbol({
513
+ positionQty,
514
+ buyOrdersQty,
515
+ sellOrdersQty
516
+ });
517
+ const positionNotionalWithOrders = positionNotionalWithOrder_by_symbol({
518
+ markPrice,
519
+ positionQtyWithOrders
520
+ });
521
+ const markPriceDecimal = new Decimal(markPrice);
522
+ const imr = IMR2({
523
+ positionNotional: markPriceDecimal.mul(positionQty).toNumber(),
524
+ ordersNotional: markPriceDecimal.mul(new Decimal(buyOrdersQty).sub(sellOrdersQty)).toNumber(),
525
+ maxLeverage: symbolMaxLeverage,
526
+ IMR_Factor: IMR_Factors[symbol],
527
+ baseIMR: symbolInfo[symbol]("base_imr", 0)
528
+ });
529
+ return positionNotionalWithOrders.mul(imr).toNumber();
530
+ }
531
+ function IMR2(inputs) {
532
+ const {
533
+ maxLeverage,
534
+ baseIMR,
535
+ IMR_Factor,
536
+ positionNotional,
537
+ ordersNotional: orderNotional,
538
+ IMR_factor_power = IMRFactorPower
539
+ } = inputs;
540
+ const imr = IMR_Factor === 0 ? 0 : new Decimal(IMR_Factor).mul(
541
+ new Decimal(positionNotional).add(orderNotional).abs().toPower(IMR_factor_power)
542
+ ).toNumber();
543
+ return Math.max(1 / maxLeverage, baseIMR, imr);
544
+ }
545
+ function totalInitialMarginWithQty(inputs) {
412
546
  const {
413
547
  positions,
414
548
  orders,
415
549
  markPrices,
416
550
  IMR_Factors,
417
- maxLeverage: maxLeverage2,
418
- symbolInfo
551
+ symbolInfo,
552
+ maxLeverageBySymbol
419
553
  } = inputs;
420
- const symbols = extractSymbols(positions, orders);
421
- const total_initial_margin_with_orders = symbols.reduce((acc, cur) => {
422
- const symbol = cur;
423
- const positionQty = getQtyFromPositions(positions, symbol);
424
- const buyOrdersQty = getQtyFromOrdersBySide(orders, symbol, OrderSide.BUY);
554
+ const crossPositions = positions.filter(
555
+ (p) => p.margin_mode !== MarginMode.ISOLATED
556
+ );
557
+ const crossOrders = orders.filter(
558
+ (o) => o.margin_mode !== MarginMode.ISOLATED
559
+ );
560
+ const crossLeverageBySymbol = crossPositions.reduce(
561
+ (acc, position) => {
562
+ if (!acc[position.symbol] && position.leverage) {
563
+ acc[position.symbol] = position.leverage;
564
+ }
565
+ return acc;
566
+ },
567
+ {}
568
+ );
569
+ const symbols = extractSymbols(crossPositions, crossOrders);
570
+ return symbols.map((symbol) => {
571
+ var _a, _b;
572
+ const positionQty = getQtyFromPositions(crossPositions, symbol);
573
+ const markPrice = markPrices[symbol] || 0;
574
+ const buyOrdersQty = getQtyFromOrdersBySide(
575
+ crossOrders,
576
+ symbol,
577
+ OrderSide.BUY
578
+ );
425
579
  const sellOrdersQty = getQtyFromOrdersBySide(
426
- orders,
580
+ crossOrders,
427
581
  symbol,
428
582
  OrderSide.SELL
429
583
  );
430
- const markPrice = markPrices[symbol] || 0;
431
- const positionQtyWithOrders = positionQtyWithOrders_by_symbol({
584
+ const symbolMaxLeverage = (_b = (_a = crossLeverageBySymbol[symbol]) != null ? _a : maxLeverageBySymbol == null ? void 0 : maxLeverageBySymbol[symbol]) != null ? _b : 1;
585
+ return calculateSymbolInitialMargin({
586
+ symbol,
432
587
  positionQty,
433
588
  buyOrdersQty,
434
- sellOrdersQty
435
- });
436
- const position_notional_with_orders = positionNotionalWithOrder_by_symbol({
589
+ sellOrdersQty,
437
590
  markPrice,
438
- positionQtyWithOrders
591
+ IMR_Factors,
592
+ symbolInfo,
593
+ symbolMaxLeverage
439
594
  });
440
- const markPriceDecimal = new Decimal3(markPrice);
441
- const imr = IMR({
442
- positionNotional: markPriceDecimal.mul(positionQty).toNumber(),
443
- ordersNotional: markPriceDecimal.mul(new Decimal3(buyOrdersQty).add(sellOrdersQty)).toNumber(),
444
- maxLeverage: maxLeverage2,
445
- IMR_Factor: IMR_Factors[symbol],
446
- baseIMR: symbolInfo[symbol]("base_imr", 0)
447
- });
448
- return position_notional_with_orders.mul(imr).add(acc).toNumber();
449
- }, 0);
450
- return total_initial_margin_with_orders;
595
+ }).reduce((acc, margin) => acc.add(margin), zero).toNumber();
451
596
  }
452
- function totalInitialMarginWithQty(inputs) {
453
- const { positions, markPrices, IMR_Factors, symbolInfo } = inputs;
454
- const symbols = positions.map((item) => item.symbol);
455
- const total_initial_margin_with_orders = symbols.reduce((acc, cur) => {
456
- var _a;
457
- const symbol = cur;
458
- const position = positions.find((item) => item.symbol === symbol);
459
- const positionQty = (position == null ? void 0 : position.position_qty) || 0;
460
- const buyOrdersQty = (position == null ? void 0 : position.pending_long_qty) || 0;
461
- const sellOrdersQty = (position == null ? void 0 : position.pending_short_qty) || 0;
462
- const markPrice = markPrices[symbol] || 0;
463
- const positionQtyWithOrders = positionQtyWithOrders_by_symbol({
464
- positionQty,
465
- buyOrdersQty,
466
- sellOrdersQty
467
- });
468
- const position_notional_with_orders = positionNotionalWithOrder_by_symbol({
469
- markPrice,
470
- positionQtyWithOrders
471
- });
472
- const markPriceDecimal = new Decimal3(markPrice);
473
- const imr = IMR({
474
- positionNotional: markPriceDecimal.mul(positionQty).toNumber(),
475
- ordersNotional: markPriceDecimal.mul(new Decimal3(buyOrdersQty).add(sellOrdersQty)).toNumber(),
476
- maxLeverage: maxLeverage({
477
- symbolLeverage: (_a = position == null ? void 0 : position.leverage) != null ? _a : inputs.maxLeverage,
478
- accountLeverage: inputs.maxLeverage
479
- }),
480
- IMR_Factor: IMR_Factors[symbol],
481
- baseIMR: symbolInfo[symbol]("base_imr", 0)
482
- });
483
- return position_notional_with_orders.mul(imr).add(acc).toNumber();
484
- }, 0);
485
- return total_initial_margin_with_orders;
597
+ function extractSymbols(positions, orders) {
598
+ const symbols = /* @__PURE__ */ new Set();
599
+ positions.forEach((item) => {
600
+ symbols.add(item.symbol);
601
+ });
602
+ orders.forEach((item) => {
603
+ symbols.add(item.symbol);
604
+ });
605
+ return Array.from(symbols);
486
606
  }
607
+
608
+ // src/account/groupOrders.ts
487
609
  function groupOrdersBySymbol(orders) {
488
610
  const symbols = {};
489
611
  orders.forEach((item) => {
@@ -494,7 +616,7 @@ function groupOrdersBySymbol(orders) {
494
616
  });
495
617
  return symbols;
496
618
  }
497
- function extractSymbols(positions, orders) {
619
+ function extractSymbols2(positions, orders) {
498
620
  const symbols = /* @__PURE__ */ new Set();
499
621
  positions.forEach((item) => {
500
622
  symbols.add(item.symbol);
@@ -504,6 +626,23 @@ function extractSymbols(positions, orders) {
504
626
  });
505
627
  return Array.from(symbols);
506
628
  }
629
+ function IMR3(inputs) {
630
+ const {
631
+ maxLeverage,
632
+ baseIMR,
633
+ IMR_Factor,
634
+ positionNotional,
635
+ ordersNotional: orderNotional,
636
+ IMR_factor_power = 4 / 5
637
+ } = inputs;
638
+ return Math.max(
639
+ 1 / maxLeverage,
640
+ baseIMR,
641
+ new Decimal(IMR_Factor).mul(
642
+ new Decimal(positionNotional).add(orderNotional).abs().toPower(IMR_factor_power)
643
+ ).toNumber()
644
+ );
645
+ }
507
646
  function otherIMs(inputs) {
508
647
  const {
509
648
  // orders,
@@ -519,23 +658,21 @@ function otherIMs(inputs) {
519
658
  console.warn("markPrices[%s] is undefined", symbol);
520
659
  return acc;
521
660
  }
522
- const markPriceDecimal = new Decimal3(markPrices[symbol] || 0);
661
+ const markPriceDecimal = new Decimal(markPrices[symbol] || 0);
523
662
  const position = positions.find((item) => item.symbol === symbol);
524
663
  const positionQty = getQtyFromPositions(positions, symbol);
525
664
  const positionNotional = markPriceDecimal.mul(positionQty).toNumber();
526
665
  const buyOrdersQty = position.pending_long_qty;
527
666
  const sellOrdersQty = position.pending_short_qty;
528
- const ordersNotional = markPriceDecimal.mul(new Decimal3(buyOrdersQty).add(sellOrdersQty)).toNumber();
667
+ const ordersNotional = markPriceDecimal.mul(new Decimal(buyOrdersQty).add(sellOrdersQty)).toNumber();
529
668
  const IMR_Factor = IMR_Factors[symbol];
530
669
  if (typeof IMR_Factor === "undefined") {
531
670
  console.warn("IMR_Factor is not found:", symbol);
532
671
  return acc;
533
672
  }
534
- const imr = IMR({
535
- maxLeverage: maxLeverage({
536
- symbolLeverage: position.leverage,
537
- accountLeverage: inputs.maxLeverage
538
- }),
673
+ const imr = IMR3({
674
+ // Use symbol + mode leverage from position directly.
675
+ maxLeverage: (position == null ? void 0 : position.leverage) || 1,
539
676
  IMR_Factor,
540
677
  baseIMR: symbolInfo[symbol]("base_imr", 0),
541
678
  positionNotional,
@@ -551,7 +688,7 @@ function otherIMs(inputs) {
551
688
  positionQtyWithOrders
552
689
  });
553
690
  return acc.add(positionNotionalWithOrders.mul(imr));
554
- }, zero2).toNumber();
691
+ }, zero).toNumber();
555
692
  }
556
693
  function maxQty(side, inputs, options) {
557
694
  if (side === OrderSide.BUY) {
@@ -565,7 +702,7 @@ function maxQtyByLong(inputs, options) {
565
702
  baseMaxQty,
566
703
  totalCollateral: totalCollateral2,
567
704
  otherIMs: otherIMs2,
568
- maxLeverage: maxLeverage2,
705
+ maxLeverage,
569
706
  baseIMR,
570
707
  markPrice,
571
708
  IMR_Factor,
@@ -576,10 +713,10 @@ function maxQtyByLong(inputs, options) {
576
713
  if (totalCollateral2 === 0) {
577
714
  return 0;
578
715
  }
579
- const totalCollateralDecimal = new Decimal3(totalCollateral2);
716
+ const totalCollateralDecimal = new Decimal(totalCollateral2);
580
717
  const factor_1 = totalCollateralDecimal.sub(otherIMs2).div(
581
- new Decimal3(takerFeeRate).mul(2).mul(1e-4).add(Math.max(1 / maxLeverage2, baseIMR))
582
- ).div(markPrice).mul(0.995).sub(new Decimal3(positionQty).add(buyOrdersQty)).toNumber();
718
+ new Decimal(takerFeeRate).mul(2).mul(1e-4).add(Math.max(1 / maxLeverage, baseIMR))
719
+ ).div(markPrice).mul(0.995).sub(new Decimal(positionQty).add(buyOrdersQty)).toNumber();
583
720
  if (positionQty === 0 && buyOrdersQty === 0) {
584
721
  return Math.min(baseMaxQty, factor_1);
585
722
  }
@@ -587,10 +724,10 @@ function maxQtyByLong(inputs, options) {
587
724
  return Math.min(baseMaxQty, factor_1);
588
725
  }
589
726
  const factor_2 = totalCollateralDecimal.sub(otherIMs2).div(IMR_Factor).toPower(1 / 1.8).div(markPrice).sub(
590
- new Decimal3(positionQty).add(buyOrdersQty)
727
+ new Decimal(positionQty).add(buyOrdersQty)
591
728
  // .abs()
592
729
  // .div(new Decimal(takerFeeRate).mul(2).mul(0.0001).add(1))
593
- ).div(new Decimal3(takerFeeRate).mul(2).mul(1e-4).add(1)).mul(0.995).toNumber();
730
+ ).div(new Decimal(takerFeeRate).mul(2).mul(1e-4).add(1)).mul(0.995).toNumber();
594
731
  return Math.min(baseMaxQty, factor_1, factor_2);
595
732
  } catch (error) {
596
733
  return 0;
@@ -602,7 +739,7 @@ function maxQtyByShort(inputs, options) {
602
739
  baseMaxQty,
603
740
  totalCollateral: totalCollateral2,
604
741
  otherIMs: otherIMs2,
605
- maxLeverage: maxLeverage2,
742
+ maxLeverage,
606
743
  baseIMR,
607
744
  markPrice,
608
745
  IMR_Factor,
@@ -611,9 +748,9 @@ function maxQtyByShort(inputs, options) {
611
748
  sellOrdersQty,
612
749
  takerFeeRate
613
750
  } = inputs;
614
- const totalCollateralDecimal = new Decimal3(totalCollateral2);
751
+ const totalCollateralDecimal = new Decimal(totalCollateral2);
615
752
  const factor_1 = totalCollateralDecimal.sub(otherIMs2).div(
616
- new Decimal3(takerFeeRate).mul(2).mul(1e-4).add(Math.max(1 / maxLeverage2, baseIMR))
753
+ new Decimal(takerFeeRate).mul(2).mul(1e-4).add(Math.max(1 / maxLeverage, baseIMR))
617
754
  ).div(markPrice).mul(0.995).add(positionQty).sub(Math.abs(sellOrdersQty)).toNumber();
618
755
  if (positionQty === 0 && sellOrdersQty === 0) {
619
756
  return Math.min(baseMaxQty, factor_1);
@@ -621,31 +758,147 @@ function maxQtyByShort(inputs, options) {
621
758
  if (IMR_Factor === 0) {
622
759
  return Math.min(baseMaxQty, factor_1);
623
760
  }
624
- const factor_2 = totalCollateralDecimal.sub(otherIMs2).div(IMR_Factor).toPower(1 / 1.8).div(markPrice).add(positionQty).sub(sellOrdersQty).div(new Decimal3(takerFeeRate).mul(2).mul(1e-4).add(1)).mul(0.995).toNumber();
761
+ const factor_2 = totalCollateralDecimal.sub(otherIMs2).div(IMR_Factor).toPower(1 / 1.8).div(markPrice).add(positionQty).sub(sellOrdersQty).div(new Decimal(takerFeeRate).mul(2).mul(1e-4).add(1)).mul(0.995).toNumber();
625
762
  return Math.min(baseMaxQty, factor_1, factor_2);
626
763
  } catch (error) {
627
764
  return 0;
628
765
  }
629
766
  }
767
+ function maxQtyForIsolatedMargin(inputs) {
768
+ const {
769
+ orderSide,
770
+ currentOrderReferencePrice,
771
+ availableBalance: availableBalance2,
772
+ leverage,
773
+ IMR_Factor,
774
+ markPrice,
775
+ positionQty,
776
+ pendingLongOrders,
777
+ pendingSellOrders,
778
+ symbolMaxNotional,
779
+ epsilon = 1
780
+ } = inputs;
781
+ const maxNotional = Math.min(
782
+ new Decimal(1).div(new Decimal(leverage).mul(IMR_Factor)).pow(5 / 4).toNumber(),
783
+ symbolMaxNotional
784
+ );
785
+ if (orderSide === OrderSide.BUY) {
786
+ if (positionQty >= 0) {
787
+ const pendingLongNotional = pendingLongOrders.reduce(
788
+ (acc, order) => acc + new Decimal(order.referencePrice).mul(order.quantity).toNumber(),
789
+ 0
790
+ );
791
+ const maxQtyByBalance = new Decimal(availableBalance2).div(currentOrderReferencePrice).mul(leverage).toNumber();
792
+ const maxQtyByNotional = new Decimal(maxNotional).sub(new Decimal(markPrice).mul(positionQty)).sub(pendingLongNotional).div(currentOrderReferencePrice).toNumber();
793
+ return Math.max(0, Math.min(maxQtyByBalance, maxQtyByNotional));
794
+ } else {
795
+ return maxQtyIsolatedBinarySearch(
796
+ {
797
+ currentOrderReferencePrice,
798
+ availableBalance: availableBalance2,
799
+ leverage,
800
+ baseIMR: inputs.baseIMR,
801
+ IMR_Factor,
802
+ positionQty,
803
+ pendingLongOrders,
804
+ pendingSellOrders,
805
+ isoOrderFrozenLong: inputs.isoOrderFrozenLong,
806
+ isoOrderFrozenShort: inputs.isoOrderFrozenShort
807
+ },
808
+ maxNotional,
809
+ epsilon,
810
+ OrderSide.BUY
811
+ );
812
+ }
813
+ } else {
814
+ if (positionQty <= 0) {
815
+ const pendingSellNotional = pendingSellOrders.reduce(
816
+ (acc, order) => acc + new Decimal(order.referencePrice).mul(order.quantity).toNumber(),
817
+ 0
818
+ );
819
+ const maxQtyByBalance = new Decimal(availableBalance2).div(currentOrderReferencePrice).mul(leverage).toNumber();
820
+ const maxQtyByNotional = new Decimal(maxNotional).sub(new Decimal(markPrice).mul(Math.abs(positionQty))).sub(pendingSellNotional).div(currentOrderReferencePrice).toNumber();
821
+ return Math.max(0, Math.min(maxQtyByBalance, maxQtyByNotional));
822
+ } else {
823
+ return maxQtyIsolatedBinarySearch(
824
+ {
825
+ currentOrderReferencePrice,
826
+ availableBalance: availableBalance2,
827
+ leverage,
828
+ baseIMR: inputs.baseIMR,
829
+ IMR_Factor,
830
+ positionQty,
831
+ pendingLongOrders,
832
+ pendingSellOrders,
833
+ isoOrderFrozenLong: inputs.isoOrderFrozenLong,
834
+ isoOrderFrozenShort: inputs.isoOrderFrozenShort
835
+ },
836
+ maxNotional,
837
+ epsilon,
838
+ OrderSide.SELL
839
+ );
840
+ }
841
+ }
842
+ }
843
+ function maxQtyIsolatedBinarySearch(inputs, maxNotional, epsilon, orderSide) {
844
+ const {
845
+ currentOrderReferencePrice,
846
+ availableBalance: availableBalance2,
847
+ leverage,
848
+ positionQty,
849
+ pendingLongOrders,
850
+ pendingSellOrders,
851
+ isoOrderFrozenLong,
852
+ isoOrderFrozenShort
853
+ } = inputs;
854
+ inputs.baseIMR;
855
+ inputs.IMR_Factor;
856
+ const pendingOrdersQty = orderSide === OrderSide.BUY ? pendingLongOrders.reduce((acc, order) => acc + order.quantity, 0) : pendingSellOrders.reduce((acc, order) => acc + order.quantity, 0);
857
+ let left = Math.max(0, Math.max(0, Math.abs(positionQty)) - pendingOrdersQty);
858
+ let right = new Decimal(maxNotional).div(currentOrderReferencePrice).add(Math.abs(positionQty)).toNumber();
859
+ for (let i = 0; i < 30; i++) {
860
+ const mid = (left + right) / 2;
861
+ const orderNotional = new Decimal(mid).mul(currentOrderReferencePrice);
862
+ const orderMargin = orderNotional.div(leverage);
863
+ const totalFrozenMargin = orderSide === OrderSide.BUY ? isoOrderFrozenLong + orderMargin.toNumber() : isoOrderFrozenShort + orderMargin.toNumber();
864
+ const newPositionQty = orderSide === OrderSide.BUY ? positionQty + mid : positionQty - mid;
865
+ const openNotional = new Decimal(Math.abs(newPositionQty)).mul(
866
+ currentOrderReferencePrice
867
+ );
868
+ const frozenOk = totalFrozenMargin <= availableBalance2;
869
+ const notionalOk = openNotional.lte(maxNotional);
870
+ if (frozenOk && notionalOk) {
871
+ left = mid;
872
+ if (new Decimal(availableBalance2).sub(totalFrozenMargin).lte(epsilon)) {
873
+ break;
874
+ }
875
+ } else {
876
+ right = mid;
877
+ }
878
+ }
879
+ return Math.max(0, left);
880
+ }
630
881
  function totalMarginRatio(inputs, dp) {
631
882
  const { totalCollateral: totalCollateral2, markPrices, positions } = inputs;
632
883
  if (totalCollateral2 === 0) {
633
884
  return 0;
634
885
  }
635
- const totalCollateralDecimal = new Decimal3(totalCollateral2);
886
+ const totalCollateralDecimal = new Decimal(totalCollateral2);
636
887
  const totalPositionNotional = positions.reduce((acc, cur) => {
637
888
  const markPrice = markPrices[cur.symbol] || 0;
638
- return acc.add(new Decimal3(cur.position_qty).mul(markPrice).abs());
639
- }, zero2);
640
- if (totalPositionNotional.eq(zero2)) {
889
+ return acc.add(new Decimal(cur.position_qty).mul(markPrice).abs());
890
+ }, zero);
891
+ if (totalPositionNotional.eq(zero)) {
641
892
  return 0;
642
893
  }
643
894
  return totalCollateralDecimal.div(totalPositionNotional).toNumber();
644
895
  }
645
896
  function totalUnrealizedROI(inputs) {
646
897
  const { totalUnrealizedPnL: totalUnrealizedPnL2, totalValue: totalValue2 } = inputs;
647
- return new Decimal3(totalUnrealizedPnL2).div(totalValue2 - totalUnrealizedPnL2).toNumber();
898
+ return new Decimal(totalUnrealizedPnL2).div(totalValue2 - totalUnrealizedPnL2).toNumber();
648
899
  }
900
+
901
+ // src/account/leverage.ts
649
902
  function currentLeverage(totalMarginRatio2) {
650
903
  if (totalMarginRatio2 === 0) {
651
904
  return 0;
@@ -654,7 +907,16 @@ function currentLeverage(totalMarginRatio2) {
654
907
  }
655
908
  function availableBalance(inputs) {
656
909
  const { USDCHolding, unsettlementPnL: unsettlementPnL2 } = inputs;
657
- return new Decimal3(USDCHolding).add(unsettlementPnL2).toNumber();
910
+ return new Decimal(USDCHolding).add(unsettlementPnL2).toNumber();
911
+ }
912
+ function availableBalanceForIsolatedMargin(inputs) {
913
+ return Math.max(
914
+ 0,
915
+ Math.min(
916
+ inputs.USDCHolding,
917
+ new Decimal(inputs.freeCollateral).sub(Math.max(inputs.totalCrossUnsettledPnL, 0)).toNumber()
918
+ )
919
+ );
658
920
  }
659
921
  function MMR2(inputs) {
660
922
  if (inputs.positionsNotional === 0) {
@@ -663,7 +925,7 @@ function MMR2(inputs) {
663
925
  if (inputs.positionsMMR === 0) {
664
926
  return null;
665
927
  }
666
- return new Decimal3(inputs.positionsMMR).div(inputs.positionsNotional).toNumber();
928
+ return new Decimal(inputs.positionsMMR).div(inputs.positionsNotional).toNumber();
667
929
  }
668
930
  var collateralRatio = (params) => {
669
931
  const {
@@ -674,30 +936,30 @@ var collateralRatio = (params) => {
674
936
  indexPrice
675
937
  } = params;
676
938
  const cap = collateralCap === -1 ? collateralQty : collateralCap;
677
- const K = new Decimal3(1.2);
678
- const DCF = new Decimal3(discountFactor || 0);
679
- const qty = new Decimal3(Math.min(collateralQty, cap));
939
+ const K = new Decimal(1.2);
940
+ const DCF = new Decimal(discountFactor || 0);
941
+ const qty = new Decimal(Math.min(collateralQty, cap));
680
942
  const notionalAbs = qty.mul(indexPrice).abs();
681
943
  const dynamicWeight = DCF.mul(notionalAbs.toPower(IMRFactorPower));
682
- const result = K.div(new Decimal3(1).add(dynamicWeight));
683
- return result.lt(baseWeight) ? result : new Decimal3(baseWeight);
944
+ const result = K.div(new Decimal(1).add(dynamicWeight));
945
+ return result.lt(baseWeight) ? result : new Decimal(baseWeight);
684
946
  };
685
947
  var collateralContribution = (params) => {
686
948
  const { collateralQty, collateralCap, collateralRatio: collateralRatio2, indexPrice } = params;
687
949
  const cap = collateralCap === -1 ? collateralQty : collateralCap;
688
- return new Decimal3(Math.min(collateralQty, cap)).mul(collateralRatio2).mul(indexPrice).toNumber();
950
+ return new Decimal(Math.min(collateralQty, cap)).mul(collateralRatio2).mul(indexPrice).toNumber();
689
951
  };
690
952
  var LTV = (params) => {
691
953
  const { usdcBalance, upnl, assets } = params;
692
- const usdcLoss = new Decimal3(Math.min(usdcBalance, 0)).abs();
693
- const upnlLoss = new Decimal3(Math.min(upnl, 0)).abs();
954
+ const usdcLoss = new Decimal(Math.min(usdcBalance, 0)).abs();
955
+ const upnlLoss = new Decimal(Math.min(upnl, 0)).abs();
694
956
  const numerator = usdcLoss.add(upnlLoss);
695
957
  const collateralSum = assets.reduce((acc, asset) => {
696
958
  return acc.add(
697
- new Decimal3(Math.max(asset.qty, 0)).mul(new Decimal3(asset.indexPrice)).mul(new Decimal3(asset.weight))
959
+ new Decimal(Math.max(asset.qty, 0)).mul(new Decimal(asset.indexPrice)).mul(new Decimal(asset.weight))
698
960
  );
699
- }, zero2);
700
- const denominator = collateralSum.add(new Decimal3(Math.max(upnl, 0)));
961
+ }, zero);
962
+ const denominator = collateralSum.add(new Decimal(Math.max(upnl, 0)));
701
963
  if (numerator.isZero() || denominator.isZero()) {
702
964
  return 0;
703
965
  }
@@ -706,44 +968,60 @@ var LTV = (params) => {
706
968
  var maxWithdrawalUSDC = (inputs) => {
707
969
  const { USDCBalance, freeCollateral: freeCollateral2, upnl } = inputs;
708
970
  const value = Math.min(
709
- new Decimal3(USDCBalance).toNumber(),
710
- new Decimal3(freeCollateral2).sub(Math.max(upnl, 0)).toNumber()
971
+ new Decimal(USDCBalance).toNumber(),
972
+ new Decimal(freeCollateral2).sub(Math.max(upnl, 0)).toNumber()
711
973
  );
712
974
  return Math.max(0, value);
713
975
  };
714
976
  var maxWithdrawalOtherCollateral = (inputs) => {
715
977
  const { USDCBalance, collateralQty, freeCollateral: freeCollateral2, indexPrice, weight } = inputs;
716
- const usdcBalance = new Decimal3(USDCBalance);
717
- const denominator = usdcBalance.isNegative() ? new Decimal3(indexPrice).mul(weight).mul(new Decimal3(1).add(2e-3)) : new Decimal3(indexPrice).mul(weight);
978
+ const usdcBalance = new Decimal(USDCBalance);
979
+ const denominator = usdcBalance.isNegative() ? new Decimal(indexPrice).mul(weight).mul(new Decimal(1).add(2e-3)) : new Decimal(indexPrice).mul(weight);
718
980
  if (denominator.isZero()) {
719
- return zero2;
981
+ return zero;
720
982
  }
721
- const qty = new Decimal3(collateralQty);
722
- const maxQtyByValue = new Decimal3(freeCollateral2).div(denominator);
983
+ const qty = new Decimal(collateralQty);
984
+ const maxQtyByValue = new Decimal(freeCollateral2).div(denominator);
723
985
  return maxQtyByValue.lt(qty) ? maxQtyByValue : qty;
724
986
  };
725
987
  var calcMinimumReceived = (inputs) => {
726
988
  const { amount, slippage } = inputs;
727
- const slippageRatio = new Decimal3(slippage).div(100);
728
- return new Decimal3(amount).mul(new Decimal3(1).minus(slippageRatio)).toNumber();
729
- };
730
- var maxLeverage = (inputs) => {
731
- const { symbolLeverage, accountLeverage } = inputs;
732
- return symbolLeverage != null ? symbolLeverage : 1;
989
+ const slippageRatio = new Decimal(slippage).div(100);
990
+ return new Decimal(amount).mul(new Decimal(1).minus(slippageRatio)).toNumber();
733
991
  };
734
992
 
993
+ // src/account/maxAddReduce.ts
994
+ function maxAdd(inputs) {
995
+ return availableBalanceForIsolatedMargin(inputs);
996
+ }
997
+ function maxReduce(inputs) {
998
+ const {
999
+ isolatedPositionMargin,
1000
+ positionNotional,
1001
+ imr,
1002
+ positionUnsettledPnL
1003
+ } = inputs;
1004
+ const minRequiredMargin = positionNotional * imr;
1005
+ const pnlAdjustment = Math.min(0, positionUnsettledPnL);
1006
+ return Math.max(
1007
+ 0,
1008
+ isolatedPositionMargin - minRequiredMargin + pnlAdjustment
1009
+ );
1010
+ }
1011
+
735
1012
  // src/order.ts
736
1013
  var order_exports = {};
737
1014
  __export(order_exports, {
738
1015
  estLeverage: () => estLeverage,
739
1016
  estLiqPrice: () => estLiqPrice,
1017
+ estLiqPriceIsolated: () => estLiqPriceIsolated,
1018
+ getOrderReferencePrice: () => getOrderReferencePrice,
740
1019
  maxPrice: () => maxPrice,
741
1020
  minPrice: () => minPrice,
742
1021
  orderFee: () => orderFee,
743
1022
  scopePrice: () => scopePrice,
744
1023
  tpslROI: () => tpslROI
745
1024
  });
746
- import { Decimal as Decimal4, getTPSLDirection, zero as zero3 } from "@orderly.network/utils";
747
1025
  function maxPrice(markprice, range) {
748
1026
  return markprice * (1 + range);
749
1027
  }
@@ -757,7 +1035,135 @@ function scopePrice(price, scope, side) {
757
1035
  return price * (1 + scope);
758
1036
  }
759
1037
  function orderFee(inputs) {
760
- return new Decimal4(inputs.qty).mul(inputs.price).mul(inputs.futuresTakeFeeRate).toNumber();
1038
+ return new Decimal(inputs.qty).mul(inputs.price).mul(inputs.futuresTakeFeeRate).toNumber();
1039
+ }
1040
+ function getOrderReferencePrice(order, askPrice, bidPrice) {
1041
+ const getMarketRefPrice = () => {
1042
+ if (order.side === OrderSide.BUY) {
1043
+ return askPrice > 0 ? askPrice : null;
1044
+ }
1045
+ return bidPrice > 0 ? bidPrice : null;
1046
+ };
1047
+ const isValidPrice = (price) => typeof price === "number" && Number.isFinite(price) && price > 0;
1048
+ const { orderType, orderTypeExt, side } = order;
1049
+ const limitPrice = isValidPrice(order.limitPrice) ? order.limitPrice : void 0;
1050
+ const triggerPrice = isValidPrice(order.triggerPrice) ? order.triggerPrice : void 0;
1051
+ if (orderType === OrderType.LIMIT && (orderTypeExt === OrderType.ASK || orderTypeExt === OrderType.BID)) {
1052
+ if (side === OrderSide.BUY) {
1053
+ return orderTypeExt === OrderType.ASK ? isValidPrice(askPrice) ? askPrice : null : isValidPrice(bidPrice) ? bidPrice : null;
1054
+ }
1055
+ return orderTypeExt === OrderType.ASK ? isValidPrice(askPrice) ? askPrice : null : isValidPrice(bidPrice) ? bidPrice : null;
1056
+ }
1057
+ switch (orderType) {
1058
+ case OrderType.LIMIT:
1059
+ case OrderType.IOC:
1060
+ case OrderType.FOK:
1061
+ case OrderType.POST_ONLY: {
1062
+ if (!limitPrice) {
1063
+ return getMarketRefPrice();
1064
+ }
1065
+ if (side === OrderSide.BUY) {
1066
+ return limitPrice;
1067
+ }
1068
+ const effectiveBid = isValidPrice(bidPrice) ? bidPrice : 0;
1069
+ return Math.max(limitPrice, effectiveBid);
1070
+ }
1071
+ case OrderType.MARKET: {
1072
+ return getMarketRefPrice();
1073
+ }
1074
+ case OrderType.STOP_MARKET: {
1075
+ if (triggerPrice) {
1076
+ return triggerPrice;
1077
+ }
1078
+ return getMarketRefPrice();
1079
+ }
1080
+ case OrderType.STOP_LIMIT: {
1081
+ if (limitPrice) {
1082
+ return limitPrice;
1083
+ }
1084
+ return getMarketRefPrice();
1085
+ }
1086
+ case OrderType.TRAILING_STOP: {
1087
+ if (triggerPrice) {
1088
+ return triggerPrice;
1089
+ }
1090
+ return getMarketRefPrice();
1091
+ }
1092
+ default:
1093
+ return null;
1094
+ }
1095
+ }
1096
+ function estLiqPriceIsolated(inputs) {
1097
+ var _a, _b;
1098
+ const {
1099
+ isolatedPositionMargin,
1100
+ costPosition,
1101
+ positionQty,
1102
+ sumUnitaryFunding,
1103
+ lastSumUnitaryFunding,
1104
+ markPrice,
1105
+ baseMMR,
1106
+ baseIMR,
1107
+ IMR_Factor: IMRFactor,
1108
+ leverage,
1109
+ newOrder
1110
+ } = inputs;
1111
+ const signedOrderQty = (_a = newOrder == null ? void 0 : newOrder.qty) != null ? _a : 0;
1112
+ const newPositionQty = positionQty + signedOrderQty;
1113
+ if (newPositionQty === 0) {
1114
+ return 0;
1115
+ }
1116
+ const orderRefPrice = (_b = newOrder == null ? void 0 : newOrder.price) != null ? _b : markPrice;
1117
+ if (markPrice <= 0 || signedOrderQty !== 0 && orderRefPrice <= 0) {
1118
+ return 0;
1119
+ }
1120
+ const isSameSign = (a, b) => a > 0 && b > 0 || a < 0 && b < 0;
1121
+ const getScenario = () => {
1122
+ if (signedOrderQty === 0) return "NO_ORDER";
1123
+ if (positionQty === 0 || isSameSign(signedOrderQty, positionQty))
1124
+ return "OPEN_ADD";
1125
+ if (isSameSign(positionQty, newPositionQty)) return "REDUCE";
1126
+ return "FLIP";
1127
+ };
1128
+ const decNewPositionQty = new Decimal(newPositionQty);
1129
+ const decAbsNewPositionQty = decNewPositionQty.abs();
1130
+ const decCostPosition = new Decimal(costPosition);
1131
+ const decIsolatedMargin = new Decimal(isolatedPositionMargin);
1132
+ const decOrderCost = new Decimal(signedOrderQty).mul(orderRefPrice);
1133
+ let newIsolatedPositionMargin;
1134
+ let newCostPosition;
1135
+ switch (getScenario()) {
1136
+ case "NO_ORDER":
1137
+ newIsolatedPositionMargin = decIsolatedMargin;
1138
+ newCostPosition = decCostPosition;
1139
+ break;
1140
+ case "OPEN_ADD":
1141
+ newIsolatedPositionMargin = decIsolatedMargin.add(
1142
+ new Decimal(Math.abs(signedOrderQty)).mul(orderRefPrice).div(leverage)
1143
+ );
1144
+ newCostPosition = decCostPosition.add(decOrderCost);
1145
+ break;
1146
+ case "REDUCE":
1147
+ newIsolatedPositionMargin = decIsolatedMargin.mul(newPositionQty).div(positionQty);
1148
+ newCostPosition = decCostPosition.add(decOrderCost);
1149
+ break;
1150
+ case "FLIP":
1151
+ newIsolatedPositionMargin = decAbsNewPositionQty.mul(orderRefPrice).div(leverage);
1152
+ newCostPosition = decNewPositionQty.mul(orderRefPrice);
1153
+ break;
1154
+ }
1155
+ const fundingAdjustment = decNewPositionQty.mul(
1156
+ new Decimal(sumUnitaryFunding).sub(lastSumUnitaryFunding)
1157
+ );
1158
+ const newPositionNotional = decAbsNewPositionQty.mul(markPrice);
1159
+ const dynamicMMR = new Decimal(baseMMR).div(baseIMR).mul(IMRFactor).mul(newPositionNotional.toPower(IMRFactorPower)).toNumber();
1160
+ const newMMR = Math.max(baseMMR, dynamicMMR);
1161
+ const denominator = decAbsNewPositionQty.mul(newMMR).sub(decNewPositionQty);
1162
+ if (denominator.isZero()) {
1163
+ return 0;
1164
+ }
1165
+ const liquidationPrice = newIsolatedPositionMargin.sub(newCostPosition).sub(fundingAdjustment).div(denominator).toNumber();
1166
+ return Math.max(0, liquidationPrice);
761
1167
  }
762
1168
  function estLiqPrice(inputs) {
763
1169
  var _a;
@@ -772,13 +1178,13 @@ function estLiqPrice(inputs) {
772
1178
  IMR_Factor
773
1179
  } = inputs;
774
1180
  let currentPosition = void 0;
775
- let newTotalMM = zero3;
1181
+ let newTotalMM = zero;
776
1182
  const hasPosition = positions.filter((item) => item.position_qty > 0).length > 0;
777
1183
  const basePrice = hasPosition ? markPrice : newOrder.price;
778
- const newOrderNotional = new Decimal4(newOrder.qty).mul(newOrder.price);
1184
+ const newOrderNotional = new Decimal(newOrder.qty).mul(newOrder.price);
779
1185
  for (let index = 0; index < positions.length; index++) {
780
1186
  const position = positions[index];
781
- let notional2 = new Decimal4(position.position_qty).mul(position.mark_price);
1187
+ let notional2 = new Decimal(position.position_qty).mul(position.mark_price);
782
1188
  if (newOrder.symbol === position.symbol) {
783
1189
  currentPosition = position;
784
1190
  notional2 = notional2.add(newOrderNotional);
@@ -790,26 +1196,26 @@ function estLiqPrice(inputs) {
790
1196
  }
791
1197
  const newMMR = Math.max(
792
1198
  baseMMR,
793
- new Decimal4(baseMMR).div(baseIMR).mul(IMR_Factor).mul(
1199
+ new Decimal(baseMMR).div(baseIMR).mul(IMR_Factor).mul(
794
1200
  newOrderNotional.add(
795
- !!currentPosition ? new Decimal4(currentPosition.position_qty).mul(
1201
+ !!currentPosition ? new Decimal(currentPosition.position_qty).mul(
796
1202
  currentPosition.mark_price
797
- ) : zero3
1203
+ ) : zero
798
1204
  ).abs()
799
1205
  ).toPower(4 / 5).toNumber()
800
1206
  );
801
- const newQty = new Decimal4(newOrder.qty).add(
1207
+ const newQty = new Decimal(newOrder.qty).add(
802
1208
  (_a = currentPosition == null ? void 0 : currentPosition.position_qty) != null ? _a : 0
803
1209
  );
804
1210
  if (newQty.eq(0)) {
805
1211
  return 0;
806
1212
  }
807
1213
  const denominator = newQty.abs().mul(newMMR).sub(newQty);
808
- if (denominator.eq(zero3)) {
1214
+ if (denominator.eq(zero)) {
809
1215
  return 0;
810
1216
  }
811
- const price = new Decimal4(basePrice).add(
812
- new Decimal4(totalCollateral2).sub(newTotalMM).sub(orderFee2).div(denominator)
1217
+ const price = new Decimal(basePrice).add(
1218
+ new Decimal(totalCollateral2).sub(newTotalMM).sub(orderFee2).div(denominator)
813
1219
  ).toNumber();
814
1220
  return Math.max(0, price);
815
1221
  }
@@ -820,25 +1226,25 @@ function estLeverage(inputs) {
820
1226
  }
821
1227
  let hasPosition = false;
822
1228
  let sumPositionNotional = positions.reduce((acc, cur) => {
823
- let count = new Decimal4(cur.position_qty).mul(cur.mark_price);
1229
+ let count = new Decimal(cur.position_qty).mul(cur.mark_price);
824
1230
  if (cur.symbol === newOrder.symbol) {
825
1231
  hasPosition = true;
826
- count = count.add(new Decimal4(newOrder.qty).mul(newOrder.price));
1232
+ count = count.add(new Decimal(newOrder.qty).mul(newOrder.price));
827
1233
  }
828
1234
  return acc.add(count.abs());
829
- }, zero3);
1235
+ }, zero);
830
1236
  if (!hasPosition) {
831
1237
  sumPositionNotional = sumPositionNotional.add(
832
- new Decimal4(newOrder.qty).mul(newOrder.price).abs()
1238
+ new Decimal(newOrder.qty).mul(newOrder.price).abs()
833
1239
  );
834
1240
  }
835
- if (sumPositionNotional.eq(zero3)) {
1241
+ if (sumPositionNotional.eq(zero)) {
836
1242
  return null;
837
1243
  }
838
- const totalMarginRatio2 = new Decimal4(totalCollateral2).div(
1244
+ const totalMarginRatio2 = new Decimal(totalCollateral2).div(
839
1245
  sumPositionNotional
840
1246
  );
841
- return new Decimal4(1).div(totalMarginRatio2).toDecimalPlaces(2, Decimal4.ROUND_HALF_EVEN).toNumber();
1247
+ return new Decimal(1).div(totalMarginRatio2).toDecimalPlaces(2, Decimal.ROUND_HALF_EVEN).toNumber();
842
1248
  }
843
1249
  function tpslROI(inputs) {
844
1250
  const direction = getTPSLDirection({
@@ -848,13 +1254,9 @@ function tpslROI(inputs) {
848
1254
  orderPrice: inputs.orderPrice
849
1255
  });
850
1256
  const { closePrice, orderPrice, leverage } = inputs;
851
- return new Decimal4(closePrice).minus(orderPrice).div(orderPrice).mul(leverage).abs().mul(direction).toNumber();
852
- }
853
- export {
854
- account_exports as account,
855
- order_exports as order,
856
- order_exports as orderUtils,
857
- positions_exports as positions,
858
- version_default as version
859
- };
1257
+ return new Decimal(closePrice).minus(orderPrice).div(orderPrice).mul(leverage).abs().mul(direction).toNumber();
1258
+ }
1259
+
1260
+ export { account_exports as account, order_exports as order, order_exports as orderUtils, positions_exports as positions, version_default as version };
1261
+ //# sourceMappingURL=index.mjs.map
860
1262
  //# sourceMappingURL=index.mjs.map