@kodiak-finance/orderly-perp 4.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,702 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ // src/version.ts
8
+ if (typeof window !== "undefined") {
9
+ window.__ORDERLY_VERSION__ = window.__ORDERLY_VERSION__ || {};
10
+ window.__ORDERLY_VERSION__["@kodiak-finance/orderly-perp"] = "4.7.4";
11
+ }
12
+ var version_default = "4.7.4";
13
+
14
+ // src/positions.ts
15
+ var positions_exports = {};
16
+ __export(positions_exports, {
17
+ MMR: () => MMR,
18
+ estOffsetForTP: () => estOffsetForTP,
19
+ estPnLForSL: () => estPnLForSL,
20
+ estPnLForTP: () => estPnLForTP,
21
+ estPriceForTP: () => estPriceForTP,
22
+ estPriceFromOffsetForTP: () => estPriceFromOffsetForTP,
23
+ liqPrice: () => liqPrice,
24
+ maintenanceMargin: () => maintenanceMargin,
25
+ maxPositionLeverage: () => maxPositionLeverage,
26
+ maxPositionNotional: () => maxPositionNotional,
27
+ notional: () => notional,
28
+ totalNotional: () => totalNotional,
29
+ totalUnrealizedPnL: () => totalUnrealizedPnL,
30
+ totalUnsettlementPnL: () => totalUnsettlementPnL,
31
+ unrealizedPnL: () => unrealizedPnL,
32
+ unrealizedPnLROI: () => unrealizedPnLROI,
33
+ unsettlementPnL: () => unsettlementPnL
34
+ });
35
+ import { Decimal, zero } from "@kodiak-finance/orderly-utils";
36
+
37
+ // src/constants.ts
38
+ var IMRFactorPower = 4 / 5;
39
+
40
+ // src/positions.ts
41
+ function notional(qty, mark_price) {
42
+ return new Decimal(qty).mul(mark_price).abs().toNumber();
43
+ }
44
+ function totalNotional(positions) {
45
+ return positions.reduce((acc, cur) => {
46
+ return acc + notional(cur.position_qty, cur.mark_price);
47
+ }, 0);
48
+ }
49
+ function unrealizedPnL(inputs) {
50
+ return new Decimal(inputs.qty).mul(inputs.markPrice - inputs.openPrice).toNumber();
51
+ }
52
+ function unrealizedPnLROI(inputs) {
53
+ const { openPrice, IMR: IMR2 } = inputs;
54
+ if (inputs.unrealizedPnL === 0 || inputs.positionQty === 0 || openPrice === 0 || IMR2 === 0)
55
+ return 0;
56
+ return new Decimal(inputs.unrealizedPnL).div(new Decimal(Math.abs(inputs.positionQty)).mul(openPrice).mul(IMR2)).toNumber();
57
+ }
58
+ function totalUnrealizedPnL(positions) {
59
+ return positions.reduce((acc, cur) => {
60
+ return acc + unrealizedPnL({
61
+ qty: cur.position_qty,
62
+ openPrice: cur.average_open_price,
63
+ markPrice: cur.mark_price
64
+ });
65
+ }, 0);
66
+ }
67
+ function liqPrice(inputs) {
68
+ const { markPrice, totalCollateral: totalCollateral2, positions, positionQty, MMR: MMR3 } = inputs;
69
+ if (positionQty === 0 || totalCollateral2 === 0) {
70
+ return null;
71
+ }
72
+ const totalNotional2 = positions.reduce((acc, cur) => {
73
+ return acc.add(
74
+ new Decimal(notional(cur.position_qty, cur.mark_price)).mul(cur.mmr)
75
+ );
76
+ }, zero);
77
+ return Math.max(
78
+ new Decimal(markPrice).add(
79
+ new Decimal(totalCollateral2).sub(totalNotional2).div(new Decimal(positionQty).abs().mul(MMR3).sub(positionQty))
80
+ ).toNumber(),
81
+ 0
82
+ );
83
+ }
84
+ function maintenanceMargin(inputs) {
85
+ const { positionQty, markPrice, MMR: MMR3 } = inputs;
86
+ return new Decimal(positionQty).mul(markPrice).mul(MMR3).abs().toNumber();
87
+ }
88
+ function unsettlementPnL(inputs) {
89
+ const {
90
+ positionQty,
91
+ markPrice,
92
+ costPosition,
93
+ sumUnitaryFunding,
94
+ lastSumUnitaryFunding
95
+ } = inputs;
96
+ const qty = new Decimal(positionQty);
97
+ return qty.mul(markPrice).sub(costPosition).sub(qty.mul(new Decimal(sumUnitaryFunding).sub(lastSumUnitaryFunding))).toNumber();
98
+ }
99
+ function totalUnsettlementPnL(positions) {
100
+ if (!Array.isArray(positions) || positions.length === 0) {
101
+ return 0;
102
+ }
103
+ return positions.reduce((acc, cur) => {
104
+ return acc + unsettlementPnL({
105
+ positionQty: cur.position_qty,
106
+ markPrice: cur.mark_price,
107
+ costPosition: cur.cost_position,
108
+ sumUnitaryFunding: cur.sum_unitary_funding,
109
+ lastSumUnitaryFunding: cur.last_sum_unitary_funding
110
+ });
111
+ }, 0);
112
+ }
113
+ function MMR(inputs) {
114
+ const {
115
+ baseMMR,
116
+ baseIMR,
117
+ IMRFactor,
118
+ positionNotional,
119
+ IMR_factor_power = IMRFactorPower
120
+ } = inputs;
121
+ return Math.max(
122
+ baseMMR,
123
+ new Decimal(baseMMR).div(baseIMR).mul(IMRFactor).mul(Math.pow(Math.abs(positionNotional), IMR_factor_power)).toNumber()
124
+ );
125
+ }
126
+ function estPnLForTP(inputs) {
127
+ return new Decimal(inputs.positionQty).mul(new Decimal(inputs.price).sub(inputs.entryPrice)).toNumber();
128
+ }
129
+ function estPriceForTP(inputs) {
130
+ return new Decimal(inputs.pnl).add(inputs.entryPrice).div(inputs.positionQty).toNumber();
131
+ }
132
+ function estOffsetForTP(inputs) {
133
+ return new Decimal(inputs.price).div(inputs.entryPrice).toNumber();
134
+ }
135
+ function estPriceFromOffsetForTP(inputs) {
136
+ return new Decimal(inputs.offset).add(inputs.entryPrice).toNumber();
137
+ }
138
+ function estPnLForSL(inputs) {
139
+ return 0;
140
+ }
141
+ function maxPositionNotional(inputs) {
142
+ const { leverage, IMRFactor } = inputs;
143
+ return new Decimal(1).div(new Decimal(leverage).mul(IMRFactor)).pow(1 / 0.8).toNumber();
144
+ }
145
+ function maxPositionLeverage(inputs) {
146
+ const { IMRFactor, notional: notional2 } = inputs;
147
+ return new Decimal(1).div(new Decimal(IMRFactor).mul(new Decimal(notional2).pow(0.8))).toNumber();
148
+ }
149
+
150
+ // src/account.ts
151
+ var account_exports = {};
152
+ __export(account_exports, {
153
+ IMR: () => IMR,
154
+ LTV: () => LTV,
155
+ MMR: () => MMR2,
156
+ availableBalance: () => availableBalance,
157
+ buyOrdersFilter_by_symbol: () => buyOrdersFilter_by_symbol,
158
+ calcMinimumReceived: () => calcMinimumReceived,
159
+ collateralContribution: () => collateralContribution,
160
+ collateralRatio: () => collateralRatio,
161
+ currentLeverage: () => currentLeverage,
162
+ extractSymbols: () => extractSymbols,
163
+ freeCollateral: () => freeCollateral,
164
+ getPositonsAndOrdersNotionalBySymbol: () => getPositonsAndOrdersNotionalBySymbol,
165
+ getQtyFromOrdersBySide: () => getQtyFromOrdersBySide,
166
+ getQtyFromPositions: () => getQtyFromPositions,
167
+ groupOrdersBySymbol: () => groupOrdersBySymbol,
168
+ initialMarginWithOrder: () => initialMarginWithOrder,
169
+ maxLeverage: () => maxLeverage,
170
+ maxQty: () => maxQty,
171
+ maxQtyByLong: () => maxQtyByLong,
172
+ maxQtyByShort: () => maxQtyByShort,
173
+ maxWithdrawalOtherCollateral: () => maxWithdrawalOtherCollateral,
174
+ maxWithdrawalUSDC: () => maxWithdrawalUSDC,
175
+ otherIMs: () => otherIMs,
176
+ positionNotionalWithOrder_by_symbol: () => positionNotionalWithOrder_by_symbol,
177
+ positionQtyWithOrders_by_symbol: () => positionQtyWithOrders_by_symbol,
178
+ sellOrdersFilter_by_symbol: () => sellOrdersFilter_by_symbol,
179
+ totalCollateral: () => totalCollateral,
180
+ totalInitialMarginWithOrders: () => totalInitialMarginWithOrders,
181
+ totalInitialMarginWithQty: () => totalInitialMarginWithQty,
182
+ totalMarginRatio: () => totalMarginRatio,
183
+ totalUnrealizedROI: () => totalUnrealizedROI,
184
+ totalValue: () => totalValue
185
+ });
186
+ import { OrderSide } from "@kodiak-finance/orderly-types";
187
+ import { Decimal as Decimal2, zero as zero2 } from "@kodiak-finance/orderly-utils";
188
+ function totalValue(inputs) {
189
+ const { totalUnsettlementPnL: totalUnsettlementPnL2, USDCHolding, nonUSDCHolding } = inputs;
190
+ const nonUSDCHoldingValue = nonUSDCHolding.reduce((acc, cur) => {
191
+ return new Decimal2(cur.holding).mul(cur.indexPrice).add(acc);
192
+ }, zero2);
193
+ return nonUSDCHoldingValue.add(USDCHolding).add(totalUnsettlementPnL2);
194
+ }
195
+ function freeCollateral(inputs) {
196
+ const value = inputs.totalCollateral.sub(inputs.totalInitialMarginWithOrders);
197
+ return value.isNegative() ? zero2 : value;
198
+ }
199
+ function totalCollateral(inputs) {
200
+ const { USDCHolding, nonUSDCHolding, unsettlementPnL: unsettlementPnL2 } = inputs;
201
+ const nonUSDCHoldingValue = nonUSDCHolding.reduce((acc, cur) => {
202
+ const finalHolding = Math.min(cur.holding, cur.collateralCap);
203
+ const value = new Decimal2(finalHolding).mul(cur.collateralRatio).mul(cur.indexPrice);
204
+ return acc.add(value);
205
+ }, zero2);
206
+ return new Decimal2(USDCHolding).add(nonUSDCHoldingValue).add(unsettlementPnL2);
207
+ }
208
+ function initialMarginWithOrder() {
209
+ }
210
+ function positionNotionalWithOrder_by_symbol(inputs) {
211
+ return new Decimal2(inputs.markPrice).mul(inputs.positionQtyWithOrders);
212
+ }
213
+ function positionQtyWithOrders_by_symbol(inputs) {
214
+ const { positionQty, buyOrdersQty, sellOrdersQty } = inputs;
215
+ const positionQtyDecimal = new Decimal2(positionQty);
216
+ const qty = Math.max(
217
+ positionQtyDecimal.add(buyOrdersQty).abs().toNumber(),
218
+ positionQtyDecimal.sub(sellOrdersQty).abs().toNumber()
219
+ );
220
+ return qty;
221
+ }
222
+ function IMR(inputs) {
223
+ const {
224
+ maxLeverage: maxLeverage2,
225
+ baseIMR,
226
+ IMR_Factor,
227
+ positionNotional,
228
+ ordersNotional: orderNotional,
229
+ IMR_factor_power = IMRFactorPower
230
+ } = inputs;
231
+ return Math.max(
232
+ 1 / maxLeverage2,
233
+ baseIMR,
234
+ new Decimal2(IMR_Factor).mul(
235
+ new Decimal2(positionNotional).add(orderNotional).abs().toPower(IMR_factor_power)
236
+ ).toNumber()
237
+ );
238
+ }
239
+ function buyOrdersFilter_by_symbol(orders, symbol) {
240
+ return orders.filter(
241
+ (item) => item.symbol === symbol && item.side === OrderSide.BUY
242
+ );
243
+ }
244
+ function sellOrdersFilter_by_symbol(orders, symbol) {
245
+ return orders.filter(
246
+ (item) => item.symbol === symbol && item.side === OrderSide.SELL
247
+ );
248
+ }
249
+ function getQtyFromPositions(positions, symbol) {
250
+ if (!positions) {
251
+ return 0;
252
+ }
253
+ const position = positions.find((item) => item.symbol === symbol);
254
+ return (position == null ? void 0 : position.position_qty) || 0;
255
+ }
256
+ function getQtyFromOrdersBySide(orders, symbol, side) {
257
+ const ordersBySide = side === OrderSide.SELL ? sellOrdersFilter_by_symbol(orders, symbol) : buyOrdersFilter_by_symbol(orders, symbol);
258
+ return ordersBySide.reduce((acc, cur) => {
259
+ return acc + cur.quantity;
260
+ }, 0);
261
+ }
262
+ function getPositonsAndOrdersNotionalBySymbol(inputs) {
263
+ const { positions, orders, symbol, markPrice } = inputs;
264
+ const positionQty = getQtyFromPositions(positions, symbol);
265
+ const buyOrdersQty = getQtyFromOrdersBySide(orders, symbol, OrderSide.BUY);
266
+ const sellOrdersQty = getQtyFromOrdersBySide(orders, symbol, OrderSide.SELL);
267
+ const markPriceDecimal = new Decimal2(markPrice);
268
+ return markPriceDecimal.mul(positionQty).add(markPriceDecimal.mul(new Decimal2(buyOrdersQty).add(sellOrdersQty))).abs().toNumber();
269
+ }
270
+ function totalInitialMarginWithOrders(inputs) {
271
+ const {
272
+ positions,
273
+ orders,
274
+ markPrices,
275
+ IMR_Factors,
276
+ maxLeverage: maxLeverage2,
277
+ symbolInfo
278
+ } = inputs;
279
+ const symbols = extractSymbols(positions, orders);
280
+ const total_initial_margin_with_orders = symbols.reduce((acc, cur) => {
281
+ const symbol = cur;
282
+ const positionQty = getQtyFromPositions(positions, symbol);
283
+ const buyOrdersQty = getQtyFromOrdersBySide(orders, symbol, OrderSide.BUY);
284
+ const sellOrdersQty = getQtyFromOrdersBySide(
285
+ orders,
286
+ symbol,
287
+ OrderSide.SELL
288
+ );
289
+ const markPrice = markPrices[symbol] || 0;
290
+ const positionQtyWithOrders = positionQtyWithOrders_by_symbol({
291
+ positionQty,
292
+ buyOrdersQty,
293
+ sellOrdersQty
294
+ });
295
+ const position_notional_with_orders = positionNotionalWithOrder_by_symbol({
296
+ markPrice,
297
+ positionQtyWithOrders
298
+ });
299
+ const markPriceDecimal = new Decimal2(markPrice);
300
+ const imr = IMR({
301
+ positionNotional: markPriceDecimal.mul(positionQty).toNumber(),
302
+ ordersNotional: markPriceDecimal.mul(new Decimal2(buyOrdersQty).add(sellOrdersQty)).toNumber(),
303
+ maxLeverage: maxLeverage2,
304
+ IMR_Factor: IMR_Factors[symbol],
305
+ baseIMR: symbolInfo[symbol]("base_imr", 0)
306
+ });
307
+ return position_notional_with_orders.mul(imr).add(acc).toNumber();
308
+ }, 0);
309
+ return total_initial_margin_with_orders;
310
+ }
311
+ function totalInitialMarginWithQty(inputs) {
312
+ const { positions, markPrices, IMR_Factors, symbolInfo } = inputs;
313
+ const symbols = positions.map((item) => item.symbol);
314
+ const total_initial_margin_with_orders = symbols.reduce((acc, cur) => {
315
+ var _a;
316
+ const symbol = cur;
317
+ const position = positions.find((item) => item.symbol === symbol);
318
+ const positionQty = (position == null ? void 0 : position.position_qty) || 0;
319
+ const buyOrdersQty = (position == null ? void 0 : position.pending_long_qty) || 0;
320
+ const sellOrdersQty = (position == null ? void 0 : position.pending_short_qty) || 0;
321
+ const markPrice = markPrices[symbol] || 0;
322
+ const positionQtyWithOrders = positionQtyWithOrders_by_symbol({
323
+ positionQty,
324
+ buyOrdersQty,
325
+ sellOrdersQty
326
+ });
327
+ const position_notional_with_orders = positionNotionalWithOrder_by_symbol({
328
+ markPrice,
329
+ positionQtyWithOrders
330
+ });
331
+ const markPriceDecimal = new Decimal2(markPrice);
332
+ const imr = IMR({
333
+ positionNotional: markPriceDecimal.mul(positionQty).toNumber(),
334
+ ordersNotional: markPriceDecimal.mul(new Decimal2(buyOrdersQty).add(sellOrdersQty)).toNumber(),
335
+ maxLeverage: maxLeverage({
336
+ symbolLeverage: (_a = position == null ? void 0 : position.leverage) != null ? _a : inputs.maxLeverage,
337
+ accountLeverage: inputs.maxLeverage
338
+ }),
339
+ IMR_Factor: IMR_Factors[symbol],
340
+ baseIMR: symbolInfo[symbol]("base_imr", 0)
341
+ });
342
+ return position_notional_with_orders.mul(imr).add(acc).toNumber();
343
+ }, 0);
344
+ return total_initial_margin_with_orders;
345
+ }
346
+ function groupOrdersBySymbol(orders) {
347
+ const symbols = {};
348
+ orders.forEach((item) => {
349
+ if (!symbols[item.symbol]) {
350
+ symbols[item.symbol] = [];
351
+ }
352
+ symbols[item.symbol].push(item);
353
+ });
354
+ return symbols;
355
+ }
356
+ function extractSymbols(positions, orders) {
357
+ const symbols = /* @__PURE__ */ new Set();
358
+ positions.forEach((item) => {
359
+ symbols.add(item.symbol);
360
+ });
361
+ orders.forEach((item) => {
362
+ symbols.add(item.symbol);
363
+ });
364
+ return Array.from(symbols);
365
+ }
366
+ function otherIMs(inputs) {
367
+ const {
368
+ // orders,
369
+ positions,
370
+ IMR_Factors,
371
+ symbolInfo,
372
+ markPrices
373
+ } = inputs;
374
+ const symbols = positions.map((item) => item.symbol);
375
+ return symbols.reduce((acc, cur) => {
376
+ const symbol = cur;
377
+ if (typeof markPrices[symbol] === "undefined") {
378
+ console.warn("markPrices[%s] is undefined", symbol);
379
+ return acc;
380
+ }
381
+ const markPriceDecimal = new Decimal2(markPrices[symbol] || 0);
382
+ const position = positions.find((item) => item.symbol === symbol);
383
+ const positionQty = getQtyFromPositions(positions, symbol);
384
+ const positionNotional = markPriceDecimal.mul(positionQty).toNumber();
385
+ const buyOrdersQty = position.pending_long_qty;
386
+ const sellOrdersQty = position.pending_short_qty;
387
+ const ordersNotional = markPriceDecimal.mul(new Decimal2(buyOrdersQty).add(sellOrdersQty)).toNumber();
388
+ const IMR_Factor = IMR_Factors[symbol];
389
+ if (!IMR_Factor) {
390
+ console.warn("IMR_Factor is not found:", symbol);
391
+ return acc;
392
+ }
393
+ const imr = IMR({
394
+ maxLeverage: maxLeverage({
395
+ symbolLeverage: position.leverage,
396
+ accountLeverage: inputs.maxLeverage
397
+ }),
398
+ IMR_Factor,
399
+ baseIMR: symbolInfo[symbol]("base_imr", 0),
400
+ positionNotional,
401
+ ordersNotional
402
+ });
403
+ const positionQtyWithOrders = positionQtyWithOrders_by_symbol({
404
+ positionQty,
405
+ buyOrdersQty,
406
+ sellOrdersQty
407
+ });
408
+ const positionNotionalWithOrders = positionNotionalWithOrder_by_symbol({
409
+ markPrice: markPrices[symbol] || 0,
410
+ positionQtyWithOrders
411
+ });
412
+ return acc.add(positionNotionalWithOrders.mul(imr));
413
+ }, zero2).toNumber();
414
+ }
415
+ function maxQty(side, inputs, options) {
416
+ if (side === OrderSide.BUY) {
417
+ return maxQtyByLong(inputs);
418
+ }
419
+ return maxQtyByShort(inputs);
420
+ }
421
+ function maxQtyByLong(inputs, options) {
422
+ try {
423
+ const {
424
+ baseMaxQty,
425
+ totalCollateral: totalCollateral2,
426
+ otherIMs: otherIMs2,
427
+ maxLeverage: maxLeverage2,
428
+ baseIMR,
429
+ markPrice,
430
+ IMR_Factor,
431
+ positionQty,
432
+ buyOrdersQty,
433
+ takerFeeRate
434
+ } = inputs;
435
+ if (totalCollateral2 === 0) {
436
+ return 0;
437
+ }
438
+ const totalCollateralDecimal = new Decimal2(totalCollateral2);
439
+ const factor_1 = totalCollateralDecimal.sub(otherIMs2).div(
440
+ new Decimal2(takerFeeRate).mul(2).mul(1e-4).add(Math.max(1 / maxLeverage2, baseIMR))
441
+ ).div(markPrice).mul(0.995).sub(new Decimal2(positionQty).add(buyOrdersQty)).toNumber();
442
+ if (positionQty === 0 && buyOrdersQty === 0) {
443
+ return Math.min(baseMaxQty, factor_1);
444
+ }
445
+ const factor_2 = totalCollateralDecimal.sub(otherIMs2).div(IMR_Factor).toPower(1 / 1.8).div(markPrice).sub(
446
+ new Decimal2(positionQty).add(buyOrdersQty)
447
+ // .abs()
448
+ // .div(new Decimal(takerFeeRate).mul(2).mul(0.0001).add(1))
449
+ ).div(new Decimal2(takerFeeRate).mul(2).mul(1e-4).add(1)).mul(0.995).toNumber();
450
+ return Math.min(baseMaxQty, factor_1, factor_2);
451
+ } catch (error) {
452
+ return 0;
453
+ }
454
+ }
455
+ function maxQtyByShort(inputs, options) {
456
+ try {
457
+ const {
458
+ baseMaxQty,
459
+ totalCollateral: totalCollateral2,
460
+ otherIMs: otherIMs2,
461
+ maxLeverage: maxLeverage2,
462
+ baseIMR,
463
+ markPrice,
464
+ IMR_Factor,
465
+ positionQty,
466
+ buyOrdersQty,
467
+ sellOrdersQty,
468
+ takerFeeRate
469
+ } = inputs;
470
+ const totalCollateralDecimal = new Decimal2(totalCollateral2);
471
+ const factor_1 = totalCollateralDecimal.sub(otherIMs2).div(
472
+ new Decimal2(takerFeeRate).mul(2).mul(1e-4).add(Math.max(1 / maxLeverage2, baseIMR))
473
+ ).div(markPrice).mul(0.995).add(positionQty).sub(Math.abs(sellOrdersQty)).toNumber();
474
+ if (positionQty === 0 && sellOrdersQty === 0) {
475
+ return Math.min(baseMaxQty, factor_1);
476
+ }
477
+ const factor_2 = totalCollateralDecimal.sub(otherIMs2).div(IMR_Factor).toPower(1 / 1.8).div(markPrice).add(positionQty).sub(sellOrdersQty).div(new Decimal2(takerFeeRate).mul(2).mul(1e-4).add(1)).mul(0.995).toNumber();
478
+ return Math.min(baseMaxQty, factor_1, factor_2);
479
+ } catch (error) {
480
+ return 0;
481
+ }
482
+ }
483
+ function totalMarginRatio(inputs, dp) {
484
+ const { totalCollateral: totalCollateral2, markPrices, positions } = inputs;
485
+ if (totalCollateral2 === 0) {
486
+ return 0;
487
+ }
488
+ const totalCollateralDecimal = new Decimal2(totalCollateral2);
489
+ const totalPositionNotional = positions.reduce((acc, cur) => {
490
+ const markPrice = markPrices[cur.symbol] || 0;
491
+ return acc.add(new Decimal2(cur.position_qty).mul(markPrice).abs());
492
+ }, zero2);
493
+ if (totalPositionNotional.eq(zero2)) {
494
+ return 0;
495
+ }
496
+ return totalCollateralDecimal.div(totalPositionNotional).toNumber();
497
+ }
498
+ function totalUnrealizedROI(inputs) {
499
+ const { totalUnrealizedPnL: totalUnrealizedPnL2, totalValue: totalValue2 } = inputs;
500
+ return new Decimal2(totalUnrealizedPnL2).div(totalValue2 - totalUnrealizedPnL2).toNumber();
501
+ }
502
+ function currentLeverage(totalMarginRatio2) {
503
+ if (totalMarginRatio2 === 0) {
504
+ return 0;
505
+ }
506
+ return 1 / totalMarginRatio2;
507
+ }
508
+ function availableBalance(inputs) {
509
+ const { USDCHolding, unsettlementPnL: unsettlementPnL2 } = inputs;
510
+ return new Decimal2(USDCHolding).add(unsettlementPnL2).toNumber();
511
+ }
512
+ function MMR2(inputs) {
513
+ if (inputs.positionsNotional === 0) {
514
+ return null;
515
+ }
516
+ if (inputs.positionsMMR === 0) {
517
+ return null;
518
+ }
519
+ return new Decimal2(inputs.positionsMMR).div(inputs.positionsNotional).toNumber();
520
+ }
521
+ var collateralRatio = (params) => {
522
+ const {
523
+ baseWeight,
524
+ discountFactor,
525
+ collateralQty,
526
+ collateralCap,
527
+ indexPrice
528
+ } = params;
529
+ const cap = collateralCap === -1 ? collateralQty : collateralCap;
530
+ const K = new Decimal2(1.2);
531
+ const DCF = new Decimal2(discountFactor || 0);
532
+ const qty = new Decimal2(Math.min(collateralQty, cap));
533
+ const notionalAbs = qty.mul(indexPrice).abs();
534
+ const dynamicWeight = DCF.mul(notionalAbs).toPower(IMRFactorPower);
535
+ const result = K.div(new Decimal2(1).add(dynamicWeight));
536
+ return result.lt(baseWeight) ? result : new Decimal2(baseWeight);
537
+ };
538
+ var collateralContribution = (params) => {
539
+ const { collateralQty, collateralCap, collateralRatio: collateralRatio2, indexPrice } = params;
540
+ const cap = collateralCap === -1 ? collateralQty : collateralCap;
541
+ return new Decimal2(Math.min(collateralQty, cap)).mul(collateralRatio2).mul(indexPrice).toNumber();
542
+ };
543
+ var LTV = (params) => {
544
+ const { usdcBalance, upnl, assets } = params;
545
+ const usdcLoss = new Decimal2(Math.min(usdcBalance, 0)).abs();
546
+ const upnlLoss = new Decimal2(Math.min(upnl, 0)).abs();
547
+ const numerator = usdcLoss.add(upnlLoss);
548
+ const collateralSum = assets.reduce((acc, asset) => {
549
+ return acc.add(
550
+ new Decimal2(Math.max(asset.qty, 0)).mul(new Decimal2(asset.indexPrice)).mul(new Decimal2(asset.weight))
551
+ );
552
+ }, zero2);
553
+ const denominator = collateralSum.add(new Decimal2(Math.max(upnl, 0)));
554
+ if (numerator.isZero() || denominator.isZero()) {
555
+ return 0;
556
+ }
557
+ return numerator.div(denominator).toNumber();
558
+ };
559
+ var maxWithdrawalUSDC = (inputs) => {
560
+ const { USDCBalance, freeCollateral: freeCollateral2, upnl } = inputs;
561
+ const value = Math.min(
562
+ new Decimal2(USDCBalance).toNumber(),
563
+ new Decimal2(freeCollateral2).sub(Math.max(upnl, 0)).toNumber()
564
+ );
565
+ return Math.max(0, value);
566
+ };
567
+ var maxWithdrawalOtherCollateral = (inputs) => {
568
+ const { USDCBalance, collateralQty, freeCollateral: freeCollateral2, indexPrice, weight } = inputs;
569
+ const usdcBalance = new Decimal2(USDCBalance);
570
+ const denominator = usdcBalance.isNegative() ? new Decimal2(indexPrice).mul(weight).mul(new Decimal2(1).add(2e-3)) : new Decimal2(indexPrice).mul(weight);
571
+ if (denominator.isZero()) {
572
+ return zero2;
573
+ }
574
+ const qty = new Decimal2(collateralQty);
575
+ const maxQtyByValue = new Decimal2(freeCollateral2).div(denominator);
576
+ return maxQtyByValue.lt(qty) ? maxQtyByValue : qty;
577
+ };
578
+ var calcMinimumReceived = (inputs) => {
579
+ const { amount, slippage } = inputs;
580
+ const slippageRatio = new Decimal2(slippage).div(100);
581
+ return new Decimal2(amount).mul(new Decimal2(1).minus(slippageRatio)).toNumber();
582
+ };
583
+ var maxLeverage = (inputs) => {
584
+ const { symbolLeverage, accountLeverage } = inputs;
585
+ return symbolLeverage != null ? symbolLeverage : 1;
586
+ };
587
+
588
+ // src/order.ts
589
+ var order_exports = {};
590
+ __export(order_exports, {
591
+ estLeverage: () => estLeverage,
592
+ estLiqPrice: () => estLiqPrice,
593
+ maxPrice: () => maxPrice,
594
+ minPrice: () => minPrice,
595
+ orderFee: () => orderFee,
596
+ scopePrice: () => scopePrice
597
+ });
598
+ import { Decimal as Decimal3, zero as zero3 } from "@kodiak-finance/orderly-utils";
599
+ function maxPrice(markprice, range) {
600
+ return markprice * (1 + range);
601
+ }
602
+ function minPrice(markprice, range) {
603
+ return markprice * (1 - range);
604
+ }
605
+ function scopePrice(price, scope, side) {
606
+ if (side === "BUY") {
607
+ return price * (1 - scope);
608
+ }
609
+ return price * (1 + scope);
610
+ }
611
+ function orderFee(inputs) {
612
+ return new Decimal3(inputs.qty).mul(inputs.price).mul(inputs.futuresTakeFeeRate).toNumber();
613
+ }
614
+ function estLiqPrice(inputs) {
615
+ var _a;
616
+ const {
617
+ positions,
618
+ newOrder,
619
+ totalCollateral: totalCollateral2,
620
+ markPrice,
621
+ baseIMR,
622
+ baseMMR,
623
+ orderFee: orderFee2,
624
+ IMR_Factor
625
+ } = inputs;
626
+ let currentPosition = void 0;
627
+ let newTotalMM = zero3;
628
+ const hasPosition = positions.filter((item) => item.position_qty > 0).length > 0;
629
+ const basePrice = hasPosition ? markPrice : newOrder.price;
630
+ const newOrderNotional = new Decimal3(newOrder.qty).mul(newOrder.price);
631
+ for (let index = 0; index < positions.length; index++) {
632
+ const position = positions[index];
633
+ let notional2 = new Decimal3(position.position_qty).mul(position.mark_price);
634
+ if (newOrder.symbol === position.symbol) {
635
+ currentPosition = position;
636
+ notional2 = notional2.add(newOrderNotional);
637
+ }
638
+ newTotalMM = newTotalMM.add(notional2.abs().mul(position.mmr));
639
+ }
640
+ if (!currentPosition) {
641
+ newTotalMM = newTotalMM.add(newOrderNotional.mul(baseMMR));
642
+ }
643
+ const newMMR = Math.max(
644
+ baseMMR,
645
+ new Decimal3(baseMMR).div(baseIMR).mul(IMR_Factor).mul(
646
+ newOrderNotional.add(
647
+ !!currentPosition ? new Decimal3(currentPosition.position_qty).mul(
648
+ currentPosition.mark_price
649
+ ) : zero3
650
+ ).abs()
651
+ ).toPower(4 / 5).toNumber()
652
+ );
653
+ const newQty = new Decimal3(newOrder.qty).add(
654
+ (_a = currentPosition == null ? void 0 : currentPosition.position_qty) != null ? _a : 0
655
+ );
656
+ if (newQty.eq(0)) {
657
+ return 0;
658
+ }
659
+ const denominator = newQty.abs().mul(newMMR).sub(newQty);
660
+ if (denominator.eq(zero3)) {
661
+ return 0;
662
+ }
663
+ const price = new Decimal3(basePrice).add(
664
+ new Decimal3(totalCollateral2).sub(newTotalMM).sub(orderFee2).div(denominator)
665
+ ).toNumber();
666
+ return Math.max(0, price);
667
+ }
668
+ function estLeverage(inputs) {
669
+ const { totalCollateral: totalCollateral2, positions, newOrder } = inputs;
670
+ if (totalCollateral2 <= 0) {
671
+ return null;
672
+ }
673
+ let hasPosition = false;
674
+ let sumPositionNotional = positions.reduce((acc, cur) => {
675
+ let count = new Decimal3(cur.position_qty).mul(cur.mark_price);
676
+ if (cur.symbol === newOrder.symbol) {
677
+ hasPosition = true;
678
+ count = count.add(new Decimal3(newOrder.qty).mul(newOrder.price));
679
+ }
680
+ return acc.add(count.abs());
681
+ }, zero3);
682
+ if (!hasPosition) {
683
+ sumPositionNotional = sumPositionNotional.add(
684
+ new Decimal3(newOrder.qty).mul(newOrder.price).abs()
685
+ );
686
+ }
687
+ if (sumPositionNotional.eq(zero3)) {
688
+ return null;
689
+ }
690
+ const totalMarginRatio2 = new Decimal3(totalCollateral2).div(
691
+ sumPositionNotional
692
+ );
693
+ return new Decimal3(1).div(totalMarginRatio2).toDecimalPlaces(2, Decimal3.ROUND_HALF_EVEN).toNumber();
694
+ }
695
+ export {
696
+ account_exports as account,
697
+ order_exports as order,
698
+ order_exports as orderUtils,
699
+ positions_exports as positions,
700
+ version_default as version
701
+ };
702
+ //# sourceMappingURL=index.mjs.map