@lifi/perps-sdk 20.1.0 → 21.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +81 -6
- package/dist/cjs/client/PerpsClient.d.ts.map +1 -1
- package/dist/cjs/client/PerpsClient.js +4 -1
- package/dist/cjs/client/PerpsClient.js.map +1 -1
- package/dist/cjs/{utils/decimal.d.ts → decimal/big.d.ts} +1 -1
- package/dist/cjs/decimal/big.d.ts.map +1 -0
- package/dist/cjs/{utils/decimal.js → decimal/big.js} +1 -1
- package/dist/cjs/decimal/big.js.map +1 -0
- package/dist/cjs/decimal/convert.d.ts +11 -0
- package/dist/cjs/decimal/convert.d.ts.map +1 -0
- package/dist/cjs/decimal/convert.js +70 -0
- package/dist/cjs/decimal/convert.js.map +1 -0
- package/dist/cjs/decimal/format.d.ts.map +1 -0
- package/dist/cjs/decimal/format.js.map +1 -0
- package/dist/cjs/decimal/parse.d.ts +6 -0
- package/dist/cjs/decimal/parse.d.ts.map +1 -0
- package/dist/cjs/{utils → decimal}/parse.js +5 -4
- package/dist/cjs/decimal/parse.js.map +1 -0
- package/dist/cjs/index.d.ts +17 -15
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +75 -61
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/math/fills.d.ts +5 -0
- package/dist/cjs/math/fills.d.ts.map +1 -0
- package/dist/cjs/{utils/fillClassification.js → math/fills.js} +16 -1
- package/dist/cjs/math/fills.js.map +1 -0
- package/dist/cjs/math/order.d.ts +45 -0
- package/dist/cjs/math/order.d.ts.map +1 -0
- package/dist/cjs/math/order.js +256 -0
- package/dist/cjs/math/order.js.map +1 -0
- package/dist/cjs/math/position.d.ts +56 -0
- package/dist/cjs/math/position.d.ts.map +1 -0
- package/dist/cjs/math/position.js +160 -0
- package/dist/cjs/math/position.js.map +1 -0
- package/dist/cjs/services/resolveQuote.d.ts.map +1 -1
- package/dist/cjs/services/resolveQuote.js +2 -2
- package/dist/cjs/services/resolveQuote.js.map +1 -1
- package/dist/cjs/services/resolveSubscribeQuote.d.ts.map +1 -1
- package/dist/cjs/services/resolveSubscribeQuote.js +2 -2
- package/dist/cjs/services/resolveSubscribeQuote.js.map +1 -1
- package/dist/cjs/types/provider.d.ts +3 -3
- package/dist/cjs/types/provider.d.ts.map +1 -1
- package/dist/cjs/types/withdrawal.d.ts +7 -5
- package/dist/cjs/types/withdrawal.d.ts.map +1 -1
- package/dist/cjs/utils/orderClassification.d.ts +1 -3
- package/dist/cjs/utils/orderClassification.d.ts.map +1 -1
- package/dist/cjs/utils/orderClassification.js +1 -15
- package/dist/cjs/utils/orderClassification.js.map +1 -1
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/wire/orderAmounts.d.ts +18 -0
- package/dist/cjs/wire/orderAmounts.d.ts.map +1 -0
- package/dist/cjs/wire/orderAmounts.js +79 -0
- package/dist/cjs/wire/orderAmounts.js.map +1 -0
- package/dist/cjs/wire/refuel.d.ts +8 -0
- package/dist/cjs/wire/refuel.d.ts.map +1 -0
- package/dist/cjs/wire/refuel.js +23 -0
- package/dist/cjs/wire/refuel.js.map +1 -0
- package/dist/cjs/wire/requireDecimal.d.ts +4 -0
- package/dist/cjs/wire/requireDecimal.d.ts.map +1 -0
- package/dist/cjs/wire/requireDecimal.js +16 -0
- package/dist/cjs/wire/requireDecimal.js.map +1 -0
- package/dist/cjs/wire/snap.d.ts +5 -0
- package/dist/cjs/wire/snap.d.ts.map +1 -0
- package/dist/cjs/wire/snap.js +12 -0
- package/dist/cjs/wire/snap.js.map +1 -0
- package/dist/cjs/wire/transferable.d.ts +3 -0
- package/dist/cjs/wire/transferable.d.ts.map +1 -0
- package/dist/cjs/wire/transferable.js +13 -0
- package/dist/cjs/wire/transferable.js.map +1 -0
- package/dist/cjs/wire/withdraw.d.ts +4 -0
- package/dist/cjs/wire/withdraw.d.ts.map +1 -0
- package/dist/cjs/wire/withdraw.js +13 -0
- package/dist/cjs/wire/withdraw.js.map +1 -0
- package/dist/esm/client/PerpsClient.d.ts.map +1 -1
- package/dist/esm/client/PerpsClient.js +4 -1
- package/dist/esm/client/PerpsClient.js.map +1 -1
- package/dist/esm/{utils/decimal.d.ts → decimal/big.d.ts} +1 -1
- package/dist/esm/decimal/big.d.ts.map +1 -0
- package/dist/esm/{utils/decimal.js → decimal/big.js} +1 -1
- package/dist/esm/decimal/big.js.map +1 -0
- package/dist/esm/decimal/convert.d.ts +80 -0
- package/dist/esm/decimal/convert.d.ts.map +1 -0
- package/dist/esm/decimal/convert.js +118 -0
- package/dist/esm/decimal/convert.js.map +1 -0
- package/dist/esm/decimal/format.d.ts.map +1 -0
- package/dist/esm/decimal/format.js.map +1 -0
- package/dist/esm/decimal/parse.d.ts +29 -0
- package/dist/esm/decimal/parse.d.ts.map +1 -0
- package/dist/esm/{utils → decimal}/parse.js +9 -10
- package/dist/esm/decimal/parse.js.map +1 -0
- package/dist/esm/index.d.ts +17 -15
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +12 -12
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/math/fills.d.ts +26 -0
- package/dist/esm/math/fills.d.ts.map +1 -0
- package/dist/esm/{utils/fillClassification.js → math/fills.js} +26 -2
- package/dist/esm/math/fills.js.map +1 -0
- package/dist/esm/{utils/calculations.d.ts → math/order.d.ts} +70 -75
- package/dist/esm/math/order.d.ts.map +1 -0
- package/dist/esm/{utils/calculations.js → math/order.js} +155 -111
- package/dist/esm/math/order.js.map +1 -0
- package/dist/esm/math/position.d.ts +211 -0
- package/dist/esm/math/position.d.ts.map +1 -0
- package/dist/esm/math/position.js +299 -0
- package/dist/esm/math/position.js.map +1 -0
- package/dist/esm/services/resolveQuote.d.ts.map +1 -1
- package/dist/esm/services/resolveQuote.js +1 -1
- package/dist/esm/services/resolveQuote.js.map +1 -1
- package/dist/esm/services/resolveSubscribeQuote.d.ts.map +1 -1
- package/dist/esm/services/resolveSubscribeQuote.js +1 -1
- package/dist/esm/services/resolveSubscribeQuote.js.map +1 -1
- package/dist/esm/types/provider.d.ts +23 -11
- package/dist/esm/types/provider.d.ts.map +1 -1
- package/dist/esm/types/withdrawal.d.ts +17 -5
- package/dist/esm/types/withdrawal.d.ts.map +1 -1
- package/dist/esm/utils/orderClassification.d.ts +1 -14
- package/dist/esm/utils/orderClassification.d.ts.map +1 -1
- package/dist/esm/utils/orderClassification.js +1 -25
- package/dist/esm/utils/orderClassification.js.map +1 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esm/wire/orderAmounts.d.ts +55 -0
- package/dist/esm/wire/orderAmounts.d.ts.map +1 -0
- package/dist/esm/wire/orderAmounts.js +114 -0
- package/dist/esm/wire/orderAmounts.js.map +1 -0
- package/dist/esm/wire/refuel.d.ts +28 -0
- package/dist/esm/wire/refuel.d.ts.map +1 -0
- package/dist/esm/wire/refuel.js +36 -0
- package/dist/esm/wire/refuel.js.map +1 -0
- package/dist/esm/wire/requireDecimal.d.ts +11 -0
- package/dist/esm/wire/requireDecimal.d.ts.map +1 -0
- package/dist/esm/wire/requireDecimal.js +17 -0
- package/dist/esm/wire/requireDecimal.js.map +1 -0
- package/dist/esm/wire/snap.d.ts +24 -0
- package/dist/esm/wire/snap.d.ts.map +1 -0
- package/dist/esm/wire/snap.js +27 -0
- package/dist/esm/wire/snap.js.map +1 -0
- package/dist/esm/wire/transferable.d.ts +15 -0
- package/dist/esm/wire/transferable.d.ts.map +1 -0
- package/dist/esm/wire/transferable.js +22 -0
- package/dist/esm/wire/transferable.js.map +1 -0
- package/dist/esm/wire/withdraw.d.ts +14 -0
- package/dist/esm/wire/withdraw.d.ts.map +1 -0
- package/dist/esm/wire/withdraw.js +20 -0
- package/dist/esm/wire/withdraw.js.map +1 -0
- package/dist/types/client/PerpsClient.d.ts.map +1 -1
- package/dist/types/{utils/decimal.d.ts → decimal/big.d.ts} +1 -1
- package/dist/types/decimal/big.d.ts.map +1 -0
- package/dist/types/decimal/convert.d.ts +80 -0
- package/dist/types/decimal/convert.d.ts.map +1 -0
- package/dist/types/decimal/format.d.ts.map +1 -0
- package/dist/types/decimal/parse.d.ts +29 -0
- package/dist/types/decimal/parse.d.ts.map +1 -0
- package/dist/types/index.d.ts +17 -15
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/math/fills.d.ts +26 -0
- package/dist/types/math/fills.d.ts.map +1 -0
- package/dist/types/{utils/calculations.d.ts → math/order.d.ts} +70 -75
- package/dist/types/math/order.d.ts.map +1 -0
- package/dist/types/math/position.d.ts +211 -0
- package/dist/types/math/position.d.ts.map +1 -0
- package/dist/types/services/resolveQuote.d.ts.map +1 -1
- package/dist/types/services/resolveSubscribeQuote.d.ts.map +1 -1
- package/dist/types/types/provider.d.ts +23 -11
- package/dist/types/types/provider.d.ts.map +1 -1
- package/dist/types/types/withdrawal.d.ts +17 -5
- package/dist/types/types/withdrawal.d.ts.map +1 -1
- package/dist/types/utils/orderClassification.d.ts +1 -14
- package/dist/types/utils/orderClassification.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/dist/types/wire/orderAmounts.d.ts +55 -0
- package/dist/types/wire/orderAmounts.d.ts.map +1 -0
- package/dist/types/wire/refuel.d.ts +28 -0
- package/dist/types/wire/refuel.d.ts.map +1 -0
- package/dist/types/wire/requireDecimal.d.ts +11 -0
- package/dist/types/wire/requireDecimal.d.ts.map +1 -0
- package/dist/types/wire/snap.d.ts +24 -0
- package/dist/types/wire/snap.d.ts.map +1 -0
- package/dist/types/wire/transferable.d.ts +15 -0
- package/dist/types/wire/transferable.d.ts.map +1 -0
- package/dist/types/wire/withdraw.d.ts +14 -0
- package/dist/types/wire/withdraw.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/client/PerpsClient.ts +4 -1
- package/src/decimal/convert.ts +164 -0
- package/src/{utils → decimal}/parse.ts +13 -11
- package/src/index.ts +80 -57
- package/src/{utils/fillClassification.ts → math/fills.ts} +30 -1
- package/src/{utils/calculations.ts → math/order.ts} +205 -127
- package/src/{utils/positionMath.ts → math/position.ts} +173 -21
- package/src/services/resolveQuote.ts +1 -1
- package/src/services/resolveSubscribeQuote.ts +1 -1
- package/src/types/provider.ts +23 -10
- package/src/types/withdrawal.ts +22 -5
- package/src/utils/orderClassification.ts +0 -30
- package/src/version.ts +1 -1
- package/src/wire/orderAmounts.ts +172 -0
- package/src/wire/refuel.ts +51 -0
- package/src/wire/requireDecimal.ts +24 -0
- package/src/wire/snap.ts +38 -0
- package/src/wire/transferable.ts +26 -0
- package/src/wire/withdraw.ts +29 -0
- package/dist/cjs/utils/calculations.d.ts +0 -47
- package/dist/cjs/utils/calculations.d.ts.map +0 -1
- package/dist/cjs/utils/calculations.js +0 -214
- package/dist/cjs/utils/calculations.js.map +0 -1
- package/dist/cjs/utils/decimal.d.ts.map +0 -1
- package/dist/cjs/utils/decimal.js.map +0 -1
- package/dist/cjs/utils/fillClassification.d.ts +0 -3
- package/dist/cjs/utils/fillClassification.d.ts.map +0 -1
- package/dist/cjs/utils/fillClassification.js.map +0 -1
- package/dist/cjs/utils/format.d.ts.map +0 -1
- package/dist/cjs/utils/format.js.map +0 -1
- package/dist/cjs/utils/math.d.ts +0 -4
- package/dist/cjs/utils/math.d.ts.map +0 -1
- package/dist/cjs/utils/math.js +0 -8
- package/dist/cjs/utils/math.js.map +0 -1
- package/dist/cjs/utils/orderEntry.d.ts +0 -6
- package/dist/cjs/utils/orderEntry.d.ts.map +0 -1
- package/dist/cjs/utils/orderEntry.js +0 -20
- package/dist/cjs/utils/orderEntry.js.map +0 -1
- package/dist/cjs/utils/orderMath.d.ts +0 -6
- package/dist/cjs/utils/orderMath.d.ts.map +0 -1
- package/dist/cjs/utils/orderMath.js +0 -85
- package/dist/cjs/utils/orderMath.js.map +0 -1
- package/dist/cjs/utils/parse.d.ts +0 -3
- package/dist/cjs/utils/parse.d.ts.map +0 -1
- package/dist/cjs/utils/parse.js.map +0 -1
- package/dist/cjs/utils/positionMath.d.ts +0 -37
- package/dist/cjs/utils/positionMath.d.ts.map +0 -1
- package/dist/cjs/utils/positionMath.js +0 -99
- package/dist/cjs/utils/positionMath.js.map +0 -1
- package/dist/cjs/utils/scaleToInteger.d.ts +0 -3
- package/dist/cjs/utils/scaleToInteger.d.ts.map +0 -1
- package/dist/cjs/utils/scaleToInteger.js +0 -30
- package/dist/cjs/utils/scaleToInteger.js.map +0 -1
- package/dist/cjs/utils/units.d.ts +0 -3
- package/dist/cjs/utils/units.d.ts.map +0 -1
- package/dist/cjs/utils/units.js +0 -18
- package/dist/cjs/utils/units.js.map +0 -1
- package/dist/cjs/utils/validation.d.ts +0 -2
- package/dist/cjs/utils/validation.d.ts.map +0 -1
- package/dist/cjs/utils/validation.js +0 -16
- package/dist/cjs/utils/validation.js.map +0 -1
- package/dist/esm/utils/calculations.d.ts.map +0 -1
- package/dist/esm/utils/calculations.js.map +0 -1
- package/dist/esm/utils/decimal.d.ts.map +0 -1
- package/dist/esm/utils/decimal.js.map +0 -1
- package/dist/esm/utils/fillClassification.d.ts +0 -13
- package/dist/esm/utils/fillClassification.d.ts.map +0 -1
- package/dist/esm/utils/fillClassification.js.map +0 -1
- package/dist/esm/utils/format.d.ts.map +0 -1
- package/dist/esm/utils/format.js.map +0 -1
- package/dist/esm/utils/math.d.ts +0 -6
- package/dist/esm/utils/math.d.ts.map +0 -1
- package/dist/esm/utils/math.js +0 -5
- package/dist/esm/utils/math.js.map +0 -1
- package/dist/esm/utils/orderEntry.d.ts +0 -26
- package/dist/esm/utils/orderEntry.d.ts.map +0 -1
- package/dist/esm/utils/orderEntry.js +0 -34
- package/dist/esm/utils/orderEntry.js.map +0 -1
- package/dist/esm/utils/orderMath.d.ts +0 -37
- package/dist/esm/utils/orderMath.d.ts.map +0 -1
- package/dist/esm/utils/orderMath.js +0 -113
- package/dist/esm/utils/orderMath.js.map +0 -1
- package/dist/esm/utils/parse.d.ts +0 -28
- package/dist/esm/utils/parse.d.ts.map +0 -1
- package/dist/esm/utils/parse.js.map +0 -1
- package/dist/esm/utils/positionMath.d.ts +0 -120
- package/dist/esm/utils/positionMath.d.ts.map +0 -1
- package/dist/esm/utils/positionMath.js +0 -173
- package/dist/esm/utils/positionMath.js.map +0 -1
- package/dist/esm/utils/scaleToInteger.d.ts +0 -22
- package/dist/esm/utils/scaleToInteger.d.ts.map +0 -1
- package/dist/esm/utils/scaleToInteger.js +0 -34
- package/dist/esm/utils/scaleToInteger.js.map +0 -1
- package/dist/esm/utils/units.d.ts +0 -27
- package/dist/esm/utils/units.d.ts.map +0 -1
- package/dist/esm/utils/units.js +0 -38
- package/dist/esm/utils/units.js.map +0 -1
- package/dist/esm/utils/validation.d.ts +0 -18
- package/dist/esm/utils/validation.d.ts.map +0 -1
- package/dist/esm/utils/validation.js +0 -29
- package/dist/esm/utils/validation.js.map +0 -1
- package/dist/types/utils/calculations.d.ts.map +0 -1
- package/dist/types/utils/decimal.d.ts.map +0 -1
- package/dist/types/utils/fillClassification.d.ts +0 -13
- package/dist/types/utils/fillClassification.d.ts.map +0 -1
- package/dist/types/utils/format.d.ts.map +0 -1
- package/dist/types/utils/math.d.ts +0 -6
- package/dist/types/utils/math.d.ts.map +0 -1
- package/dist/types/utils/orderEntry.d.ts +0 -26
- package/dist/types/utils/orderEntry.d.ts.map +0 -1
- package/dist/types/utils/orderMath.d.ts +0 -37
- package/dist/types/utils/orderMath.d.ts.map +0 -1
- package/dist/types/utils/parse.d.ts +0 -28
- package/dist/types/utils/parse.d.ts.map +0 -1
- package/dist/types/utils/positionMath.d.ts +0 -120
- package/dist/types/utils/positionMath.d.ts.map +0 -1
- package/dist/types/utils/scaleToInteger.d.ts +0 -22
- package/dist/types/utils/scaleToInteger.d.ts.map +0 -1
- package/dist/types/utils/units.d.ts +0 -27
- package/dist/types/utils/units.d.ts.map +0 -1
- package/dist/types/utils/validation.d.ts +0 -18
- package/dist/types/utils/validation.d.ts.map +0 -1
- package/src/utils/math.ts +0 -7
- package/src/utils/orderEntry.ts +0 -38
- package/src/utils/orderMath.ts +0 -152
- package/src/utils/scaleToInteger.ts +0 -56
- package/src/utils/units.ts +0 -39
- package/src/utils/validation.ts +0 -38
- /package/dist/cjs/{utils → decimal}/format.d.ts +0 -0
- /package/dist/cjs/{utils → decimal}/format.js +0 -0
- /package/dist/esm/{utils → decimal}/format.d.ts +0 -0
- /package/dist/esm/{utils → decimal}/format.js +0 -0
- /package/dist/types/{utils → decimal}/format.d.ts +0 -0
- /package/src/{utils/decimal.ts → decimal/big.ts} +0 -0
- /package/src/{utils → decimal}/format.ts +0 -0
|
@@ -1,24 +1,151 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Display-tier position formulas. Every function takes and gives `number`;
|
|
3
|
+
* exact decimal arithmetic happens internally with `DivBig`.
|
|
4
4
|
*
|
|
5
|
-
* Sign convention: long = +1, short = -1. Sizes passed to
|
|
6
|
-
* always non-negative magnitudes; direction is carried by
|
|
5
|
+
* Sign convention: long = +1, short = -1. Sizes passed to the `estimate*`
|
|
6
|
+
* helpers are always non-negative magnitudes; direction is carried by
|
|
7
|
+
* `isLong`.
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
|
-
import { areFinite, DivBig } from '
|
|
10
|
+
import { areFinite, DivBig } from '../decimal/big.js'
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Direction sign for a position.
|
|
13
14
|
*
|
|
14
|
-
* @
|
|
15
|
-
* @returns +1 for long, -1 for short.
|
|
16
|
-
* @public
|
|
15
|
+
* @deprecated Inline `isLong ? 1 : -1`. Removed in the next major.
|
|
17
16
|
*/
|
|
18
17
|
export function directionSign(isLong: boolean): 1 | -1 {
|
|
19
18
|
return isLong ? 1 : -1
|
|
20
19
|
}
|
|
21
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Calculate notional value of a position.
|
|
23
|
+
*
|
|
24
|
+
* @param size - Position size in asset units
|
|
25
|
+
* @param price - Current asset price
|
|
26
|
+
* @returns Notional value in USD
|
|
27
|
+
* @public
|
|
28
|
+
*/
|
|
29
|
+
export function calculateNotionalValue(size: number, price: number): number {
|
|
30
|
+
if (!areFinite(size, price)) {
|
|
31
|
+
return Number.NaN
|
|
32
|
+
}
|
|
33
|
+
return new DivBig(size).abs().times(price).toNumber()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Calculate unrealized PnL.
|
|
38
|
+
*
|
|
39
|
+
* @param entryPrice - Position entry price
|
|
40
|
+
* @param currentPrice - Current market price
|
|
41
|
+
* @param size - Position size (positive for long, negative for short)
|
|
42
|
+
* @returns Unrealized PnL in USD
|
|
43
|
+
* @public
|
|
44
|
+
*/
|
|
45
|
+
export function calculateUnrealizedPnl(
|
|
46
|
+
entryPrice: number,
|
|
47
|
+
currentPrice: number,
|
|
48
|
+
size: number
|
|
49
|
+
): number {
|
|
50
|
+
if (!areFinite(entryPrice, currentPrice, size)) {
|
|
51
|
+
return Number.NaN
|
|
52
|
+
}
|
|
53
|
+
return new DivBig(currentPrice).minus(entryPrice).times(size).toNumber()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Calculate return on equity (ROE) percentage.
|
|
58
|
+
*
|
|
59
|
+
* @param pnl - Profit/loss in USD
|
|
60
|
+
* @param margin - Initial margin in USD
|
|
61
|
+
* @returns ROE as percentage (e.g., 10 for 10%)
|
|
62
|
+
* @public
|
|
63
|
+
*/
|
|
64
|
+
export function calculateRoe(pnl: number, margin: number): number {
|
|
65
|
+
if (margin === 0) {
|
|
66
|
+
return 0
|
|
67
|
+
}
|
|
68
|
+
if (!areFinite(pnl, margin)) {
|
|
69
|
+
return Number.NaN
|
|
70
|
+
}
|
|
71
|
+
return new DivBig(pnl).div(margin).times(100).toNumber()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Calculate required margin for a position.
|
|
76
|
+
*
|
|
77
|
+
* @param notionalValue - Position notional value in USD
|
|
78
|
+
* @param leverage - Position leverage
|
|
79
|
+
* @returns Required margin in USD
|
|
80
|
+
* @public
|
|
81
|
+
*/
|
|
82
|
+
export function calculateRequiredMargin(
|
|
83
|
+
notionalValue: number,
|
|
84
|
+
leverage: number
|
|
85
|
+
): number {
|
|
86
|
+
if (leverage === 0) {
|
|
87
|
+
return notionalValue / leverage
|
|
88
|
+
}
|
|
89
|
+
if (!areFinite(notionalValue, leverage)) {
|
|
90
|
+
return Number.NaN
|
|
91
|
+
}
|
|
92
|
+
return new DivBig(notionalValue).div(leverage).toNumber()
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Distance from the current price to the liquidation price, as a percentage of
|
|
97
|
+
* the current price.
|
|
98
|
+
*
|
|
99
|
+
* @param liquidationPrice - The position's liquidation price
|
|
100
|
+
* @param currentPrice - Current market price
|
|
101
|
+
* @returns Absolute distance as a percentage, or 0 when current price is zero
|
|
102
|
+
* @public
|
|
103
|
+
*/
|
|
104
|
+
export function calculateLiquidationDistance(params: {
|
|
105
|
+
liquidationPrice: number
|
|
106
|
+
currentPrice: number
|
|
107
|
+
}): number {
|
|
108
|
+
const { liquidationPrice, currentPrice } = params
|
|
109
|
+
if (currentPrice === 0) {
|
|
110
|
+
return 0
|
|
111
|
+
}
|
|
112
|
+
return Math.abs((liquidationPrice - currentPrice) / currentPrice) * 100
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* @deprecated Use `calculateLiquidationDistance`. Removed in the next major.
|
|
117
|
+
*/
|
|
118
|
+
export const liquidationDistancePercent = calculateLiquidationDistance
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Effective leverage of an open position.
|
|
122
|
+
*
|
|
123
|
+
* leverage = positionValueUsd / marginUsd
|
|
124
|
+
*
|
|
125
|
+
* @param positionValueUsd - Position notional value in USD
|
|
126
|
+
* @param marginUsd - Margin backing the position in USD
|
|
127
|
+
* @returns Effective leverage, or 0 when margin is zero
|
|
128
|
+
* @public
|
|
129
|
+
*/
|
|
130
|
+
export function calculateEffectiveLeverage(params: {
|
|
131
|
+
positionValueUsd: number
|
|
132
|
+
marginUsd: number
|
|
133
|
+
}): number {
|
|
134
|
+
const { positionValueUsd, marginUsd } = params
|
|
135
|
+
if (marginUsd === 0) {
|
|
136
|
+
return 0
|
|
137
|
+
}
|
|
138
|
+
if (!areFinite(positionValueUsd, marginUsd)) {
|
|
139
|
+
return Number.NaN
|
|
140
|
+
}
|
|
141
|
+
return new DivBig(positionValueUsd).div(marginUsd).toNumber()
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* @deprecated Use `calculateEffectiveLeverage`. Removed in the next major.
|
|
146
|
+
*/
|
|
147
|
+
export const effectiveLeverage = calculateEffectiveLeverage
|
|
148
|
+
|
|
22
149
|
/**
|
|
23
150
|
* Estimated liquidation price for an isolated-margin position, parameterised
|
|
24
151
|
* by the venue's maintenance margin rate.
|
|
@@ -37,7 +164,7 @@ export function directionSign(isLong: boolean): 1 | -1 {
|
|
|
37
164
|
* produce one (zero leverage, degenerate denominator).
|
|
38
165
|
* @public
|
|
39
166
|
*/
|
|
40
|
-
export function
|
|
167
|
+
export function estimateLiquidationPrice(params: {
|
|
41
168
|
entryPrice: number
|
|
42
169
|
leverage: number
|
|
43
170
|
isLong: boolean
|
|
@@ -47,7 +174,7 @@ export function estimateIsolatedLiquidationPrice(params: {
|
|
|
47
174
|
if (leverage === 0) {
|
|
48
175
|
return undefined
|
|
49
176
|
}
|
|
50
|
-
const side =
|
|
177
|
+
const side = isLong ? 1 : -1
|
|
51
178
|
const denominator = 1 - maintenanceMarginRate * side
|
|
52
179
|
if (denominator === 0) {
|
|
53
180
|
return undefined
|
|
@@ -65,6 +192,11 @@ export function estimateIsolatedLiquidationPrice(params: {
|
|
|
65
192
|
.toNumber()
|
|
66
193
|
}
|
|
67
194
|
|
|
195
|
+
/**
|
|
196
|
+
* @deprecated Use `estimateLiquidationPrice`. Removed in the next major.
|
|
197
|
+
*/
|
|
198
|
+
export const estimateIsolatedLiquidationPrice = estimateLiquidationPrice
|
|
199
|
+
|
|
68
200
|
/**
|
|
69
201
|
* Whether an isolated position with this liquidation price is already past
|
|
70
202
|
* liquidation at `currentPrice`: a long liquidates when the price falls to its
|
|
@@ -88,7 +220,7 @@ export function wouldImmediatelyLiquidate(params: {
|
|
|
88
220
|
}
|
|
89
221
|
|
|
90
222
|
/**
|
|
91
|
-
*
|
|
223
|
+
* Estimated average entry price after adding to an existing position.
|
|
92
224
|
*
|
|
93
225
|
* Weighted average of the current entry and the new fill price, weighted by
|
|
94
226
|
* the size of each leg in coin units. Both legs assumed in the same direction
|
|
@@ -103,7 +235,7 @@ export function wouldImmediatelyLiquidate(params: {
|
|
|
103
235
|
* cannot produce a valid average (zero combined size, non-finite values).
|
|
104
236
|
* @public
|
|
105
237
|
*/
|
|
106
|
-
export function
|
|
238
|
+
export function estimateAverageEntryPrice(params: {
|
|
107
239
|
currentSize: number
|
|
108
240
|
currentEntry: number
|
|
109
241
|
addSize: number
|
|
@@ -128,7 +260,12 @@ export function predictAverageEntryPrice(params: {
|
|
|
128
260
|
}
|
|
129
261
|
|
|
130
262
|
/**
|
|
131
|
-
*
|
|
263
|
+
* @deprecated Use `estimateAverageEntryPrice`. Removed in the next major.
|
|
264
|
+
*/
|
|
265
|
+
export const predictAverageEntryPrice = estimateAverageEntryPrice
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Estimated effective leverage after adding margin and notional.
|
|
132
269
|
*
|
|
133
270
|
* leverage = totalNotional / totalMargin. The caller computes notional from
|
|
134
271
|
* size and price (`calculateNotionalValue`) and supplies the additional
|
|
@@ -138,7 +275,7 @@ export function predictAverageEntryPrice(params: {
|
|
|
138
275
|
* non-positive.
|
|
139
276
|
* @public
|
|
140
277
|
*/
|
|
141
|
-
export function
|
|
278
|
+
export function estimateNewLeverage(params: {
|
|
142
279
|
currentNotional: number
|
|
143
280
|
currentMargin: number
|
|
144
281
|
addNotional: number
|
|
@@ -159,14 +296,19 @@ export function predictNewLeverage(params: {
|
|
|
159
296
|
}
|
|
160
297
|
|
|
161
298
|
/**
|
|
162
|
-
*
|
|
299
|
+
* @deprecated Use `estimateNewLeverage`. Removed in the next major.
|
|
300
|
+
*/
|
|
301
|
+
export const predictNewLeverage = estimateNewLeverage
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Estimated unrealised PnL at the current mark price.
|
|
163
305
|
*
|
|
164
|
-
* `pnl = (markPrice - entryPrice) * size *
|
|
306
|
+
* `pnl = (markPrice - entryPrice) * size * (isLong ? 1 : -1)`
|
|
165
307
|
*
|
|
166
308
|
* @param size - Position size as a non-negative magnitude.
|
|
167
309
|
* @public
|
|
168
310
|
*/
|
|
169
|
-
export function
|
|
311
|
+
export function estimateUnrealizedPnl(params: {
|
|
170
312
|
entryPrice: number
|
|
171
313
|
markPrice: number
|
|
172
314
|
size: number
|
|
@@ -179,19 +321,24 @@ export function predictUnrealizedPnl(params: {
|
|
|
179
321
|
return new DivBig(markPrice)
|
|
180
322
|
.minus(entryPrice)
|
|
181
323
|
.times(size)
|
|
182
|
-
.times(
|
|
324
|
+
.times(isLong ? 1 : -1)
|
|
183
325
|
.toNumber()
|
|
184
326
|
}
|
|
185
327
|
|
|
328
|
+
/**
|
|
329
|
+
* @deprecated Use `estimateUnrealizedPnl`. Removed in the next major.
|
|
330
|
+
*/
|
|
331
|
+
export const predictUnrealizedPnl = estimateUnrealizedPnl
|
|
332
|
+
|
|
186
333
|
/**
|
|
187
334
|
* Realised PnL on the portion of a position being closed.
|
|
188
335
|
*
|
|
189
|
-
* `rPnl = (closePrice - entryPrice) * closeSize *
|
|
336
|
+
* `rPnl = (closePrice - entryPrice) * closeSize * (isLong ? 1 : -1)`
|
|
190
337
|
*
|
|
191
338
|
* @param closeSize - Size being closed as a non-negative magnitude.
|
|
192
339
|
* @public
|
|
193
340
|
*/
|
|
194
|
-
export function
|
|
341
|
+
export function calculateRealizedPnl(params: {
|
|
195
342
|
entryPrice: number
|
|
196
343
|
closePrice: number
|
|
197
344
|
closeSize: number
|
|
@@ -204,6 +351,11 @@ export function realizedPnlOnClose(params: {
|
|
|
204
351
|
return new DivBig(closePrice)
|
|
205
352
|
.minus(entryPrice)
|
|
206
353
|
.times(closeSize)
|
|
207
|
-
.times(
|
|
354
|
+
.times(isLong ? 1 : -1)
|
|
208
355
|
.toNumber()
|
|
209
356
|
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* @deprecated Use `calculateRealizedPnl`. Removed in the next major.
|
|
360
|
+
*/
|
|
361
|
+
export const realizedPnlOnClose = calculateRealizedPnl
|
|
@@ -6,12 +6,12 @@ import {
|
|
|
6
6
|
type Quote,
|
|
7
7
|
} from '@lifi/perps-types'
|
|
8
8
|
import { PerpsError } from '../errors/PerpsError.js'
|
|
9
|
+
import { buildQuote } from '../math/order.js'
|
|
9
10
|
import type { SDKRequestOptions } from '../types/config.js'
|
|
10
11
|
import type {
|
|
11
12
|
PerpsSDKClient,
|
|
12
13
|
ProviderGetQuoteParams,
|
|
13
14
|
} from '../types/provider.js'
|
|
14
|
-
import { buildQuote } from '../utils/calculations.js'
|
|
15
15
|
import { getMarkets } from './getMarkets.js'
|
|
16
16
|
import { getMarketsContext } from './getMarketsContext.js'
|
|
17
17
|
import { getOrderbook } from './getOrderbook.js'
|
|
@@ -3,12 +3,12 @@ import type {
|
|
|
3
3
|
MarketContext,
|
|
4
4
|
OrderbookResponse,
|
|
5
5
|
} from '@lifi/perps-types'
|
|
6
|
+
import { buildQuote } from '../math/order.js'
|
|
6
7
|
import type {
|
|
7
8
|
PerpsSDKClient,
|
|
8
9
|
ProviderGetQuoteParams,
|
|
9
10
|
QuoteListener,
|
|
10
11
|
} from '../types/provider.js'
|
|
11
|
-
import { buildQuote } from '../utils/calculations.js'
|
|
12
12
|
import type { WsProvider } from '../websocket/types.js'
|
|
13
13
|
import { resolveQuoteMarket, resolveQuotePrice } from './resolveQuote.js'
|
|
14
14
|
|
package/src/types/provider.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
ActivitiesResponse,
|
|
10
10
|
ActivityType,
|
|
11
11
|
AvailableToTrade,
|
|
12
|
+
DecimalString,
|
|
12
13
|
FillsResponse,
|
|
13
14
|
Market,
|
|
14
15
|
MarketRef,
|
|
@@ -534,29 +535,37 @@ export interface PerpsProviderPlugin {
|
|
|
534
535
|
): AccountSummary
|
|
535
536
|
|
|
536
537
|
/**
|
|
537
|
-
*
|
|
538
|
-
* the canonical, provider-correct
|
|
539
|
-
* differ per provider, so provider-agnostic consumers must route
|
|
540
|
-
* order price through the market's own provider instead of applying
|
|
541
|
-
* venue's rules to another's markets. Pure — does no I/O.
|
|
538
|
+
* Snap an order price onto the venue's tick grid for `market`, rounding
|
|
539
|
+
* half-up. This is the canonical, provider-correct price surface — venue
|
|
540
|
+
* tick rules differ per provider, so provider-agnostic consumers must route
|
|
541
|
+
* every order price through the market's own provider instead of applying
|
|
542
|
+
* one venue's rules to another's markets. Pure — does no I/O.
|
|
543
|
+
*
|
|
544
|
+
* Takes and gives a {@link DecimalString}. Never pass a `number`: above 15
|
|
545
|
+
* significant digits the value has already lost digits by the time it
|
|
546
|
+
* arrives.
|
|
542
547
|
*
|
|
543
548
|
* @returns The price as a wire-ready decimal string, trailing zeros
|
|
544
549
|
* stripped.
|
|
545
550
|
* @throws {PerpsError} `ValidationError` when `market` lacks the tick
|
|
546
551
|
* metadata the venue's rules need (e.g. `Market.priceDecimals` absent).
|
|
547
552
|
*/
|
|
548
|
-
|
|
553
|
+
snapOrderPrice(market: Market, price: DecimalString): DecimalString
|
|
549
554
|
|
|
550
555
|
/**
|
|
551
|
-
*
|
|
552
|
-
* (never
|
|
553
|
-
* size or available balance. Pure — does no I/O.
|
|
556
|
+
* Snap an order size onto the venue's lot grid for `market`, truncating
|
|
557
|
+
* toward zero (never rounding up) so the snapped size cannot exceed the
|
|
558
|
+
* user's intended size or available balance. Pure — does no I/O.
|
|
559
|
+
*
|
|
560
|
+
* Takes and gives a {@link DecimalString}. Never pass a `number`: above 15
|
|
561
|
+
* significant digits the value has already lost digits by the time it
|
|
562
|
+
* arrives.
|
|
554
563
|
*
|
|
555
564
|
* @param size - Size in base-asset units as a non-negative magnitude.
|
|
556
565
|
* @returns The size as a wire-ready decimal string, trailing zeros
|
|
557
566
|
* stripped.
|
|
558
567
|
*/
|
|
559
|
-
|
|
568
|
+
snapOrderSize(market: Market, size: DecimalString): DecimalString
|
|
560
569
|
|
|
561
570
|
/**
|
|
562
571
|
* Estimate the liquidation price of a new isolated position on `market`
|
|
@@ -564,6 +573,10 @@ export interface PerpsProviderPlugin {
|
|
|
564
573
|
* positions, prefer `Position.liquidationPrice` from the venue. Pure —
|
|
565
574
|
* does no I/O.
|
|
566
575
|
*
|
|
576
|
+
* Numbers, in and out, on purpose: this is a display-tier estimate that
|
|
577
|
+
* feeds a screen, not a wire amount. It is not a `snap*` method and must
|
|
578
|
+
* not be converted to {@link DecimalString}.
|
|
579
|
+
*
|
|
567
580
|
* @returns The estimated liquidation price, or `undefined` when the venue's
|
|
568
581
|
* model cannot be evaluated client-side (degenerate inputs, or `market`
|
|
569
582
|
* lacks the margin metadata the model needs).
|
package/src/types/withdrawal.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
ActionType,
|
|
3
|
+
Asset,
|
|
4
|
+
DecimalString,
|
|
5
|
+
WithdrawalRoute,
|
|
6
|
+
} from '@lifi/perps-types'
|
|
2
7
|
import type { Address } from 'viem'
|
|
3
8
|
|
|
4
9
|
export type { WithdrawalRoute }
|
|
@@ -14,13 +19,19 @@ export interface ProviderWithdrawableBalance {
|
|
|
14
19
|
assetId: string
|
|
15
20
|
route: WithdrawalRoute
|
|
16
21
|
/** Withdrawable amount in the asset's own units. Always greater than zero. */
|
|
17
|
-
available:
|
|
22
|
+
available: DecimalString
|
|
23
|
+
/**
|
|
24
|
+
* Largest `amount` the row can fund: `available` when the fee is deducted
|
|
25
|
+
* from the amount or absent; `available − withdrawalFee` floored at zero
|
|
26
|
+
* when the venue charges the fee on top (`isFeeDeducted === false`).
|
|
27
|
+
*/
|
|
28
|
+
max: DecimalString
|
|
18
29
|
/**
|
|
19
30
|
* Flat venue fee on a withdrawal from this row, in the asset's own units.
|
|
20
31
|
* Absent when the venue publishes no fee for the asset. The client rejects
|
|
21
32
|
* a value that is not a non-negative decimal.
|
|
22
33
|
*/
|
|
23
|
-
withdrawalFee?:
|
|
34
|
+
withdrawalFee?: DecimalString
|
|
24
35
|
/**
|
|
25
36
|
* `true` when the venue takes `withdrawalFee` out of the requested amount,
|
|
26
37
|
* `false` when it charges the fee in addition. Set together with
|
|
@@ -40,7 +51,13 @@ export interface WithdrawableBalance {
|
|
|
40
51
|
asset: Asset
|
|
41
52
|
route: WithdrawalRoute
|
|
42
53
|
/** Withdrawable amount in the asset's own units. */
|
|
43
|
-
available:
|
|
54
|
+
available: DecimalString
|
|
55
|
+
/**
|
|
56
|
+
* Largest `amount` the row can fund: `available` when the fee is deducted
|
|
57
|
+
* from the amount or absent; `available − withdrawalFee` floored at zero
|
|
58
|
+
* when the venue charges the fee on top (`isFeeDeducted === false`).
|
|
59
|
+
*/
|
|
60
|
+
max: DecimalString
|
|
44
61
|
/**
|
|
45
62
|
* Flat venue fee on a withdrawal from this row, in the asset's own units.
|
|
46
63
|
* Absent when the venue publishes no fee for the asset. With
|
|
@@ -51,7 +68,7 @@ export interface WithdrawableBalance {
|
|
|
51
68
|
* is zero or negative when the fee is at or above `available`, and the row
|
|
52
69
|
* then funds no withdrawal.
|
|
53
70
|
*/
|
|
54
|
-
withdrawalFee?:
|
|
71
|
+
withdrawalFee?: DecimalString
|
|
55
72
|
/**
|
|
56
73
|
* Present only together with `withdrawalFee`. Absent on a row from a
|
|
57
74
|
* provider plugin that does not report it; absence means unknown, not
|
|
@@ -5,20 +5,11 @@ import type {
|
|
|
5
5
|
TwapOrder,
|
|
6
6
|
} from '@lifi/perps-types'
|
|
7
7
|
import {
|
|
8
|
-
FillClassification,
|
|
9
8
|
OrderSide,
|
|
10
9
|
OrderStatus,
|
|
11
10
|
OrderType,
|
|
12
11
|
TriggerCondition,
|
|
13
12
|
} from '@lifi/perps-types'
|
|
14
|
-
import { stringToFloat } from './parse.js'
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Re-exported fill taxonomy used by {@link classifyFillFromPosition}.
|
|
18
|
-
*
|
|
19
|
-
* @public
|
|
20
|
-
*/
|
|
21
|
-
export { FillClassification }
|
|
22
13
|
|
|
23
14
|
const TP_TYPES = new Set<OrderType>([
|
|
24
15
|
OrderType.TAKE_PROFIT_MARKET,
|
|
@@ -97,24 +88,3 @@ export const ACTIVE_ORDER_STATUSES: ReadonlySet<OrderStatus> = new Set([
|
|
|
97
88
|
export function isActiveOrderStatus(status: OrderStatus): boolean {
|
|
98
89
|
return ACTIVE_ORDER_STATUSES.has(status)
|
|
99
90
|
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Classify a fill as open or close based on realizedPnl.
|
|
103
|
-
* @deprecated Use `Fill.classification` instead — it uses startPosition
|
|
104
|
-
* for accurate open/increase/reduce/close/reverse classification.
|
|
105
|
-
* @public
|
|
106
|
-
*/
|
|
107
|
-
export function classifyFill(
|
|
108
|
-
side: OrderSide,
|
|
109
|
-
realizedPnl: string | null | undefined
|
|
110
|
-
): FillClassification {
|
|
111
|
-
const isClose = realizedPnl != null && stringToFloat(realizedPnl) !== 0
|
|
112
|
-
if (side === OrderSide.BUY) {
|
|
113
|
-
return isClose
|
|
114
|
-
? FillClassification.CLOSED_SHORT
|
|
115
|
-
: FillClassification.OPENED_LONG
|
|
116
|
-
}
|
|
117
|
-
return isClose
|
|
118
|
-
? FillClassification.CLOSED_LONG
|
|
119
|
-
: FillClassification.OPENED_SHORT
|
|
120
|
-
}
|
package/src/version.ts
CHANGED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type DecimalString,
|
|
3
|
+
isDecimalString,
|
|
4
|
+
type Market,
|
|
5
|
+
PerpsErrorCode,
|
|
6
|
+
} from '@lifi/perps-types'
|
|
7
|
+
import Big from 'big.js'
|
|
8
|
+
import { TruncBig } from '../decimal/big.js'
|
|
9
|
+
import { PerpsError } from '../errors/PerpsError.js'
|
|
10
|
+
import type { PerpsSDKClient } from '../types/provider.js'
|
|
11
|
+
import { snapOrderSize } from './snap.js'
|
|
12
|
+
|
|
13
|
+
/** @public */
|
|
14
|
+
export interface OrderAmountsInput {
|
|
15
|
+
sdk: PerpsSDKClient
|
|
16
|
+
market: Market
|
|
17
|
+
/** The field the user typed; the other two are calculated from it. */
|
|
18
|
+
held: 'margin' | 'size' | 'notional'
|
|
19
|
+
amount: DecimalString
|
|
20
|
+
leverage: number
|
|
21
|
+
price: DecimalString
|
|
22
|
+
/** Decimals for the quote-asset amounts (margin, notional). Default 2. */
|
|
23
|
+
quoteDecimals?: number
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** @public */
|
|
27
|
+
export interface OrderAmounts {
|
|
28
|
+
/**
|
|
29
|
+
* On the `quoteDecimals` grid: rounded up when derived, so it funds `size`
|
|
30
|
+
* at the requested leverage, and truncated when the user holds it.
|
|
31
|
+
*/
|
|
32
|
+
margin: DecimalString
|
|
33
|
+
/** Snapped onto the venue lot grid. */
|
|
34
|
+
size: DecimalString
|
|
35
|
+
/** Truncated to `quoteDecimals`. */
|
|
36
|
+
notional: DecimalString
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const DEFAULT_QUOTE_DECIMALS = 2
|
|
40
|
+
const TEN = new Big(10)
|
|
41
|
+
|
|
42
|
+
/** Round a quote amount down onto its decimal grid, with no trailing zeros. */
|
|
43
|
+
function quoteAmount(value: Big, decimals: number): DecimalString {
|
|
44
|
+
const truncated = value.round(decimals, Big.roundDown)
|
|
45
|
+
return truncated.eq(0) ? '0' : truncated.toFixed()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The smallest margin on the `decimals` grid that funds `notional` at
|
|
50
|
+
* `leverage`, so `margin × leverage ≥ notional` holds. The one derived amount
|
|
51
|
+
* that rounds up: a margin rounded down under-funds the size it backs.
|
|
52
|
+
*
|
|
53
|
+
* The ceiling is exact: the remainder decides the carry, so the result never
|
|
54
|
+
* leans on a fixed decimal-place limit the way `div` then `round` would.
|
|
55
|
+
*/
|
|
56
|
+
function coveringMargin(
|
|
57
|
+
notional: Big,
|
|
58
|
+
leverage: Big,
|
|
59
|
+
decimals: number
|
|
60
|
+
): DecimalString {
|
|
61
|
+
const scale = TEN.pow(decimals)
|
|
62
|
+
const scaled = notional.times(scale)
|
|
63
|
+
const remainder = scaled.mod(leverage)
|
|
64
|
+
const whole = scaled.minus(remainder).div(leverage)
|
|
65
|
+
const covering = remainder.eq(0) ? whole : whole.plus(1)
|
|
66
|
+
return covering.eq(0) ? '0' : covering.div(scale).toFixed()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* An order needs three positive amounts. A grid that snaps any of them to
|
|
71
|
+
* zero — a sub-lot size, a sub-cent quote amount — describes no order a venue
|
|
72
|
+
* can take, so the caller gets `null` instead of a result it has to re-check.
|
|
73
|
+
*/
|
|
74
|
+
function executable(amounts: OrderAmounts): OrderAmounts | null {
|
|
75
|
+
const positive =
|
|
76
|
+
new Big(amounts.size).gt(0) &&
|
|
77
|
+
new Big(amounts.margin).gt(0) &&
|
|
78
|
+
new Big(amounts.notional).gt(0)
|
|
79
|
+
return positive ? amounts : null
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function positiveDecimal(value: DecimalString): Big | null {
|
|
83
|
+
if (!isDecimalString(value)) {
|
|
84
|
+
return null
|
|
85
|
+
}
|
|
86
|
+
const parsed = new TruncBig(value)
|
|
87
|
+
return parsed.gt(0) ? parsed : null
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* The three order-entry amounts, derived from whichever one the user typed.
|
|
92
|
+
*
|
|
93
|
+
* The held field is normalised first — truncated to `quoteDecimals` for a
|
|
94
|
+
* margin or notional, snapped onto the venue lot grid for a size — and the
|
|
95
|
+
* other two are then derived from that normalised value, so the three agree
|
|
96
|
+
* with each other rather than with an input the user cannot see.
|
|
97
|
+
*
|
|
98
|
+
* Rounding is directional, so the result always funds itself:
|
|
99
|
+
* `size × price ≤ margin × leverage`. A derived size truncates onto the lot
|
|
100
|
+
* grid and a derived notional truncates onto the quote grid, but a derived
|
|
101
|
+
* margin rounds **up** onto the quote grid, because it is the one amount that
|
|
102
|
+
* has to cover the others rather than cap them.
|
|
103
|
+
*
|
|
104
|
+
* Formulas: `size = margin × leverage ÷ price`,
|
|
105
|
+
* `margin = size × price ÷ leverage`, `notional = size × price`
|
|
106
|
+
* (or `margin × leverage` when the margin is held).
|
|
107
|
+
*
|
|
108
|
+
* @returns `null` when `amount` or `price` is not a positive decimal string,
|
|
109
|
+
* when `leverage` is not a positive finite number, or when the venue and
|
|
110
|
+
* quote grids snap the result to a non-positive amount — a sub-lot size or
|
|
111
|
+
* a sub-cent quote amount describes no order a venue can take.
|
|
112
|
+
* @throws {PerpsError} `ValidationError` when `quoteDecimals` is not a
|
|
113
|
+
* non-negative integer, or `SDKError` when `market.providerId` names no
|
|
114
|
+
* registered provider plugin.
|
|
115
|
+
* @public
|
|
116
|
+
*/
|
|
117
|
+
export function calculateOrderAmounts(
|
|
118
|
+
input: OrderAmountsInput
|
|
119
|
+
): OrderAmounts | null {
|
|
120
|
+
const {
|
|
121
|
+
sdk,
|
|
122
|
+
market,
|
|
123
|
+
held,
|
|
124
|
+
leverage,
|
|
125
|
+
quoteDecimals = DEFAULT_QUOTE_DECIMALS,
|
|
126
|
+
} = input
|
|
127
|
+
if (!Number.isInteger(quoteDecimals) || quoteDecimals < 0) {
|
|
128
|
+
throw new PerpsError(
|
|
129
|
+
PerpsErrorCode.ValidationError,
|
|
130
|
+
`Invalid quoteDecimals for order amounts: ${quoteDecimals}`
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
const amount = positiveDecimal(input.amount)
|
|
134
|
+
const price = positiveDecimal(input.price)
|
|
135
|
+
if (
|
|
136
|
+
amount === null ||
|
|
137
|
+
price === null ||
|
|
138
|
+
!Number.isFinite(leverage) ||
|
|
139
|
+
leverage <= 0
|
|
140
|
+
) {
|
|
141
|
+
return null
|
|
142
|
+
}
|
|
143
|
+
const leverageFactor = new TruncBig(leverage)
|
|
144
|
+
|
|
145
|
+
if (held === 'size') {
|
|
146
|
+
const size = snapOrderSize(sdk, market, amount.toFixed())
|
|
147
|
+
const notional = new TruncBig(size).times(price)
|
|
148
|
+
return executable({
|
|
149
|
+
margin: coveringMargin(notional, leverageFactor, quoteDecimals),
|
|
150
|
+
size,
|
|
151
|
+
notional: quoteAmount(notional, quoteDecimals),
|
|
152
|
+
})
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (held === 'notional') {
|
|
156
|
+
const notional = quoteAmount(amount, quoteDecimals)
|
|
157
|
+
const exact = new TruncBig(notional)
|
|
158
|
+
return executable({
|
|
159
|
+
margin: coveringMargin(exact, leverageFactor, quoteDecimals),
|
|
160
|
+
size: snapOrderSize(sdk, market, exact.div(price).toFixed()),
|
|
161
|
+
notional,
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const margin = quoteAmount(amount, quoteDecimals)
|
|
166
|
+
const notional = new TruncBig(margin).times(leverage)
|
|
167
|
+
return executable({
|
|
168
|
+
margin,
|
|
169
|
+
size: snapOrderSize(sdk, market, notional.div(price).toFixed()),
|
|
170
|
+
notional: quoteAmount(notional, quoteDecimals),
|
|
171
|
+
})
|
|
172
|
+
}
|