@lifi/perps-sdk 23.1.0 → 24.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 +85 -45
- package/dist/cjs/client/PerpsClient.d.ts +3 -2
- package/dist/cjs/client/PerpsClient.d.ts.map +1 -1
- package/dist/cjs/client/PerpsClient.js +16 -9
- package/dist/cjs/client/PerpsClient.js.map +1 -1
- package/dist/cjs/decimal/arithmetic.d.ts +13 -0
- package/dist/cjs/decimal/arithmetic.d.ts.map +1 -0
- package/dist/cjs/decimal/arithmetic.js +48 -0
- package/dist/cjs/decimal/arithmetic.js.map +1 -0
- package/dist/cjs/decimal/big.d.ts +0 -1
- package/dist/cjs/decimal/big.d.ts.map +1 -1
- package/dist/cjs/decimal/big.js +0 -4
- package/dist/cjs/decimal/big.js.map +1 -1
- package/dist/cjs/decimal/compare.d.ts +6 -2
- package/dist/cjs/decimal/compare.d.ts.map +1 -1
- package/dist/cjs/decimal/compare.js +15 -2
- package/dist/cjs/decimal/compare.js.map +1 -1
- package/dist/cjs/decimal/convert.d.ts +12 -6
- package/dist/cjs/decimal/convert.d.ts.map +1 -1
- package/dist/cjs/decimal/convert.js +36 -14
- package/dist/cjs/decimal/convert.js.map +1 -1
- package/dist/cjs/decimal/decimalStringToBig.d.ts +5 -0
- package/dist/cjs/decimal/decimalStringToBig.d.ts.map +1 -0
- package/dist/cjs/decimal/decimalStringToBig.js +27 -0
- package/dist/cjs/decimal/decimalStringToBig.js.map +1 -0
- package/dist/cjs/decimal/format.d.ts.map +1 -1
- package/dist/cjs/decimal/format.js +70 -52
- package/dist/cjs/decimal/format.js.map +1 -1
- package/dist/cjs/decimal/parse.d.ts +4 -4
- package/dist/cjs/decimal/parse.d.ts.map +1 -1
- package/dist/cjs/decimal/parse.js +42 -25
- package/dist/cjs/decimal/parse.js.map +1 -1
- package/dist/cjs/index.d.ts +13 -11
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +64 -8
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/math/fills.d.ts +1 -1
- package/dist/cjs/math/fills.d.ts.map +1 -1
- package/dist/cjs/math/fills.js +28 -13
- package/dist/cjs/math/fills.js.map +1 -1
- package/dist/cjs/math/order.d.ts +27 -16
- package/dist/cjs/math/order.d.ts.map +1 -1
- package/dist/cjs/math/order.js +106 -122
- package/dist/cjs/math/order.js.map +1 -1
- package/dist/cjs/math/position.d.ts +85 -35
- package/dist/cjs/math/position.d.ts.map +1 -1
- package/dist/cjs/math/position.js +88 -91
- package/dist/cjs/math/position.js.map +1 -1
- package/dist/cjs/services/getGasRecommendation.js +1 -1
- package/dist/cjs/services/getGasRecommendation.js.map +1 -1
- package/dist/cjs/services/getQuote.d.ts +1 -1
- package/dist/cjs/services/resolveSubscribeQuote.d.ts.map +1 -1
- package/dist/cjs/services/resolveSubscribeQuote.js +3 -2
- package/dist/cjs/services/resolveSubscribeQuote.js.map +1 -1
- package/dist/cjs/transport/request.d.ts +1 -0
- package/dist/cjs/transport/request.d.ts.map +1 -1
- package/dist/cjs/transport/request.js +2 -2
- package/dist/cjs/transport/request.js.map +1 -1
- package/dist/cjs/types/api.d.ts +4 -0
- package/dist/cjs/types/api.d.ts.map +1 -1
- package/dist/cjs/types/provider.d.ts +9 -5
- package/dist/cjs/types/provider.d.ts.map +1 -1
- package/dist/cjs/types/withdrawal.d.ts +12 -4
- package/dist/cjs/types/withdrawal.d.ts.map +1 -1
- package/dist/cjs/utils/createSafeFunction.d.ts +2 -0
- package/dist/cjs/utils/createSafeFunction.d.ts.map +1 -0
- package/dist/cjs/utils/createSafeFunction.js +15 -0
- package/dist/cjs/utils/createSafeFunction.js.map +1 -0
- package/dist/cjs/utils/timestampToIsoString.d.ts +3 -0
- package/dist/cjs/utils/timestampToIsoString.d.ts.map +1 -0
- package/dist/cjs/utils/timestampToIsoString.js +16 -0
- package/dist/cjs/utils/timestampToIsoString.js.map +1 -0
- package/dist/cjs/utils/warnOnce.d.ts +2 -0
- package/dist/cjs/utils/warnOnce.d.ts.map +1 -1
- package/dist/cjs/utils/warnOnce.js +13 -1
- package/dist/cjs/utils/warnOnce.js.map +1 -1
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/websocket/PerpsWsClient.d.ts +2 -0
- package/dist/cjs/websocket/PerpsWsClient.d.ts.map +1 -1
- package/dist/cjs/websocket/PerpsWsClient.js +14 -1
- package/dist/cjs/websocket/PerpsWsClient.js.map +1 -1
- package/dist/cjs/websocket/wsLog.d.ts +2 -0
- package/dist/cjs/websocket/wsLog.d.ts.map +1 -1
- package/dist/cjs/websocket/wsLog.js +8 -0
- package/dist/cjs/websocket/wsLog.js.map +1 -1
- package/dist/cjs/wire/orderAmounts.d.ts.map +1 -1
- package/dist/cjs/wire/orderAmounts.js +6 -9
- package/dist/cjs/wire/orderAmounts.js.map +1 -1
- package/dist/cjs/wire/refuel.d.ts +4 -1
- package/dist/cjs/wire/refuel.d.ts.map +1 -1
- package/dist/cjs/wire/refuel.js +23 -6
- package/dist/cjs/wire/refuel.js.map +1 -1
- package/dist/cjs/wire/transferable.js +3 -3
- package/dist/cjs/wire/transferable.js.map +1 -1
- package/dist/cjs/wire/withdraw.d.ts.map +1 -1
- package/dist/cjs/wire/withdraw.js +3 -3
- package/dist/cjs/wire/withdraw.js.map +1 -1
- package/dist/esm/client/PerpsClient.d.ts +17 -4
- package/dist/esm/client/PerpsClient.d.ts.map +1 -1
- package/dist/esm/client/PerpsClient.js +30 -8
- package/dist/esm/client/PerpsClient.js.map +1 -1
- package/dist/esm/decimal/arithmetic.d.ts +84 -0
- package/dist/esm/decimal/arithmetic.d.ts.map +1 -0
- package/dist/esm/decimal/arithmetic.js +110 -0
- package/dist/esm/decimal/arithmetic.js.map +1 -0
- package/dist/esm/decimal/big.d.ts +0 -2
- package/dist/esm/decimal/big.d.ts.map +1 -1
- package/dist/esm/decimal/big.js +0 -4
- package/dist/esm/decimal/big.js.map +1 -1
- package/dist/esm/decimal/compare.d.ts +39 -5
- package/dist/esm/decimal/compare.d.ts.map +1 -1
- package/dist/esm/decimal/compare.js +45 -5
- package/dist/esm/decimal/compare.js.map +1 -1
- package/dist/esm/decimal/convert.d.ts +62 -26
- package/dist/esm/decimal/convert.d.ts.map +1 -1
- package/dist/esm/decimal/convert.js +76 -25
- package/dist/esm/decimal/convert.js.map +1 -1
- package/dist/esm/decimal/decimalStringToBig.d.ts +26 -0
- package/dist/esm/decimal/decimalStringToBig.d.ts.map +1 -0
- package/dist/esm/decimal/decimalStringToBig.js +40 -0
- package/dist/esm/decimal/decimalStringToBig.js.map +1 -0
- package/dist/esm/decimal/format.d.ts +4 -1
- package/dist/esm/decimal/format.d.ts.map +1 -1
- package/dist/esm/decimal/format.js +71 -70
- package/dist/esm/decimal/format.js.map +1 -1
- package/dist/esm/decimal/parse.d.ts +22 -13
- package/dist/esm/decimal/parse.d.ts.map +1 -1
- package/dist/esm/decimal/parse.js +56 -46
- package/dist/esm/decimal/parse.js.map +1 -1
- package/dist/esm/index.d.ts +13 -11
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +9 -7
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/math/fills.d.ts +6 -3
- package/dist/esm/math/fills.d.ts.map +1 -1
- package/dist/esm/math/fills.js +31 -16
- package/dist/esm/math/fills.js.map +1 -1
- package/dist/esm/math/order.d.ts +85 -65
- package/dist/esm/math/order.d.ts.map +1 -1
- package/dist/esm/math/order.js +158 -166
- package/dist/esm/math/order.js.map +1 -1
- package/dist/esm/math/position.d.ts +155 -98
- package/dist/esm/math/position.d.ts.map +1 -1
- package/dist/esm/math/position.js +157 -155
- package/dist/esm/math/position.js.map +1 -1
- package/dist/esm/services/getGasRecommendation.js +1 -1
- package/dist/esm/services/getGasRecommendation.js.map +1 -1
- package/dist/esm/services/getQuote.d.ts +2 -2
- package/dist/esm/services/getQuote.js +1 -1
- package/dist/esm/services/resolveSubscribeQuote.d.ts +1 -1
- package/dist/esm/services/resolveSubscribeQuote.d.ts.map +1 -1
- package/dist/esm/services/resolveSubscribeQuote.js +4 -3
- package/dist/esm/services/resolveSubscribeQuote.js.map +1 -1
- package/dist/esm/transport/request.d.ts +5 -0
- package/dist/esm/transport/request.d.ts.map +1 -1
- package/dist/esm/transport/request.js +2 -2
- package/dist/esm/transport/request.js.map +1 -1
- package/dist/esm/types/api.d.ts +9 -0
- package/dist/esm/types/api.d.ts.map +1 -1
- package/dist/esm/types/provider.d.ts +26 -13
- package/dist/esm/types/provider.d.ts.map +1 -1
- package/dist/esm/types/withdrawal.d.ts +32 -7
- package/dist/esm/types/withdrawal.d.ts.map +1 -1
- package/dist/esm/utils/createSafeFunction.d.ts +9 -0
- package/dist/esm/utils/createSafeFunction.d.ts.map +1 -0
- package/dist/esm/utils/createSafeFunction.js +19 -0
- package/dist/esm/utils/createSafeFunction.js.map +1 -0
- package/dist/esm/utils/timestampToIsoString.d.ts +15 -0
- package/dist/esm/utils/timestampToIsoString.d.ts.map +1 -0
- package/dist/esm/utils/timestampToIsoString.js +24 -0
- package/dist/esm/utils/timestampToIsoString.js.map +1 -0
- package/dist/esm/utils/warnOnce.d.ts +16 -0
- package/dist/esm/utils/warnOnce.d.ts.map +1 -1
- package/dist/esm/utils/warnOnce.js +24 -0
- package/dist/esm/utils/warnOnce.js.map +1 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esm/websocket/PerpsWsClient.d.ts +7 -0
- package/dist/esm/websocket/PerpsWsClient.d.ts.map +1 -1
- package/dist/esm/websocket/PerpsWsClient.js +20 -2
- package/dist/esm/websocket/PerpsWsClient.js.map +1 -1
- package/dist/esm/websocket/wsLog.d.ts +12 -0
- package/dist/esm/websocket/wsLog.d.ts.map +1 -1
- package/dist/esm/websocket/wsLog.js +18 -0
- package/dist/esm/websocket/wsLog.js.map +1 -1
- package/dist/esm/wire/orderAmounts.d.ts.map +1 -1
- package/dist/esm/wire/orderAmounts.js +2 -2
- package/dist/esm/wire/orderAmounts.js.map +1 -1
- package/dist/esm/wire/refuel.d.ts +24 -14
- package/dist/esm/wire/refuel.d.ts.map +1 -1
- package/dist/esm/wire/refuel.js +38 -17
- package/dist/esm/wire/refuel.js.map +1 -1
- package/dist/esm/wire/transferable.js +3 -3
- package/dist/esm/wire/transferable.js.map +1 -1
- package/dist/esm/wire/withdraw.d.ts.map +1 -1
- package/dist/esm/wire/withdraw.js +3 -3
- package/dist/esm/wire/withdraw.js.map +1 -1
- package/dist/types/client/PerpsClient.d.ts +17 -4
- package/dist/types/client/PerpsClient.d.ts.map +1 -1
- package/dist/types/decimal/arithmetic.d.ts +84 -0
- package/dist/types/decimal/arithmetic.d.ts.map +1 -0
- package/dist/types/decimal/big.d.ts +0 -2
- package/dist/types/decimal/big.d.ts.map +1 -1
- package/dist/types/decimal/compare.d.ts +39 -5
- package/dist/types/decimal/compare.d.ts.map +1 -1
- package/dist/types/decimal/convert.d.ts +62 -26
- package/dist/types/decimal/convert.d.ts.map +1 -1
- package/dist/types/decimal/decimalStringToBig.d.ts +26 -0
- package/dist/types/decimal/decimalStringToBig.d.ts.map +1 -0
- package/dist/types/decimal/format.d.ts +4 -1
- package/dist/types/decimal/format.d.ts.map +1 -1
- package/dist/types/decimal/parse.d.ts +22 -13
- package/dist/types/decimal/parse.d.ts.map +1 -1
- package/dist/types/index.d.ts +13 -11
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/math/fills.d.ts +6 -3
- package/dist/types/math/fills.d.ts.map +1 -1
- package/dist/types/math/order.d.ts +85 -65
- package/dist/types/math/order.d.ts.map +1 -1
- package/dist/types/math/position.d.ts +155 -98
- package/dist/types/math/position.d.ts.map +1 -1
- package/dist/types/services/getQuote.d.ts +2 -2
- package/dist/types/services/resolveSubscribeQuote.d.ts +1 -1
- package/dist/types/services/resolveSubscribeQuote.d.ts.map +1 -1
- package/dist/types/transport/request.d.ts +5 -0
- package/dist/types/transport/request.d.ts.map +1 -1
- package/dist/types/types/api.d.ts +9 -0
- package/dist/types/types/api.d.ts.map +1 -1
- package/dist/types/types/provider.d.ts +26 -13
- package/dist/types/types/provider.d.ts.map +1 -1
- package/dist/types/types/withdrawal.d.ts +32 -7
- package/dist/types/types/withdrawal.d.ts.map +1 -1
- package/dist/types/utils/createSafeFunction.d.ts +9 -0
- package/dist/types/utils/createSafeFunction.d.ts.map +1 -0
- package/dist/types/utils/timestampToIsoString.d.ts +15 -0
- package/dist/types/utils/timestampToIsoString.d.ts.map +1 -0
- package/dist/types/utils/warnOnce.d.ts +16 -0
- package/dist/types/utils/warnOnce.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/dist/types/websocket/PerpsWsClient.d.ts +7 -0
- package/dist/types/websocket/PerpsWsClient.d.ts.map +1 -1
- package/dist/types/websocket/wsLog.d.ts +12 -0
- package/dist/types/websocket/wsLog.d.ts.map +1 -1
- package/dist/types/wire/orderAmounts.d.ts.map +1 -1
- package/dist/types/wire/refuel.d.ts +24 -14
- package/dist/types/wire/refuel.d.ts.map +1 -1
- package/dist/types/wire/withdraw.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/client/PerpsClient.ts +48 -10
- package/src/decimal/arithmetic.ts +144 -0
- package/src/decimal/big.ts +0 -5
- package/src/decimal/compare.ts +60 -10
- package/src/decimal/convert.ts +123 -44
- package/src/decimal/decimalStringToBig.ts +47 -0
- package/src/decimal/format.ts +81 -72
- package/src/decimal/parse.ts +71 -61
- package/src/index.ts +73 -10
- package/src/math/fills.ts +32 -17
- package/src/math/order.ts +261 -216
- package/src/math/position.ts +277 -194
- package/src/services/getGasRecommendation.ts +1 -1
- package/src/services/getQuote.ts +2 -2
- package/src/services/resolveSubscribeQuote.ts +4 -3
- package/src/transport/request.ts +7 -2
- package/src/types/api.ts +10 -0
- package/src/types/provider.ts +35 -13
- package/src/types/withdrawal.ts +35 -8
- package/src/utils/createSafeFunction.ts +20 -0
- package/src/utils/timestampToIsoString.ts +31 -0
- package/src/utils/warnOnce.ts +44 -0
- package/src/version.ts +1 -1
- package/src/websocket/PerpsWsClient.ts +25 -2
- package/src/websocket/wsLog.ts +31 -0
- package/src/wire/orderAmounts.ts +3 -2
- package/src/wire/refuel.ts +56 -20
- package/src/wire/transferable.ts +3 -3
- package/src/wire/withdraw.ts +3 -5
- package/dist/cjs/decimal/requireDecimal.d.ts +0 -4
- package/dist/cjs/decimal/requireDecimal.d.ts.map +0 -1
- package/dist/cjs/decimal/requireDecimal.js +0 -12
- package/dist/cjs/decimal/requireDecimal.js.map +0 -1
- package/dist/esm/decimal/requireDecimal.d.ts +0 -5
- package/dist/esm/decimal/requireDecimal.d.ts.map +0 -1
- package/dist/esm/decimal/requireDecimal.js +0 -7
- package/dist/esm/decimal/requireDecimal.js.map +0 -1
- package/dist/types/decimal/requireDecimal.d.ts +0 -5
- package/dist/types/decimal/requireDecimal.d.ts.map +0 -1
- package/src/decimal/requireDecimal.ts +0 -8
package/src/math/order.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Display-tier order formulas. Every function takes and gives
|
|
3
|
-
*
|
|
2
|
+
* Display-tier order formulas. Every function takes and gives decimal
|
|
3
|
+
* strings; arithmetic is exact Big.js, with division to 40 decimal places.
|
|
4
|
+
* Each formula throws `ValidationError` on an input that is not a decimal
|
|
5
|
+
* string and has a `safe*` pair that gives `undefined` in place of the throw.
|
|
4
6
|
*/
|
|
5
7
|
|
|
6
8
|
import {
|
|
@@ -20,10 +22,14 @@ import {
|
|
|
20
22
|
type TradeType,
|
|
21
23
|
type TriggerOrder,
|
|
22
24
|
} from '@lifi/perps-types'
|
|
23
|
-
import
|
|
24
|
-
import {
|
|
25
|
-
|
|
25
|
+
import { DivBig } from '../decimal/big.js'
|
|
26
|
+
import {
|
|
27
|
+
bigToDecimalString,
|
|
28
|
+
decimalStringToBig,
|
|
29
|
+
decimalStringToDivBig,
|
|
30
|
+
} from '../decimal/decimalStringToBig.js'
|
|
26
31
|
import { PerpsError } from '../errors/PerpsError.js'
|
|
32
|
+
import { createSafeFunction } from '../utils/createSafeFunction.js'
|
|
27
33
|
import {
|
|
28
34
|
isActiveOrderStatus,
|
|
29
35
|
isRegularOrder,
|
|
@@ -32,74 +38,91 @@ import {
|
|
|
32
38
|
import { calculateRealizedPnl } from './position.js'
|
|
33
39
|
|
|
34
40
|
/**
|
|
35
|
-
*
|
|
41
|
+
* Position size in asset units from margin: `marginUsd × leverage ÷ price`.
|
|
36
42
|
*
|
|
37
|
-
* @param marginUsd - Margin amount in USD
|
|
38
|
-
* @param leverage - Position leverage
|
|
39
|
-
* @param price - Current asset price
|
|
40
|
-
* @returns Position size in asset units
|
|
41
43
|
* @example
|
|
42
44
|
* ```ts
|
|
43
|
-
* calculateSize(100, 10, 2000) // 0.5 (ETH at $2000)
|
|
45
|
+
* calculateSize('100', '10', '2000') // '0.5' (ETH at $2000)
|
|
44
46
|
* ```
|
|
47
|
+
* @throws {PerpsError} `ValidationError` when an input is not a decimal string
|
|
48
|
+
* or `price` is zero.
|
|
45
49
|
* @public
|
|
46
50
|
*/
|
|
47
51
|
export function calculateSize(
|
|
48
|
-
marginUsd:
|
|
49
|
-
leverage:
|
|
50
|
-
price:
|
|
51
|
-
):
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
marginUsd: string,
|
|
53
|
+
leverage: string,
|
|
54
|
+
price: string
|
|
55
|
+
): string {
|
|
56
|
+
const notional = decimalStringToDivBig(marginUsd).times(
|
|
57
|
+
decimalStringToBig(leverage)
|
|
58
|
+
)
|
|
59
|
+
const priceBig = decimalStringToBig(price)
|
|
60
|
+
if (priceBig.eq(0)) {
|
|
61
|
+
throw new PerpsError(
|
|
62
|
+
PerpsErrorCode.ValidationError,
|
|
63
|
+
'Price must not be zero.'
|
|
64
|
+
)
|
|
57
65
|
}
|
|
58
|
-
return
|
|
66
|
+
return bigToDecimalString(notional.div(priceBig))
|
|
59
67
|
}
|
|
60
68
|
|
|
69
|
+
/** @public */
|
|
70
|
+
export const safeCalculateSize = createSafeFunction(
|
|
71
|
+
'calculateSize',
|
|
72
|
+
calculateSize
|
|
73
|
+
)
|
|
74
|
+
|
|
61
75
|
/**
|
|
62
|
-
*
|
|
76
|
+
* Estimated trading fee in USD: `sizeUsd × feeRate`.
|
|
63
77
|
*
|
|
64
|
-
* @param
|
|
65
|
-
* @
|
|
66
|
-
* @returns Estimated fee in USD
|
|
78
|
+
* @param feeRate - Fee rate as a fraction (`'0.00035'` for 0.035%).
|
|
79
|
+
* @throws {PerpsError} `ValidationError` when an input is not a decimal string.
|
|
67
80
|
* @public
|
|
68
81
|
*/
|
|
69
|
-
export function estimateFees(sizeUsd:
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
return new DivBig(sizeUsd).times(feeRate).toNumber()
|
|
82
|
+
export function estimateFees(sizeUsd: string, feeRate: string): string {
|
|
83
|
+
return bigToDecimalString(
|
|
84
|
+
decimalStringToBig(sizeUsd).times(decimalStringToBig(feeRate))
|
|
85
|
+
)
|
|
74
86
|
}
|
|
75
87
|
|
|
88
|
+
/** @public */
|
|
89
|
+
export const safeEstimateFees = createSafeFunction('estimateFees', estimateFees)
|
|
90
|
+
|
|
76
91
|
/**
|
|
77
|
-
* Apply slippage to
|
|
92
|
+
* Apply slippage to an order-entry price with exact decimal math: a buy
|
|
93
|
+
* multiplies by `1 + slippagePercent / 100`, a sell divides by it. The result
|
|
94
|
+
* is not rounded; snap it to the market tick before it goes to a venue.
|
|
78
95
|
*
|
|
79
|
-
* @param
|
|
80
|
-
* @
|
|
81
|
-
*
|
|
82
|
-
* @returns Price adjusted for slippage
|
|
96
|
+
* @param slippagePercent - Slippage tolerance as a percentage (`'0.5'` is 0.5%).
|
|
97
|
+
* @throws {PerpsError} `ValidationError` when an input is not a decimal
|
|
98
|
+
* string, or `slippagePercent` is -100 or less.
|
|
83
99
|
* @public
|
|
84
100
|
*/
|
|
85
|
-
export function
|
|
86
|
-
price:
|
|
87
|
-
slippagePercent:
|
|
101
|
+
export function applySlippageToPrice(
|
|
102
|
+
price: string,
|
|
103
|
+
slippagePercent: string,
|
|
88
104
|
isBuy: boolean
|
|
89
|
-
):
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
if (multiplier.eq(0)) {
|
|
98
|
-
return price / multiplier.toNumber()
|
|
105
|
+
): string {
|
|
106
|
+
const base = decimalStringToDivBig(price)
|
|
107
|
+
const slippage = decimalStringToBig(slippagePercent)
|
|
108
|
+
if (slippage.lte(-100)) {
|
|
109
|
+
throw new PerpsError(
|
|
110
|
+
PerpsErrorCode.ValidationError,
|
|
111
|
+
`Invalid \`slippagePercent\`: ${slippagePercent}.`
|
|
112
|
+
)
|
|
99
113
|
}
|
|
100
|
-
|
|
114
|
+
const multiplier = new DivBig(slippage).div(100).plus(1)
|
|
115
|
+
return bigToDecimalString(
|
|
116
|
+
isBuy ? base.times(multiplier) : base.div(multiplier)
|
|
117
|
+
)
|
|
101
118
|
}
|
|
102
119
|
|
|
120
|
+
/** @public */
|
|
121
|
+
export const safeApplySlippageToPrice = createSafeFunction(
|
|
122
|
+
'applySlippageToPrice',
|
|
123
|
+
applySlippageToPrice
|
|
124
|
+
)
|
|
125
|
+
|
|
103
126
|
/**
|
|
104
127
|
* Signed expected PnL for a trigger price — see {@link calculateExpectedPnl}.
|
|
105
128
|
*
|
|
@@ -107,131 +130,154 @@ export function applySlippage(
|
|
|
107
130
|
*/
|
|
108
131
|
export interface ExpectedPnl {
|
|
109
132
|
/** Signed expected profit/loss in USD. */
|
|
110
|
-
amount:
|
|
111
|
-
/** Signed expected return as a percentage (10 means 10%). */
|
|
112
|
-
percent:
|
|
133
|
+
amount: string
|
|
134
|
+
/** Signed expected return as a percentage (`'10'` means 10%). */
|
|
135
|
+
percent: string
|
|
113
136
|
}
|
|
114
137
|
|
|
115
138
|
/**
|
|
116
|
-
*
|
|
117
|
-
*
|
|
139
|
+
* Expected gain or loss for a TP or SL trigger price. Positive is a profit,
|
|
140
|
+
* negative a loss.
|
|
118
141
|
*
|
|
119
|
-
* @param
|
|
120
|
-
* @param
|
|
121
|
-
* @
|
|
122
|
-
*
|
|
123
|
-
* @
|
|
142
|
+
* @param entryPrice - Position entry or current market price.
|
|
143
|
+
* @param margin - Margin amount in USD.
|
|
144
|
+
* @returns The expected PnL, or `null` when `triggerPrice`, `entryPrice` or
|
|
145
|
+
* `margin` is zero.
|
|
146
|
+
* @throws {PerpsError} `ValidationError` when an input is not a decimal string.
|
|
124
147
|
* @public
|
|
125
148
|
*/
|
|
126
149
|
export function calculateExpectedPnl(
|
|
127
|
-
triggerPrice:
|
|
128
|
-
entryPrice:
|
|
129
|
-
leverage:
|
|
150
|
+
triggerPrice: string,
|
|
151
|
+
entryPrice: string,
|
|
152
|
+
leverage: string,
|
|
130
153
|
isLong: boolean,
|
|
131
|
-
margin:
|
|
154
|
+
margin: string
|
|
132
155
|
): ExpectedPnl | null {
|
|
133
|
-
|
|
156
|
+
const trigger = decimalStringToDivBig(triggerPrice)
|
|
157
|
+
const entry = decimalStringToBig(entryPrice)
|
|
158
|
+
const leverageBig = decimalStringToBig(leverage)
|
|
159
|
+
const marginBig = decimalStringToBig(margin)
|
|
160
|
+
if (trigger.eq(0) || entry.eq(0) || marginBig.eq(0)) {
|
|
134
161
|
return null
|
|
135
162
|
}
|
|
136
|
-
if (!areFinite(triggerPrice, entryPrice, leverage, margin)) {
|
|
137
|
-
return { amount: Number.NaN, percent: Number.NaN }
|
|
138
|
-
}
|
|
139
163
|
const priceDiff = isLong
|
|
140
|
-
?
|
|
141
|
-
:
|
|
142
|
-
const percent = priceDiff.div(
|
|
143
|
-
const amount = percent.times(
|
|
144
|
-
return {
|
|
164
|
+
? trigger.minus(entry)
|
|
165
|
+
: trigger.times(-1).plus(entry)
|
|
166
|
+
const percent = priceDiff.div(entry).times(leverageBig).times(100)
|
|
167
|
+
const amount = percent.times(marginBig).div(100)
|
|
168
|
+
return {
|
|
169
|
+
amount: bigToDecimalString(amount),
|
|
170
|
+
percent: bigToDecimalString(percent),
|
|
171
|
+
}
|
|
145
172
|
}
|
|
146
173
|
|
|
174
|
+
/** @public */
|
|
175
|
+
export const safeCalculateExpectedPnl = createSafeFunction(
|
|
176
|
+
'calculateExpectedPnl',
|
|
177
|
+
calculateExpectedPnl
|
|
178
|
+
)
|
|
179
|
+
|
|
147
180
|
/**
|
|
148
|
-
*
|
|
181
|
+
* Trigger price that realises a percentage gain or loss. A zero `entryPrice`
|
|
182
|
+
* or `leverage` gives `'0'`.
|
|
149
183
|
*
|
|
150
|
-
* @param percent - Target gain
|
|
151
|
-
*
|
|
152
|
-
* @
|
|
153
|
-
* @param isLong - True for long positions, false for short
|
|
184
|
+
* @param percent - Target gain or loss percentage (positive = profitable
|
|
185
|
+
* direction).
|
|
186
|
+
* @throws {PerpsError} `ValidationError` when an input is not a decimal string.
|
|
154
187
|
* @public
|
|
155
188
|
*/
|
|
156
189
|
export function calculateTriggerPrice(
|
|
157
|
-
percent:
|
|
158
|
-
entryPrice:
|
|
159
|
-
leverage:
|
|
190
|
+
percent: string,
|
|
191
|
+
entryPrice: string,
|
|
192
|
+
leverage: string,
|
|
160
193
|
isLong: boolean
|
|
161
|
-
):
|
|
162
|
-
|
|
163
|
-
|
|
194
|
+
): string {
|
|
195
|
+
const percentBig = decimalStringToDivBig(percent)
|
|
196
|
+
const entry = decimalStringToBig(entryPrice)
|
|
197
|
+
const leverageBig = decimalStringToBig(leverage)
|
|
198
|
+
if (entry.eq(0) || leverageBig.eq(0)) {
|
|
199
|
+
return '0'
|
|
164
200
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
.times(entryPrice)
|
|
170
|
-
.div(new DivBig(leverage).times(100))
|
|
171
|
-
const entry = new DivBig(entryPrice)
|
|
172
|
-
return (isLong ? entry.plus(priceDelta) : entry.minus(priceDelta)).toNumber()
|
|
201
|
+
const priceDelta = percentBig.times(entry).div(leverageBig.times(100))
|
|
202
|
+
return bigToDecimalString(
|
|
203
|
+
isLong ? entry.plus(priceDelta) : entry.minus(priceDelta)
|
|
204
|
+
)
|
|
173
205
|
}
|
|
174
206
|
|
|
207
|
+
/** @public */
|
|
208
|
+
export const safeCalculateTriggerPrice = createSafeFunction(
|
|
209
|
+
'calculateTriggerPrice',
|
|
210
|
+
calculateTriggerPrice
|
|
211
|
+
)
|
|
212
|
+
|
|
175
213
|
/**
|
|
176
|
-
*
|
|
214
|
+
* Percentage gain or loss that a trigger price realises. A zero `entryPrice`
|
|
215
|
+
* or `leverage` gives `'0'`.
|
|
177
216
|
*
|
|
178
|
-
* @
|
|
179
|
-
* @param entryPrice - Position entry price
|
|
180
|
-
* @param leverage - Position leverage multiplier
|
|
181
|
-
* @param isLong - True for long positions, false for short
|
|
217
|
+
* @throws {PerpsError} `ValidationError` when an input is not a decimal string.
|
|
182
218
|
* @public
|
|
183
219
|
*/
|
|
184
220
|
export function calculateTriggerPercent(
|
|
185
|
-
price:
|
|
186
|
-
entryPrice:
|
|
187
|
-
leverage:
|
|
221
|
+
price: string,
|
|
222
|
+
entryPrice: string,
|
|
223
|
+
leverage: string,
|
|
188
224
|
isLong: boolean
|
|
189
|
-
):
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
if (
|
|
194
|
-
return
|
|
225
|
+
): string {
|
|
226
|
+
const priceBig = decimalStringToDivBig(price)
|
|
227
|
+
const entry = decimalStringToBig(entryPrice)
|
|
228
|
+
const leverageBig = decimalStringToBig(leverage)
|
|
229
|
+
if (entry.eq(0) || leverageBig.eq(0)) {
|
|
230
|
+
return '0'
|
|
195
231
|
}
|
|
196
232
|
const priceDiff = isLong
|
|
197
|
-
?
|
|
198
|
-
:
|
|
199
|
-
return priceDiff.div(
|
|
233
|
+
? priceBig.minus(entry)
|
|
234
|
+
: priceBig.times(-1).plus(entry)
|
|
235
|
+
return bigToDecimalString(priceDiff.div(entry).times(leverageBig).times(100))
|
|
200
236
|
}
|
|
201
237
|
|
|
238
|
+
/** @public */
|
|
239
|
+
export const safeCalculateTriggerPercent = createSafeFunction(
|
|
240
|
+
'calculateTriggerPercent',
|
|
241
|
+
calculateTriggerPercent
|
|
242
|
+
)
|
|
243
|
+
|
|
202
244
|
/**
|
|
203
|
-
*
|
|
245
|
+
* Realized PnL as a percentage of the position value at close:
|
|
246
|
+
* `realizedPnl ÷ (|size| × price) × 100`. A zero position value gives `'0'`.
|
|
204
247
|
*
|
|
205
|
-
* @
|
|
206
|
-
* @param size - Position size in asset units at close
|
|
207
|
-
* @param price - Price at close
|
|
208
|
-
* @returns PnL as a percentage of position value
|
|
248
|
+
* @throws {PerpsError} `ValidationError` when an input is not a decimal string.
|
|
209
249
|
* @public
|
|
210
250
|
*/
|
|
211
251
|
export function calculateRealizedPnlPercent(
|
|
212
|
-
realizedPnl:
|
|
213
|
-
size:
|
|
214
|
-
price:
|
|
215
|
-
):
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
252
|
+
realizedPnl: string,
|
|
253
|
+
size: string,
|
|
254
|
+
price: string
|
|
255
|
+
): string {
|
|
256
|
+
const pnl = decimalStringToDivBig(realizedPnl)
|
|
257
|
+
const positionValue = decimalStringToBig(size)
|
|
258
|
+
.abs()
|
|
259
|
+
.times(decimalStringToBig(price))
|
|
220
260
|
if (positionValue.eq(0)) {
|
|
221
|
-
return 0
|
|
261
|
+
return '0'
|
|
222
262
|
}
|
|
223
|
-
return
|
|
263
|
+
return bigToDecimalString(pnl.div(positionValue).times(100))
|
|
224
264
|
}
|
|
225
265
|
|
|
266
|
+
/** @public */
|
|
267
|
+
export const safeCalculateRealizedPnlPercent = createSafeFunction(
|
|
268
|
+
'calculateRealizedPnlPercent',
|
|
269
|
+
calculateRealizedPnlPercent
|
|
270
|
+
)
|
|
271
|
+
|
|
226
272
|
/** Result of {@link walkOrderbook} — the fill obtained for a USD-notional walk. */
|
|
227
273
|
interface BookWalk {
|
|
228
274
|
/** Base amount filled. */
|
|
229
|
-
baseSize:
|
|
275
|
+
baseSize: string
|
|
230
276
|
/** Notional actually filled in USD (equals the requested size unless the book ran dry). */
|
|
231
|
-
filledNotional:
|
|
232
|
-
/** Volume-weighted average fill price, or 0 when the book is empty. */
|
|
233
|
-
vwap:
|
|
234
|
-
/** True when the levels could not absorb the requested notional
|
|
277
|
+
filledNotional: string
|
|
278
|
+
/** Volume-weighted average fill price, or `'0'` when the book is empty. */
|
|
279
|
+
vwap: string
|
|
280
|
+
/** True when the levels could not absorb the requested notional. */
|
|
235
281
|
insufficientLiquidity: boolean
|
|
236
282
|
}
|
|
237
283
|
|
|
@@ -241,34 +287,25 @@ interface BookWalk {
|
|
|
241
287
|
* in array order — the caller passes asks for a buy and bids for a sell, each
|
|
242
288
|
* already ordered best-price-first. When the book cannot absorb the full
|
|
243
289
|
* notional, the walk stops at the last level and flags `insufficientLiquidity`,
|
|
244
|
-
* returning the best obtainable fill.
|
|
245
|
-
* fields with `insufficientLiquidity` set.
|
|
290
|
+
* returning the best obtainable fill.
|
|
246
291
|
*
|
|
247
|
-
* @throws {PerpsError} `ValidationError` when a level's `price`
|
|
248
|
-
*
|
|
292
|
+
* @throws {PerpsError} `ValidationError` when `sizeUsd` or a level's `price`
|
|
293
|
+
* or `size` is not a decimal string.
|
|
249
294
|
* @public
|
|
250
295
|
*/
|
|
251
296
|
export function walkOrderbook(
|
|
252
297
|
levels: OrderbookLevel[],
|
|
253
|
-
sizeUsd:
|
|
298
|
+
sizeUsd: string
|
|
254
299
|
): BookWalk {
|
|
255
|
-
|
|
256
|
-
return {
|
|
257
|
-
baseSize: Number.NaN,
|
|
258
|
-
filledNotional: Number.NaN,
|
|
259
|
-
vwap: Number.NaN,
|
|
260
|
-
insufficientLiquidity: true,
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
let remaining = new DivBig(sizeUsd)
|
|
300
|
+
let remaining = decimalStringToDivBig(sizeUsd)
|
|
264
301
|
let baseSize = new DivBig(0)
|
|
265
302
|
let filledNotional = new DivBig(0)
|
|
266
303
|
for (const level of levels) {
|
|
267
304
|
if (remaining.lte(0)) {
|
|
268
305
|
break
|
|
269
306
|
}
|
|
270
|
-
const
|
|
271
|
-
const levelNotional = size.times(price)
|
|
307
|
+
const price = decimalStringToDivBig(level.price)
|
|
308
|
+
const levelNotional = decimalStringToBig(level.size).times(price)
|
|
272
309
|
const take = remaining.lt(levelNotional) ? remaining : levelNotional
|
|
273
310
|
if (take.eq(0)) {
|
|
274
311
|
continue
|
|
@@ -278,23 +315,20 @@ export function walkOrderbook(
|
|
|
278
315
|
remaining = remaining.minus(take)
|
|
279
316
|
}
|
|
280
317
|
return {
|
|
281
|
-
baseSize: baseSize
|
|
282
|
-
filledNotional: filledNotional
|
|
283
|
-
vwap: baseSize.eq(0)
|
|
318
|
+
baseSize: bigToDecimalString(baseSize),
|
|
319
|
+
filledNotional: bigToDecimalString(filledNotional),
|
|
320
|
+
vwap: baseSize.eq(0)
|
|
321
|
+
? '0'
|
|
322
|
+
: bigToDecimalString(filledNotional.div(baseSize)),
|
|
284
323
|
insufficientLiquidity: remaining.gt(0),
|
|
285
324
|
}
|
|
286
325
|
}
|
|
287
326
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
PerpsErrorCode.ValidationError,
|
|
294
|
-
`Malformed orderbook level: price='${level.price}', size='${level.size}'`
|
|
295
|
-
)
|
|
296
|
-
}
|
|
297
|
-
}
|
|
327
|
+
/** @public */
|
|
328
|
+
export const safeWalkOrderbook = createSafeFunction(
|
|
329
|
+
'walkOrderbook',
|
|
330
|
+
walkOrderbook
|
|
331
|
+
)
|
|
298
332
|
|
|
299
333
|
/** Inputs to {@link buildQuote} — the resolved market, its live price, its book, and the trade ask. */
|
|
300
334
|
interface BuildQuoteInput {
|
|
@@ -302,7 +336,7 @@ interface BuildQuoteInput {
|
|
|
302
336
|
symbol: string
|
|
303
337
|
type: TradeType
|
|
304
338
|
side: QuoteSide
|
|
305
|
-
sizeUsd:
|
|
339
|
+
sizeUsd: string
|
|
306
340
|
market: Market
|
|
307
341
|
price: MarketContext
|
|
308
342
|
bids: OrderbookLevel[]
|
|
@@ -319,44 +353,45 @@ interface BuildQuoteInput {
|
|
|
319
353
|
* versus mark, applies the base taker fee on the filled notional, and carries
|
|
320
354
|
* the market's `funding` (`null` for spot, which has none).
|
|
321
355
|
*
|
|
322
|
-
* @throws {PerpsError} `ValidationError` when
|
|
323
|
-
*
|
|
324
|
-
* not finite (a non-finite `sizeUsd`, mark price or taker fee).
|
|
356
|
+
* @throws {PerpsError} `ValidationError` when `sizeUsd`, the mark price, the
|
|
357
|
+
* taker fee or a book level is not a decimal string.
|
|
325
358
|
* @public
|
|
326
359
|
*/
|
|
327
360
|
export function buildQuote(input: BuildQuoteInput): Quote {
|
|
328
361
|
const { market, price, side, sizeUsd, feeTier } = input
|
|
329
|
-
const markPrice =
|
|
362
|
+
const markPrice = decimalStringToDivBig(price.markPrice)
|
|
330
363
|
const levels = side === 'buy' ? input.asks : input.bids
|
|
331
364
|
const walk = walkOrderbook(levels, sizeUsd)
|
|
365
|
+
const vwap = decimalStringToBig(walk.vwap)
|
|
332
366
|
const priceImpactBps =
|
|
333
|
-
markPrice
|
|
334
|
-
? 0
|
|
335
|
-
:
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
Number.parseFloat(feeTier.taker)
|
|
339
|
-
)
|
|
367
|
+
markPrice.eq(0) || vwap.eq(0)
|
|
368
|
+
? '0'
|
|
369
|
+
: bigToDecimalString(
|
|
370
|
+
vwap.minus(markPrice).div(markPrice).abs().times(10_000)
|
|
371
|
+
)
|
|
340
372
|
return {
|
|
341
373
|
provider: input.provider,
|
|
342
374
|
symbol: input.symbol,
|
|
343
375
|
marketId: market.id,
|
|
344
376
|
type: input.type,
|
|
345
377
|
side,
|
|
346
|
-
sizeUsd:
|
|
347
|
-
baseSize:
|
|
378
|
+
sizeUsd: bigToDecimalString(decimalStringToBig(sizeUsd)),
|
|
379
|
+
baseSize: walk.baseSize,
|
|
348
380
|
markPrice: price.markPrice,
|
|
349
|
-
expectedFillPrice:
|
|
350
|
-
priceImpactBps
|
|
381
|
+
expectedFillPrice: walk.vwap,
|
|
382
|
+
priceImpactBps,
|
|
351
383
|
feeTier,
|
|
352
384
|
isDefaultFeeTier: true,
|
|
353
|
-
feeUsd:
|
|
385
|
+
feeUsd: estimateFees(walk.filledNotional, feeTier.taker),
|
|
354
386
|
funding: price.funding ?? null,
|
|
355
387
|
insufficientLiquidity: walk.insufficientLiquidity,
|
|
356
388
|
timestamp: input.timestamp,
|
|
357
389
|
}
|
|
358
390
|
}
|
|
359
391
|
|
|
392
|
+
/** @public */
|
|
393
|
+
export const safeBuildQuote = createSafeFunction('buildQuote', buildQuote)
|
|
394
|
+
|
|
360
395
|
/**
|
|
361
396
|
* Pick the matching open position for an order's market, if any.
|
|
362
397
|
*
|
|
@@ -379,18 +414,28 @@ export function findMatchingPosition(
|
|
|
379
414
|
* position can only close what's open.
|
|
380
415
|
*
|
|
381
416
|
* Inputs are non-negative magnitudes.
|
|
417
|
+
*
|
|
418
|
+
* @throws {PerpsError} `ValidationError` when an input is not a decimal string.
|
|
382
419
|
* @public
|
|
383
420
|
*/
|
|
384
421
|
export function resolveCloseSize(
|
|
385
|
-
orderSize:
|
|
386
|
-
positionSize:
|
|
387
|
-
):
|
|
388
|
-
|
|
389
|
-
|
|
422
|
+
orderSize: string,
|
|
423
|
+
positionSize: string
|
|
424
|
+
): string {
|
|
425
|
+
const order = decimalStringToBig(orderSize)
|
|
426
|
+
const position = decimalStringToBig(positionSize)
|
|
427
|
+
if (order.eq(0)) {
|
|
428
|
+
return bigToDecimalString(position)
|
|
390
429
|
}
|
|
391
|
-
return
|
|
430
|
+
return bigToDecimalString(order.lt(position) ? order : position)
|
|
392
431
|
}
|
|
393
432
|
|
|
433
|
+
/** @public */
|
|
434
|
+
export const safeResolveCloseSize = createSafeFunction(
|
|
435
|
+
'resolveCloseSize',
|
|
436
|
+
resolveCloseSize
|
|
437
|
+
)
|
|
438
|
+
|
|
394
439
|
/**
|
|
395
440
|
* Expected rPnL for a resting limit order against a matching position.
|
|
396
441
|
*
|
|
@@ -403,7 +448,7 @@ export function resolveCloseSize(
|
|
|
403
448
|
function regularOrderRealizedPnl(
|
|
404
449
|
order: RegularOrder,
|
|
405
450
|
position: Position | undefined
|
|
406
|
-
):
|
|
451
|
+
): string | null {
|
|
407
452
|
if (!position || !isActiveOrderStatus(order.status)) {
|
|
408
453
|
return null
|
|
409
454
|
}
|
|
@@ -416,32 +461,29 @@ function regularOrderRealizedPnl(
|
|
|
416
461
|
return null
|
|
417
462
|
}
|
|
418
463
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
const
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
!Number.isFinite(entryPrice) ||
|
|
426
|
-
!Number.isFinite(orderSize) ||
|
|
427
|
-
!Number.isFinite(positionSize) ||
|
|
428
|
-
positionSize <= 0
|
|
429
|
-
) {
|
|
464
|
+
if (order.price === undefined) {
|
|
465
|
+
return null
|
|
466
|
+
}
|
|
467
|
+
const orderSize = decimalStringToBig(order.remainingSize).abs()
|
|
468
|
+
const positionSize = decimalStringToBig(position.size).abs()
|
|
469
|
+
if (positionSize.lte(0)) {
|
|
430
470
|
return null
|
|
431
471
|
}
|
|
432
472
|
|
|
433
473
|
// `resolveCloseSize` reads a zero size as "close the whole position", a
|
|
434
474
|
// convention that belongs to an order's submitted size. `remainingSize` is
|
|
435
475
|
// the unfilled quantity, so zero means nothing is left to fill.
|
|
436
|
-
if (orderSize
|
|
476
|
+
if (orderSize.eq(0)) {
|
|
437
477
|
return null
|
|
438
478
|
}
|
|
439
479
|
|
|
440
|
-
const closeSize = resolveCloseSize(orderSize, positionSize)
|
|
441
480
|
return calculateRealizedPnl({
|
|
442
|
-
entryPrice,
|
|
443
|
-
closePrice:
|
|
444
|
-
closeSize
|
|
481
|
+
entryPrice: position.entryPrice,
|
|
482
|
+
closePrice: order.price,
|
|
483
|
+
closeSize: resolveCloseSize(
|
|
484
|
+
bigToDecimalString(orderSize),
|
|
485
|
+
bigToDecimalString(positionSize)
|
|
486
|
+
),
|
|
445
487
|
isLong,
|
|
446
488
|
})
|
|
447
489
|
}
|
|
@@ -450,9 +492,10 @@ function regularOrderRealizedPnl(
|
|
|
450
492
|
function triggerOrderRealizedPnl(
|
|
451
493
|
order: TriggerOrder,
|
|
452
494
|
position: Position | undefined
|
|
453
|
-
):
|
|
495
|
+
): string | null {
|
|
454
496
|
if (
|
|
455
497
|
!position ||
|
|
498
|
+
order.triggerPrice === undefined ||
|
|
456
499
|
!isActiveOrderStatus(order.status) ||
|
|
457
500
|
order.status === OrderStatus.PENDING
|
|
458
501
|
) {
|
|
@@ -466,31 +509,25 @@ function triggerOrderRealizedPnl(
|
|
|
466
509
|
) {
|
|
467
510
|
return null
|
|
468
511
|
}
|
|
469
|
-
const
|
|
470
|
-
const
|
|
471
|
-
|
|
472
|
-
const positionSize = Math.abs(Number.parseFloat(position.size))
|
|
473
|
-
if (
|
|
474
|
-
!Number.isFinite(triggerPrice) ||
|
|
475
|
-
!Number.isFinite(entryPrice) ||
|
|
476
|
-
!Number.isFinite(orderSize) ||
|
|
477
|
-
!Number.isFinite(positionSize) ||
|
|
478
|
-
positionSize <= 0
|
|
479
|
-
) {
|
|
512
|
+
const orderSize = decimalStringToBig(order.remainingSize).abs()
|
|
513
|
+
const positionSize = decimalStringToBig(position.size).abs()
|
|
514
|
+
if (positionSize.lte(0)) {
|
|
480
515
|
return null
|
|
481
516
|
}
|
|
482
517
|
if (
|
|
483
|
-
orderSize
|
|
484
|
-
(
|
|
518
|
+
orderSize.eq(0) &&
|
|
519
|
+
(!decimalStringToBig(order.originalSize).eq(0) || !order.reduceOnly)
|
|
485
520
|
) {
|
|
486
521
|
return null
|
|
487
522
|
}
|
|
488
523
|
|
|
489
|
-
const closeSize = resolveCloseSize(orderSize, positionSize)
|
|
490
524
|
return calculateRealizedPnl({
|
|
491
|
-
entryPrice,
|
|
492
|
-
closePrice: triggerPrice,
|
|
493
|
-
closeSize
|
|
525
|
+
entryPrice: position.entryPrice,
|
|
526
|
+
closePrice: order.triggerPrice,
|
|
527
|
+
closeSize: resolveCloseSize(
|
|
528
|
+
bigToDecimalString(orderSize),
|
|
529
|
+
bigToDecimalString(positionSize)
|
|
530
|
+
),
|
|
494
531
|
isLong,
|
|
495
532
|
})
|
|
496
533
|
}
|
|
@@ -503,12 +540,14 @@ function triggerOrderRealizedPnl(
|
|
|
503
540
|
*
|
|
504
541
|
* @returns Realised PnL if the order would reduce the position, otherwise
|
|
505
542
|
* `null`.
|
|
543
|
+
* @throws {PerpsError} `ValidationError` when a price or size on the order or
|
|
544
|
+
* the position is not a decimal string.
|
|
506
545
|
* @public
|
|
507
546
|
*/
|
|
508
547
|
export function estimateRealizedPnl(
|
|
509
548
|
order: Order,
|
|
510
549
|
position: Position | undefined
|
|
511
|
-
):
|
|
550
|
+
): string | null {
|
|
512
551
|
if (isTriggerOrder(order)) {
|
|
513
552
|
return triggerOrderRealizedPnl(order, position)
|
|
514
553
|
}
|
|
@@ -517,3 +556,9 @@ export function estimateRealizedPnl(
|
|
|
517
556
|
}
|
|
518
557
|
return null
|
|
519
558
|
}
|
|
559
|
+
|
|
560
|
+
/** @public */
|
|
561
|
+
export const safeEstimateRealizedPnl = createSafeFunction(
|
|
562
|
+
'estimateRealizedPnl',
|
|
563
|
+
estimateRealizedPnl
|
|
564
|
+
)
|