@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/README.md +1 -0
- package/dist/index.d.mts +599 -0
- package/dist/index.d.ts +599 -0
- package/dist/index.js +727 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +702 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +39 -0
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
|