@lifi/perps-sdk-provider-hyperliquid 25.0.0 → 27.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/dist/cjs/accountSummary.d.ts.map +1 -1
- package/dist/cjs/accountSummary.js +8 -14
- package/dist/cjs/accountSummary.js.map +1 -1
- package/dist/cjs/services/getAccount.d.ts.map +1 -1
- package/dist/cjs/services/getAccount.js +18 -16
- package/dist/cjs/services/getAccount.js.map +1 -1
- package/dist/cjs/services/getFills.d.ts.map +1 -1
- package/dist/cjs/services/getFills.js +2 -1
- package/dist/cjs/services/getFills.js.map +1 -1
- package/dist/cjs/services/getMarketSettings.d.ts.map +1 -1
- package/dist/cjs/services/getMarketSettings.js +1 -1
- package/dist/cjs/services/getMarketSettings.js.map +1 -1
- package/dist/cjs/services/getOrder.d.ts.map +1 -1
- package/dist/cjs/services/getOrder.js +14 -4
- package/dist/cjs/services/getOrder.js.map +1 -1
- package/dist/cjs/services/getOrders.d.ts.map +1 -1
- package/dist/cjs/services/getOrders.js +8 -28
- package/dist/cjs/services/getOrders.js.map +1 -1
- package/dist/cjs/services/getPortfolioHistory.d.ts.map +1 -1
- package/dist/cjs/services/getPortfolioHistory.js +17 -6
- package/dist/cjs/services/getPortfolioHistory.js.map +1 -1
- package/dist/cjs/services/getPositions.d.ts.map +1 -1
- package/dist/cjs/services/getPositions.js +4 -1
- package/dist/cjs/services/getPositions.js.map +1 -1
- package/dist/cjs/types/ws.d.ts +3 -2
- package/dist/cjs/types/ws.d.ts.map +1 -1
- package/dist/cjs/utils/index.d.ts +1 -1
- package/dist/cjs/utils/index.d.ts.map +1 -1
- package/dist/cjs/utils/index.js +3 -1
- package/dist/cjs/utils/index.js.map +1 -1
- package/dist/cjs/utils/liquidation.d.ts +5 -2
- package/dist/cjs/utils/liquidation.d.ts.map +1 -1
- package/dist/cjs/utils/liquidation.js +8 -8
- package/dist/cjs/utils/liquidation.js.map +1 -1
- package/dist/cjs/utils/mapActivity.d.ts.map +1 -1
- package/dist/cjs/utils/mapActivity.js +38 -23
- package/dist/cjs/utils/mapActivity.js.map +1 -1
- package/dist/cjs/utils/mapFill.d.ts +1 -1
- package/dist/cjs/utils/mapFill.d.ts.map +1 -1
- package/dist/cjs/utils/mapFill.js +17 -6
- package/dist/cjs/utils/mapFill.js.map +1 -1
- package/dist/cjs/utils/mapMarket.d.ts.map +1 -1
- package/dist/cjs/utils/mapMarket.js +9 -13
- package/dist/cjs/utils/mapMarket.js.map +1 -1
- package/dist/cjs/utils/mapMarketContext.d.ts.map +1 -1
- package/dist/cjs/utils/mapMarketContext.js +3 -12
- package/dist/cjs/utils/mapMarketContext.js.map +1 -1
- package/dist/cjs/utils/mapOrder.d.ts +3 -1
- package/dist/cjs/utils/mapOrder.d.ts.map +1 -1
- package/dist/cjs/utils/mapOrder.js +73 -19
- package/dist/cjs/utils/mapOrder.js.map +1 -1
- package/dist/cjs/utils/mapPosition.d.ts +1 -1
- package/dist/cjs/utils/mapPosition.d.ts.map +1 -1
- package/dist/cjs/utils/mapPosition.js +41 -15
- package/dist/cjs/utils/mapPosition.js.map +1 -1
- package/dist/cjs/utils/rowTimestamp.d.ts +2 -0
- package/dist/cjs/utils/rowTimestamp.d.ts.map +1 -0
- package/dist/cjs/utils/rowTimestamp.js +14 -0
- package/dist/cjs/utils/rowTimestamp.js.map +1 -0
- package/dist/cjs/utils/spotBalance.d.ts +3 -3
- package/dist/cjs/utils/spotBalance.d.ts.map +1 -1
- package/dist/cjs/utils/spotBalance.js +6 -5
- package/dist/cjs/utils/spotBalance.js.map +1 -1
- package/dist/cjs/utils/spotCollateral.d.ts.map +1 -1
- package/dist/cjs/utils/spotCollateral.js +3 -2
- package/dist/cjs/utils/spotCollateral.js.map +1 -1
- package/dist/cjs/utils/transferMargin.d.ts.map +1 -1
- package/dist/cjs/utils/transferMargin.js +16 -19
- package/dist/cjs/utils/transferMargin.js.map +1 -1
- package/dist/cjs/utils/venueTotals.d.ts +4 -5
- package/dist/cjs/utils/venueTotals.d.ts.map +1 -1
- package/dist/cjs/utils/venueTotals.js +18 -10
- package/dist/cjs/utils/venueTotals.js.map +1 -1
- package/dist/cjs/utils/withdrawableBalances.d.ts.map +1 -1
- package/dist/cjs/utils/withdrawableBalances.js +10 -10
- package/dist/cjs/utils/withdrawableBalances.js.map +1 -1
- package/dist/cjs/websocket/HyperliquidWsProvider.d.ts +1 -0
- package/dist/cjs/websocket/HyperliquidWsProvider.d.ts.map +1 -1
- package/dist/cjs/websocket/HyperliquidWsProvider.js +144 -115
- package/dist/cjs/websocket/HyperliquidWsProvider.js.map +1 -1
- package/dist/esm/accountSummary.d.ts +2 -1
- package/dist/esm/accountSummary.d.ts.map +1 -1
- package/dist/esm/accountSummary.js +11 -13
- package/dist/esm/accountSummary.js.map +1 -1
- package/dist/esm/services/getAccount.d.ts.map +1 -1
- package/dist/esm/services/getAccount.js +23 -21
- package/dist/esm/services/getAccount.js.map +1 -1
- package/dist/esm/services/getFills.d.ts.map +1 -1
- package/dist/esm/services/getFills.js +2 -1
- package/dist/esm/services/getFills.js.map +1 -1
- package/dist/esm/services/getMarketSettings.d.ts.map +1 -1
- package/dist/esm/services/getMarketSettings.js +2 -2
- package/dist/esm/services/getMarketSettings.js.map +1 -1
- package/dist/esm/services/getOrder.d.ts.map +1 -1
- package/dist/esm/services/getOrder.js +14 -4
- package/dist/esm/services/getOrder.js.map +1 -1
- package/dist/esm/services/getOrders.d.ts.map +1 -1
- package/dist/esm/services/getOrders.js +12 -37
- package/dist/esm/services/getOrders.js.map +1 -1
- package/dist/esm/services/getPortfolioHistory.d.ts.map +1 -1
- package/dist/esm/services/getPortfolioHistory.js +19 -7
- package/dist/esm/services/getPortfolioHistory.js.map +1 -1
- package/dist/esm/services/getPositions.d.ts.map +1 -1
- package/dist/esm/services/getPositions.js +4 -1
- package/dist/esm/services/getPositions.js.map +1 -1
- package/dist/esm/services/getWithdrawableBalances.d.ts +1 -1
- package/dist/esm/services/getWithdrawableBalances.js +1 -1
- package/dist/esm/types/ws.d.ts +3 -2
- package/dist/esm/types/ws.d.ts.map +1 -1
- package/dist/esm/utils/index.d.ts +1 -1
- package/dist/esm/utils/index.d.ts.map +1 -1
- package/dist/esm/utils/index.js +1 -1
- package/dist/esm/utils/index.js.map +1 -1
- package/dist/esm/utils/liquidation.d.ts +23 -24
- package/dist/esm/utils/liquidation.d.ts.map +1 -1
- package/dist/esm/utils/liquidation.js +26 -31
- package/dist/esm/utils/liquidation.js.map +1 -1
- package/dist/esm/utils/mapActivity.d.ts +2 -1
- package/dist/esm/utils/mapActivity.d.ts.map +1 -1
- package/dist/esm/utils/mapActivity.js +41 -22
- package/dist/esm/utils/mapActivity.js.map +1 -1
- package/dist/esm/utils/mapFill.d.ts +3 -2
- package/dist/esm/utils/mapFill.d.ts.map +1 -1
- package/dist/esm/utils/mapFill.js +21 -9
- package/dist/esm/utils/mapFill.js.map +1 -1
- package/dist/esm/utils/mapMarket.d.ts +2 -2
- package/dist/esm/utils/mapMarket.d.ts.map +1 -1
- package/dist/esm/utils/mapMarket.js +12 -13
- package/dist/esm/utils/mapMarket.js.map +1 -1
- package/dist/esm/utils/mapMarketContext.d.ts.map +1 -1
- package/dist/esm/utils/mapMarketContext.js +3 -9
- package/dist/esm/utils/mapMarketContext.js.map +1 -1
- package/dist/esm/utils/mapOrder.d.ts +12 -2
- package/dist/esm/utils/mapOrder.d.ts.map +1 -1
- package/dist/esm/utils/mapOrder.js +81 -17
- package/dist/esm/utils/mapOrder.js.map +1 -1
- package/dist/esm/utils/mapPosition.d.ts +4 -2
- package/dist/esm/utils/mapPosition.d.ts.map +1 -1
- package/dist/esm/utils/mapPosition.js +44 -13
- package/dist/esm/utils/mapPosition.js.map +1 -1
- package/dist/esm/utils/rowTimestamp.d.ts +6 -0
- package/dist/esm/utils/rowTimestamp.d.ts.map +1 -0
- package/dist/esm/utils/rowTimestamp.js +14 -0
- package/dist/esm/utils/rowTimestamp.js.map +1 -0
- package/dist/esm/utils/spotBalance.d.ts +5 -5
- package/dist/esm/utils/spotBalance.d.ts.map +1 -1
- package/dist/esm/utils/spotBalance.js +9 -8
- package/dist/esm/utils/spotBalance.js.map +1 -1
- package/dist/esm/utils/spotCollateral.d.ts.map +1 -1
- package/dist/esm/utils/spotCollateral.js +3 -2
- package/dist/esm/utils/spotCollateral.js.map +1 -1
- package/dist/esm/utils/transferMargin.d.ts +2 -1
- package/dist/esm/utils/transferMargin.d.ts.map +1 -1
- package/dist/esm/utils/transferMargin.js +19 -18
- package/dist/esm/utils/transferMargin.js.map +1 -1
- package/dist/esm/utils/venueTotals.d.ts +7 -6
- package/dist/esm/utils/venueTotals.d.ts.map +1 -1
- package/dist/esm/utils/venueTotals.js +21 -8
- package/dist/esm/utils/venueTotals.js.map +1 -1
- package/dist/esm/utils/withdrawableBalances.d.ts +6 -4
- package/dist/esm/utils/withdrawableBalances.d.ts.map +1 -1
- package/dist/esm/utils/withdrawableBalances.js +17 -15
- package/dist/esm/utils/withdrawableBalances.js.map +1 -1
- package/dist/esm/websocket/HyperliquidWsProvider.d.ts +3 -0
- package/dist/esm/websocket/HyperliquidWsProvider.d.ts.map +1 -1
- package/dist/esm/websocket/HyperliquidWsProvider.js +155 -115
- package/dist/esm/websocket/HyperliquidWsProvider.js.map +1 -1
- package/dist/types/accountSummary.d.ts +2 -1
- package/dist/types/accountSummary.d.ts.map +1 -1
- package/dist/types/services/getAccount.d.ts.map +1 -1
- package/dist/types/services/getFills.d.ts.map +1 -1
- package/dist/types/services/getMarketSettings.d.ts.map +1 -1
- package/dist/types/services/getOrder.d.ts.map +1 -1
- package/dist/types/services/getOrders.d.ts.map +1 -1
- package/dist/types/services/getPortfolioHistory.d.ts.map +1 -1
- package/dist/types/services/getPositions.d.ts.map +1 -1
- package/dist/types/services/getWithdrawableBalances.d.ts +1 -1
- package/dist/types/types/ws.d.ts +3 -2
- package/dist/types/types/ws.d.ts.map +1 -1
- package/dist/types/utils/index.d.ts +1 -1
- package/dist/types/utils/index.d.ts.map +1 -1
- package/dist/types/utils/liquidation.d.ts +23 -24
- package/dist/types/utils/liquidation.d.ts.map +1 -1
- package/dist/types/utils/mapActivity.d.ts +2 -1
- package/dist/types/utils/mapActivity.d.ts.map +1 -1
- package/dist/types/utils/mapFill.d.ts +3 -2
- package/dist/types/utils/mapFill.d.ts.map +1 -1
- package/dist/types/utils/mapMarket.d.ts +2 -2
- package/dist/types/utils/mapMarket.d.ts.map +1 -1
- package/dist/types/utils/mapMarketContext.d.ts.map +1 -1
- package/dist/types/utils/mapOrder.d.ts +12 -2
- package/dist/types/utils/mapOrder.d.ts.map +1 -1
- package/dist/types/utils/mapPosition.d.ts +4 -2
- package/dist/types/utils/mapPosition.d.ts.map +1 -1
- package/dist/types/utils/rowTimestamp.d.ts +6 -0
- package/dist/types/utils/rowTimestamp.d.ts.map +1 -0
- package/dist/types/utils/spotBalance.d.ts +5 -5
- package/dist/types/utils/spotBalance.d.ts.map +1 -1
- package/dist/types/utils/spotCollateral.d.ts.map +1 -1
- package/dist/types/utils/transferMargin.d.ts +2 -1
- package/dist/types/utils/transferMargin.d.ts.map +1 -1
- package/dist/types/utils/venueTotals.d.ts +7 -6
- package/dist/types/utils/venueTotals.d.ts.map +1 -1
- package/dist/types/utils/withdrawableBalances.d.ts +6 -4
- package/dist/types/utils/withdrawableBalances.d.ts.map +1 -1
- package/dist/types/websocket/HyperliquidWsProvider.d.ts +3 -0
- package/dist/types/websocket/HyperliquidWsProvider.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/HyperliquidProvider.ts +1 -1
- package/src/accountSummary.ts +35 -23
- package/src/services/getAccount.ts +50 -33
- package/src/services/getFills.ts +2 -1
- package/src/services/getMarketSettings.ts +6 -2
- package/src/services/getOrder.ts +18 -7
- package/src/services/getOrders.ts +14 -46
- package/src/services/getPortfolioHistory.ts +34 -7
- package/src/services/getPositions.ts +4 -3
- package/src/services/getWithdrawableBalances.ts +1 -1
- package/src/types/ws.ts +3 -2
- package/src/utils/index.ts +2 -0
- package/src/utils/liquidation.ts +46 -34
- package/src/utils/mapActivity.ts +48 -20
- package/src/utils/mapFill.ts +25 -9
- package/src/utils/mapMarket.ts +16 -12
- package/src/utils/mapMarketContext.ts +6 -8
- package/src/utils/mapOrder.ts +107 -20
- package/src/utils/mapPosition.ts +72 -14
- package/src/utils/rowTimestamp.ts +15 -0
- package/src/utils/spotBalance.ts +19 -16
- package/src/utils/spotCollateral.ts +15 -2
- package/src/utils/transferMargin.ts +40 -18
- package/src/utils/venueTotals.ts +51 -17
- package/src/utils/withdrawableBalances.ts +33 -15
- package/src/websocket/HyperliquidWsProvider.ts +224 -133
- package/dist/cjs/utils/decimal.d.ts +0 -3
- package/dist/cjs/utils/decimal.d.ts.map +0 -1
- package/dist/cjs/utils/decimal.js +0 -19
- package/dist/cjs/utils/decimal.js.map +0 -1
- package/dist/esm/utils/decimal.d.ts +0 -10
- package/dist/esm/utils/decimal.d.ts.map +0 -1
- package/dist/esm/utils/decimal.js +0 -19
- package/dist/esm/utils/decimal.js.map +0 -1
- package/dist/types/utils/decimal.d.ts +0 -10
- package/dist/types/utils/decimal.d.ts.map +0 -1
- package/src/utils/decimal.ts +0 -21
package/src/utils/mapOrder.ts
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
createWarnOnce,
|
|
3
|
+
isDecimalString,
|
|
4
|
+
isDecimalStringGreaterThan,
|
|
5
|
+
type MarketRegistry,
|
|
6
|
+
PerpsError,
|
|
7
|
+
safeDivideDecimalString,
|
|
8
|
+
safeIsDecimalStringGreaterThan,
|
|
9
|
+
safeIsDecimalStringZero,
|
|
10
|
+
safeSubtractDecimalString,
|
|
11
|
+
triggerConditionFor,
|
|
12
|
+
warnSkippedVenueRow,
|
|
13
|
+
} from '@lifi/perps-sdk'
|
|
2
14
|
import type {
|
|
3
15
|
MarketDisplay,
|
|
4
16
|
Order,
|
|
@@ -12,13 +24,14 @@ import {
|
|
|
12
24
|
PerpsErrorCode,
|
|
13
25
|
TimeInForce,
|
|
14
26
|
} from '@lifi/perps-types'
|
|
15
|
-
import Big from 'big.js'
|
|
16
27
|
import { PROVIDER_KEY } from '../constants.js'
|
|
17
28
|
import type {
|
|
18
29
|
HlFrontendOpenOrder,
|
|
19
30
|
HlOrderDetail,
|
|
20
31
|
HlTwapHistoryEntry,
|
|
21
32
|
} from '../types/index.js'
|
|
33
|
+
import { assetIsOutcome } from './assetId.js'
|
|
34
|
+
import { rowTimestampToIsoStringOrUndefined } from './rowTimestamp.js'
|
|
22
35
|
|
|
23
36
|
/** Order payload shared by frontend, historical, and single-order reads. */
|
|
24
37
|
export type HlOrderLike = HlFrontendOpenOrder | HlOrderDetail['order']
|
|
@@ -87,28 +100,85 @@ export const mapOrderStatus = (status: string): OrderStatus => {
|
|
|
87
100
|
}
|
|
88
101
|
}
|
|
89
102
|
|
|
103
|
+
const skipOrder = (
|
|
104
|
+
marketId: string,
|
|
105
|
+
field: string,
|
|
106
|
+
value: unknown
|
|
107
|
+
): undefined => {
|
|
108
|
+
warnSkippedVenueRow(PROVIDER_KEY, 'order', field, value, { marketId })
|
|
109
|
+
return undefined
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const warnDroppedRowOnce = createWarnOnce()
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Map one venue row, or drop it. An outcome market identity, a coin the backend
|
|
116
|
+
* market list does not hold, and a row the mapper rejects each drop only their
|
|
117
|
+
* own row; each distinct mapper message warns once.
|
|
118
|
+
*/
|
|
119
|
+
export const mapOrderRow = (
|
|
120
|
+
coin: string,
|
|
121
|
+
registry: MarketRegistry | undefined,
|
|
122
|
+
map: (market: MarketDisplay) => Order | undefined
|
|
123
|
+
): Order | undefined => {
|
|
124
|
+
if (assetIsOutcome(coin)) {
|
|
125
|
+
return undefined
|
|
126
|
+
}
|
|
127
|
+
const market = registry?.get(coin)
|
|
128
|
+
if (market === undefined) {
|
|
129
|
+
return undefined
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
return map(market)
|
|
133
|
+
} catch (error) {
|
|
134
|
+
if (!(error instanceof PerpsError)) {
|
|
135
|
+
throw error
|
|
136
|
+
}
|
|
137
|
+
const message = `[${PROVIDER_KEY}] dropped order row: ${error.message}`
|
|
138
|
+
warnDroppedRowOnce(message, message)
|
|
139
|
+
return undefined
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
90
143
|
function venueError(message: string): PerpsError {
|
|
91
144
|
const error = new PerpsError(PerpsErrorCode.ThirdPartyError, message)
|
|
92
145
|
error.tool = PROVIDER_KEY
|
|
93
146
|
return error
|
|
94
147
|
}
|
|
95
148
|
|
|
96
|
-
/**
|
|
149
|
+
/**
|
|
150
|
+
* Normalize regular, trigger, and TWAP rows through one lifecycle model. A row
|
|
151
|
+
* whose filled or remaining size or timestamp cannot be derived gives `undefined`.
|
|
152
|
+
*/
|
|
97
153
|
export const mapOrder = (
|
|
98
154
|
raw: HlOrderLike | HlOrderDetail | HlTwapHistoryEntry,
|
|
99
155
|
market: MarketDisplay,
|
|
100
156
|
parentOrderId?: string
|
|
101
|
-
): Order => {
|
|
157
|
+
): Order | undefined => {
|
|
102
158
|
if ('state' in raw) {
|
|
103
159
|
if (raw.twapId === undefined) {
|
|
104
160
|
throw venueError('Hyperliquid returned a TWAP without a twapId.')
|
|
105
161
|
}
|
|
106
162
|
const { state } = raw
|
|
107
|
-
const
|
|
163
|
+
const remainingSize = safeSubtractDecimalString(state.sz, state.executedSz)
|
|
164
|
+
if (remainingSize === undefined) {
|
|
165
|
+
return skipOrder(market.id, 'executedSz', state.executedSz)
|
|
166
|
+
}
|
|
167
|
+
const createdAt = rowTimestampToIsoStringOrUndefined(state.timestamp)
|
|
168
|
+
if (createdAt === undefined) {
|
|
169
|
+
return skipOrder(market.id, 'timestamp', state.timestamp)
|
|
170
|
+
}
|
|
171
|
+
const updatedAt = rowTimestampToIsoStringOrUndefined(raw.time * 1000)
|
|
172
|
+
if (updatedAt === undefined) {
|
|
173
|
+
return skipOrder(market.id, 'time', raw.time)
|
|
174
|
+
}
|
|
108
175
|
let status: OrderStatus
|
|
109
176
|
switch (raw.status.status) {
|
|
110
177
|
case 'activated':
|
|
111
|
-
status =
|
|
178
|
+
status =
|
|
179
|
+
safeIsDecimalStringGreaterThan(state.executedSz, '0') === true
|
|
180
|
+
? OrderStatus.PARTIALLY_FILLED
|
|
181
|
+
: OrderStatus.OPEN
|
|
112
182
|
break
|
|
113
183
|
case 'waitingForTrigger':
|
|
114
184
|
status = OrderStatus.OPEN
|
|
@@ -128,35 +198,54 @@ export const mapOrder = (
|
|
|
128
198
|
`Unknown Hyperliquid TWAP status: ${raw.status.status}`
|
|
129
199
|
)
|
|
130
200
|
}
|
|
201
|
+
const averagePrice =
|
|
202
|
+
safeIsDecimalStringZero(state.executedSz) === false
|
|
203
|
+
? safeDivideDecimalString(state.executedNtl, state.executedSz)
|
|
204
|
+
: undefined
|
|
131
205
|
return {
|
|
132
206
|
orderId: String(raw.twapId),
|
|
133
207
|
market,
|
|
134
208
|
type: OrderType.TWAP,
|
|
135
209
|
side: state.side === 'B' ? OrderSide.BUY : OrderSide.SELL,
|
|
136
210
|
originalSize: state.sz,
|
|
137
|
-
remainingSize
|
|
211
|
+
remainingSize,
|
|
138
212
|
filledSize: state.executedSz,
|
|
139
|
-
...(
|
|
140
|
-
? {}
|
|
141
|
-
: { averagePrice: new Big(state.executedNtl).div(filled).toFixed() }),
|
|
213
|
+
...(averagePrice === undefined ? {} : { averagePrice }),
|
|
142
214
|
reduceOnly: state.reduceOnly,
|
|
143
215
|
status,
|
|
144
216
|
...(status === OrderStatus.CANCELLED || status === OrderStatus.REJECTED
|
|
145
217
|
? { statusReason: raw.status.description ?? raw.status.status }
|
|
146
218
|
: {}),
|
|
147
|
-
createdAt
|
|
148
|
-
updatedAt
|
|
149
|
-
startedAt:
|
|
219
|
+
createdAt,
|
|
220
|
+
updatedAt,
|
|
221
|
+
startedAt: createdAt,
|
|
150
222
|
durationSeconds: state.minutes * 60,
|
|
151
223
|
}
|
|
152
224
|
}
|
|
153
225
|
const o = 'order' in raw ? raw.order : raw
|
|
154
226
|
const venueStatus = 'order' in raw ? raw.status : 'open'
|
|
155
|
-
const
|
|
227
|
+
const filledSize = safeSubtractDecimalString(o.origSz, o.sz)
|
|
228
|
+
if (filledSize === undefined) {
|
|
229
|
+
return isDecimalString(o.origSz)
|
|
230
|
+
? skipOrder(market.id, 'sz', o.sz)
|
|
231
|
+
: skipOrder(market.id, 'origSz', o.origSz)
|
|
232
|
+
}
|
|
233
|
+
const createdAt = rowTimestampToIsoStringOrUndefined(o.timestamp)
|
|
234
|
+
if (createdAt === undefined) {
|
|
235
|
+
return skipOrder(market.id, 'timestamp', o.timestamp)
|
|
236
|
+
}
|
|
237
|
+
const statusTimestamp = 'order' in raw ? raw.statusTimestamp : o.timestamp
|
|
238
|
+
const updatedAt = rowTimestampToIsoStringOrUndefined(statusTimestamp)
|
|
239
|
+
if (updatedAt === undefined) {
|
|
240
|
+
return skipOrder(market.id, 'statusTimestamp', statusTimestamp)
|
|
241
|
+
}
|
|
156
242
|
let status = mapOrderStatus(venueStatus)
|
|
157
243
|
if (parentOrderId !== undefined && !('order' in raw)) {
|
|
158
244
|
status = OrderStatus.PENDING
|
|
159
|
-
} else if (
|
|
245
|
+
} else if (
|
|
246
|
+
status === OrderStatus.OPEN &&
|
|
247
|
+
isDecimalStringGreaterThan(filledSize, '0')
|
|
248
|
+
) {
|
|
160
249
|
status = OrderStatus.PARTIALLY_FILLED
|
|
161
250
|
}
|
|
162
251
|
const base: OrderBase = {
|
|
@@ -170,13 +259,11 @@ export const mapOrder = (
|
|
|
170
259
|
: {}),
|
|
171
260
|
originalSize: o.origSz,
|
|
172
261
|
remainingSize: o.sz,
|
|
173
|
-
filledSize
|
|
262
|
+
filledSize,
|
|
174
263
|
reduceOnly: o.reduceOnly,
|
|
175
264
|
...(parentOrderId === undefined ? {} : { parentOrderId }),
|
|
176
|
-
createdAt
|
|
177
|
-
updatedAt
|
|
178
|
-
'order' in raw ? raw.statusTimestamp : o.timestamp
|
|
179
|
-
).toISOString(),
|
|
265
|
+
createdAt,
|
|
266
|
+
updatedAt,
|
|
180
267
|
}
|
|
181
268
|
let type = mapOrderType(o.orderType)
|
|
182
269
|
if (o.isTrigger && (type === OrderType.MARKET || type === OrderType.LIMIT)) {
|
package/src/utils/mapPosition.ts
CHANGED
|
@@ -1,8 +1,32 @@
|
|
|
1
|
+
import {
|
|
2
|
+
absDecimalString,
|
|
3
|
+
createWarnOnce,
|
|
4
|
+
isDecimalString,
|
|
5
|
+
isDecimalStringGreaterThan,
|
|
6
|
+
isDecimalStringZero,
|
|
7
|
+
safeAbsDecimalString,
|
|
8
|
+
safeDivideDecimalString,
|
|
9
|
+
safeIsDecimalStringZero,
|
|
10
|
+
safeNumberToDecimalString,
|
|
11
|
+
safeSubtractDecimalString,
|
|
12
|
+
warnSkippedVenueRow,
|
|
13
|
+
} from '@lifi/perps-sdk'
|
|
1
14
|
import type { PerpsMarketDisplay, Position } from '@lifi/perps-types'
|
|
2
15
|
import { MarginMode, PositionSide } from '@lifi/perps-types'
|
|
3
|
-
import
|
|
16
|
+
import { PROVIDER_KEY } from '../constants.js'
|
|
4
17
|
import type { HlAssetPosition } from '../types/index.js'
|
|
5
18
|
|
|
19
|
+
const warnNonPositiveLeverageOnce = createWarnOnce()
|
|
20
|
+
|
|
21
|
+
const skipPosition = (
|
|
22
|
+
marketId: string,
|
|
23
|
+
field: string,
|
|
24
|
+
value: unknown
|
|
25
|
+
): undefined => {
|
|
26
|
+
warnSkippedVenueRow(PROVIDER_KEY, 'position', field, value, { marketId })
|
|
27
|
+
return undefined
|
|
28
|
+
}
|
|
29
|
+
|
|
6
30
|
/**
|
|
7
31
|
* True when the assetPosition has non-zero size. Hyperliquid keeps zero-size
|
|
8
32
|
* rows in clearinghouse states after a close; both the REST and WS positions
|
|
@@ -10,39 +34,73 @@ import type { HlAssetPosition } from '../types/index.js'
|
|
|
10
34
|
* @public
|
|
11
35
|
*/
|
|
12
36
|
export const isOpenAssetPosition = (ap: HlAssetPosition): boolean =>
|
|
13
|
-
|
|
37
|
+
safeIsDecimalStringZero(ap.position.szi) !== true
|
|
14
38
|
|
|
15
39
|
/**
|
|
16
40
|
* Map a non-zero Hyperliquid position payload to the SDK's normalized
|
|
17
41
|
* position. Signed wire size determines side; decimal strings remain strings
|
|
18
42
|
* in the normalized response. `cumFunding.sinceOpen` is negated because
|
|
19
43
|
* Hyperliquid signs funding paid as positive and `accruedFunding` signs it as
|
|
20
|
-
* negative.
|
|
44
|
+
* negative. A row with an invalid size gives `undefined`; an invalid position
|
|
45
|
+
* value, a non-positive leverage or an invalid funding leaves the derived field
|
|
46
|
+
* absent.
|
|
21
47
|
* @public
|
|
22
48
|
*/
|
|
23
49
|
export const mapPosition = (
|
|
24
50
|
ap: HlAssetPosition,
|
|
25
51
|
market: PerpsMarketDisplay
|
|
26
|
-
): Position => {
|
|
52
|
+
): Position | undefined => {
|
|
27
53
|
const pos = ap.position
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
54
|
+
if (!isDecimalString(pos.szi)) {
|
|
55
|
+
return skipPosition(market.id, 'szi', pos.szi)
|
|
56
|
+
}
|
|
57
|
+
const size = absDecimalString(pos.szi)
|
|
58
|
+
const positionValue = safeAbsDecimalString(pos.positionValue)
|
|
59
|
+
const markPrice =
|
|
60
|
+
positionValue === undefined
|
|
61
|
+
? undefined
|
|
62
|
+
: isDecimalStringZero(size)
|
|
63
|
+
? '0'
|
|
64
|
+
: safeDivideDecimalString(positionValue, size)
|
|
65
|
+
const accruedFunding = safeSubtractDecimalString(
|
|
66
|
+
'0',
|
|
67
|
+
pos.cumFunding.sinceOpen
|
|
68
|
+
)
|
|
69
|
+
const venueLeverage = safeNumberToDecimalString(pos.leverage.value)
|
|
70
|
+
const leverage =
|
|
71
|
+
venueLeverage !== undefined &&
|
|
72
|
+
isDecimalStringGreaterThan(venueLeverage, '0')
|
|
73
|
+
? venueLeverage
|
|
74
|
+
: undefined
|
|
75
|
+
if (venueLeverage !== undefined && leverage === undefined) {
|
|
76
|
+
warnNonPositiveLeverageOnce(
|
|
77
|
+
venueLeverage,
|
|
78
|
+
`[${PROVIDER_KEY}] position \`leverage.value\` is not positive: '${venueLeverage}'`
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
const initialMarginRequirement =
|
|
82
|
+
positionValue === undefined || leverage === undefined
|
|
83
|
+
? undefined
|
|
84
|
+
: safeDivideDecimalString(positionValue, leverage)
|
|
31
85
|
const marginMode =
|
|
32
86
|
pos.leverage.type === 'cross' ? MarginMode.CROSS : MarginMode.ISOLATED
|
|
33
87
|
|
|
34
88
|
return {
|
|
35
89
|
market,
|
|
36
|
-
side:
|
|
37
|
-
|
|
90
|
+
side: isDecimalStringGreaterThan('0', pos.szi)
|
|
91
|
+
? PositionSide.SHORT
|
|
92
|
+
: PositionSide.LONG,
|
|
93
|
+
size,
|
|
38
94
|
entryPrice: pos.entryPx ?? '0',
|
|
39
|
-
markPrice
|
|
40
|
-
liquidationPrice: pos.liquidationPx
|
|
95
|
+
...(markPrice === undefined ? {} : { markPrice }),
|
|
96
|
+
liquidationPrice: pos.liquidationPx || '0',
|
|
41
97
|
unrealizedPnl: pos.unrealizedPnl,
|
|
42
|
-
accruedFunding:
|
|
43
|
-
leverage:
|
|
98
|
+
...(accruedFunding === undefined ? {} : { accruedFunding }),
|
|
99
|
+
...(leverage === undefined ? {} : { leverage }),
|
|
44
100
|
marginUsed: pos.marginUsed,
|
|
45
|
-
initialMarginRequirement
|
|
101
|
+
...(initialMarginRequirement === undefined
|
|
102
|
+
? {}
|
|
103
|
+
: { initialMarginRequirement }),
|
|
46
104
|
marginMode,
|
|
47
105
|
}
|
|
48
106
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { timestampToIsoString } from '@lifi/perps-sdk'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Read a venue row time as an ISO-8601 string, or `undefined` when the time is
|
|
5
|
+
* not valid. The caller logs the row skip, so this logs nothing.
|
|
6
|
+
*/
|
|
7
|
+
export const rowTimestampToIsoStringOrUndefined = (
|
|
8
|
+
value: string | number
|
|
9
|
+
): string | undefined => {
|
|
10
|
+
try {
|
|
11
|
+
return timestampToIsoString(value)
|
|
12
|
+
} catch {
|
|
13
|
+
return undefined
|
|
14
|
+
}
|
|
15
|
+
}
|
package/src/utils/spotBalance.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
isDecimalString,
|
|
3
|
+
isDecimalStringGreaterThan,
|
|
4
|
+
multiplyDecimalString,
|
|
5
|
+
} from '@lifi/perps-sdk'
|
|
6
|
+
import type { Asset, Balance, DecimalString, Market } from '@lifi/perps-types'
|
|
3
7
|
import { SPOT_MARKET_ID } from '../constants.js'
|
|
4
8
|
import type { HlSpotBalance } from '../types/index.js'
|
|
5
9
|
import { spotLogoURI } from './assetLogo.js'
|
|
@@ -7,23 +11,24 @@ import { coinAsset } from './marketDisplay.js'
|
|
|
7
11
|
|
|
8
12
|
/**
|
|
9
13
|
* Build USD prices keyed by spot token asset ID. Base tokens use the supplied
|
|
10
|
-
* market mark price; quote tokens default to exactly `$1`; missing
|
|
11
|
-
* default to `0`.
|
|
14
|
+
* market mark price; quote tokens default to exactly `$1`; missing or invalid
|
|
15
|
+
* base prices default to `0`.
|
|
12
16
|
* @public
|
|
13
17
|
*/
|
|
14
18
|
export const spotPriceById = (
|
|
15
19
|
markets: readonly Market[],
|
|
16
|
-
priceByMarketId: ReadonlyMap<string,
|
|
17
|
-
): Map<string,
|
|
18
|
-
const map = new Map<string,
|
|
20
|
+
priceByMarketId: ReadonlyMap<string, DecimalString>
|
|
21
|
+
): Map<string, DecimalString> => {
|
|
22
|
+
const map = new Map<string, DecimalString>()
|
|
19
23
|
for (const m of markets) {
|
|
20
24
|
if (m.categoryId === SPOT_MARKET_ID) {
|
|
21
|
-
|
|
25
|
+
const price = priceByMarketId.get(m.id)
|
|
26
|
+
map.set(m.baseAsset.id, isDecimalString(price) ? price : '0')
|
|
22
27
|
}
|
|
23
28
|
}
|
|
24
29
|
for (const m of markets) {
|
|
25
30
|
if (!map.has(m.quoteAsset.id)) {
|
|
26
|
-
map.set(m.quoteAsset.id, 1)
|
|
31
|
+
map.set(m.quoteAsset.id, '1')
|
|
27
32
|
}
|
|
28
33
|
}
|
|
29
34
|
return map
|
|
@@ -44,18 +49,16 @@ export const spotAssetFromToken = (b: HlSpotBalance): Asset => ({
|
|
|
44
49
|
/** Assemble a typed spot {@link Balance}; `total` is native token units and its unit price and USD value use `priceById`. @public */
|
|
45
50
|
export const spotBalance = (
|
|
46
51
|
asset: Asset,
|
|
47
|
-
total:
|
|
48
|
-
priceById:
|
|
52
|
+
total: DecimalString,
|
|
53
|
+
priceById: ReadonlyMap<string, DecimalString>
|
|
49
54
|
): Balance => {
|
|
50
|
-
const price = priceById.get(asset.id) ?? 0
|
|
55
|
+
const price = priceById.get(asset.id) ?? '0'
|
|
51
56
|
return {
|
|
52
57
|
categoryId: SPOT_MARKET_ID,
|
|
53
58
|
asset,
|
|
54
59
|
units: total,
|
|
55
|
-
valueUsd:
|
|
56
|
-
(parseDecimal(total) ?? Number.NaN) * price
|
|
57
|
-
),
|
|
60
|
+
valueUsd: multiplyDecimalString(total, price),
|
|
58
61
|
// A zero entry means the map holds no mark for the asset, not a free asset.
|
|
59
|
-
...(price
|
|
62
|
+
...(isDecimalStringGreaterThan(price, '0') ? { price } : {}),
|
|
60
63
|
}
|
|
61
64
|
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isDecimalStringGreaterThan,
|
|
3
|
+
unknownToDecimalString,
|
|
4
|
+
} from '@lifi/perps-sdk'
|
|
1
5
|
import type { Balance } from '@lifi/perps-types'
|
|
2
|
-
import {
|
|
6
|
+
import { PROVIDER_KEY } from '../constants.js'
|
|
3
7
|
|
|
4
8
|
/**
|
|
5
9
|
* Result of {@link partitionSpotBalances}: balances that count toward
|
|
@@ -24,7 +28,16 @@ export const partitionSpotBalances = (
|
|
|
24
28
|
const collateralBalances: Balance[] = []
|
|
25
29
|
const balances: Balance[] = []
|
|
26
30
|
for (const balance of spotBalances) {
|
|
27
|
-
if (
|
|
31
|
+
if (
|
|
32
|
+
!isDecimalStringGreaterThan(
|
|
33
|
+
unknownToDecimalString(
|
|
34
|
+
balance.units,
|
|
35
|
+
'spotBalance.units',
|
|
36
|
+
PROVIDER_KEY
|
|
37
|
+
),
|
|
38
|
+
'0'
|
|
39
|
+
)
|
|
40
|
+
) {
|
|
28
41
|
continue
|
|
29
42
|
}
|
|
30
43
|
if (quoteAssetIds.has(balance.asset.id)) {
|
|
@@ -1,32 +1,49 @@
|
|
|
1
1
|
import {
|
|
2
|
+
isDecimalString,
|
|
3
|
+
isDecimalStringGreaterThan,
|
|
4
|
+
multiplyDecimalString,
|
|
2
5
|
PerpsError,
|
|
3
6
|
positionSupportsMarginAdjustment,
|
|
4
7
|
positionSupportsMarginRemoval,
|
|
5
|
-
|
|
8
|
+
roundDecimalString,
|
|
9
|
+
subtractDecimalString,
|
|
6
10
|
} from '@lifi/perps-sdk'
|
|
7
11
|
import {
|
|
8
12
|
type DecimalString,
|
|
9
13
|
PerpsErrorCode,
|
|
10
14
|
type Position,
|
|
11
15
|
} from '@lifi/perps-types'
|
|
12
|
-
import Big from 'big.js'
|
|
13
16
|
|
|
14
17
|
const NOTIONAL_FLOOR_RATIO = '0.1'
|
|
15
18
|
const AMOUNT_DECIMALS = 6
|
|
16
19
|
|
|
17
|
-
function
|
|
18
|
-
|
|
20
|
+
function requirePositionAmount(
|
|
21
|
+
value: DecimalString,
|
|
22
|
+
field: string
|
|
23
|
+
): DecimalString {
|
|
24
|
+
if (!isDecimalString(value)) {
|
|
25
|
+
throw new PerpsError(
|
|
26
|
+
PerpsErrorCode.ValidationError,
|
|
27
|
+
`Invalid \`Position.${field}\`: '${value}' does not match the decimal pattern.`
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
return value
|
|
19
31
|
}
|
|
20
32
|
|
|
21
|
-
function
|
|
22
|
-
|
|
23
|
-
|
|
33
|
+
function requirePositivePositionAmount(
|
|
34
|
+
value: DecimalString | undefined,
|
|
35
|
+
field: string
|
|
36
|
+
): DecimalString {
|
|
37
|
+
if (
|
|
38
|
+
value === undefined ||
|
|
39
|
+
!isDecimalStringGreaterThan(requirePositionAmount(value, field), '0')
|
|
40
|
+
) {
|
|
24
41
|
throw new PerpsError(
|
|
25
42
|
PerpsErrorCode.ValidationError,
|
|
26
43
|
`Position.${field} must be greater than zero.`
|
|
27
44
|
)
|
|
28
45
|
}
|
|
29
|
-
return
|
|
46
|
+
return value
|
|
30
47
|
}
|
|
31
48
|
|
|
32
49
|
/**
|
|
@@ -40,7 +57,8 @@ function positivePositionAmount(value: DecimalString, field: string): Big {
|
|
|
40
57
|
* margin adjustment; `'0'` for add-only strict-isolated markets and when
|
|
41
58
|
* nothing is removable.
|
|
42
59
|
* @throws {PerpsError} `ValidationError` when a required `Position` decimal
|
|
43
|
-
* is malformed, or when a size, price or requirement is not
|
|
60
|
+
* is absent or malformed, or when a size, price or requirement is not
|
|
61
|
+
* positive.
|
|
44
62
|
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/trading/margining
|
|
45
63
|
* @public
|
|
46
64
|
*/
|
|
@@ -53,21 +71,25 @@ export function positionRemovableMargin(
|
|
|
53
71
|
if (!positionSupportsMarginRemoval(position)) {
|
|
54
72
|
return '0'
|
|
55
73
|
}
|
|
56
|
-
const marginUsed =
|
|
57
|
-
const initialMargin =
|
|
74
|
+
const marginUsed = requirePositionAmount(position.marginUsed, 'marginUsed')
|
|
75
|
+
const initialMargin = requirePositivePositionAmount(
|
|
58
76
|
position.initialMarginRequirement,
|
|
59
77
|
'initialMarginRequirement'
|
|
60
78
|
)
|
|
61
|
-
const notionalFloor =
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
79
|
+
const notionalFloor = multiplyDecimalString(
|
|
80
|
+
multiplyDecimalString(
|
|
81
|
+
requirePositivePositionAmount(position.size, 'size'),
|
|
82
|
+
requirePositivePositionAmount(position.markPrice, 'markPrice')
|
|
83
|
+
),
|
|
84
|
+
NOTIONAL_FLOOR_RATIO
|
|
85
|
+
)
|
|
86
|
+
const minimumMargin = isDecimalStringGreaterThan(initialMargin, notionalFloor)
|
|
65
87
|
? initialMargin
|
|
66
88
|
: notionalFloor
|
|
67
89
|
|
|
68
|
-
const removable = marginUsed
|
|
69
|
-
if (removable
|
|
90
|
+
const removable = subtractDecimalString(marginUsed, minimumMargin)
|
|
91
|
+
if (!isDecimalStringGreaterThan(removable, '0')) {
|
|
70
92
|
return '0'
|
|
71
93
|
}
|
|
72
|
-
return removable
|
|
94
|
+
return roundDecimalString(removable, AMOUNT_DECIMALS, 'truncate')
|
|
73
95
|
}
|
package/src/utils/venueTotals.ts
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
addDecimalString,
|
|
3
|
+
addDecimalStrings,
|
|
4
|
+
createWarnOnce,
|
|
5
|
+
isDecimalString,
|
|
6
|
+
unknownToDecimalString,
|
|
7
|
+
} from '@lifi/perps-sdk'
|
|
8
|
+
import type {
|
|
9
|
+
DecimalString,
|
|
10
|
+
HyperliquidMarginSummary,
|
|
11
|
+
Position,
|
|
12
|
+
} from '@lifi/perps-types'
|
|
13
|
+
import { PROVIDER_KEY } from '../constants.js'
|
|
4
14
|
|
|
5
15
|
/**
|
|
6
16
|
* One perps sub-dex entry {@link perpsTotals} reads. The REST response always
|
|
@@ -15,34 +25,58 @@ export interface DexMarginSummary {
|
|
|
15
25
|
* Sum the venue `marginSummary` totals over every perps sub-dex of an
|
|
16
26
|
* account. `accountValue` is total equity, so it already carries locked
|
|
17
27
|
* margin and unrealized PnL. An entry without a `marginSummary` adds nothing.
|
|
28
|
+
* @throws {PerpsError} `SDKError` when a venue figure is not a decimal.
|
|
18
29
|
* @public
|
|
19
30
|
*/
|
|
20
31
|
export const perpsTotals = (
|
|
21
32
|
dexStates: readonly DexMarginSummary[]
|
|
22
|
-
): { accountValue:
|
|
23
|
-
let accountValue =
|
|
24
|
-
let marginUsed =
|
|
33
|
+
): { accountValue: DecimalString; marginUsed: DecimalString } => {
|
|
34
|
+
let accountValue = '0'
|
|
35
|
+
let marginUsed = '0'
|
|
25
36
|
for (const { marginSummary } of dexStates) {
|
|
26
37
|
if (marginSummary === undefined) {
|
|
27
38
|
continue
|
|
28
39
|
}
|
|
29
|
-
accountValue =
|
|
30
|
-
|
|
40
|
+
accountValue = addDecimalString(
|
|
41
|
+
accountValue,
|
|
42
|
+
unknownToDecimalString(
|
|
43
|
+
marginSummary.accountValue,
|
|
44
|
+
'marginSummary.accountValue',
|
|
45
|
+
PROVIDER_KEY
|
|
46
|
+
)
|
|
31
47
|
)
|
|
32
|
-
marginUsed =
|
|
33
|
-
|
|
48
|
+
marginUsed = addDecimalString(
|
|
49
|
+
marginUsed,
|
|
50
|
+
unknownToDecimalString(
|
|
51
|
+
marginSummary.totalMarginUsed,
|
|
52
|
+
'marginSummary.totalMarginUsed',
|
|
53
|
+
PROVIDER_KEY
|
|
54
|
+
)
|
|
34
55
|
)
|
|
35
56
|
}
|
|
36
57
|
return { accountValue, marginUsed }
|
|
37
58
|
}
|
|
38
59
|
|
|
60
|
+
const warnSkippedTermOnce = createWarnOnce()
|
|
61
|
+
|
|
39
62
|
/**
|
|
40
|
-
* Sum the unrealized PnL of every position, in quote-asset units.
|
|
63
|
+
* Sum the unrealized PnL of every position, in quote-asset units. A term that
|
|
64
|
+
* does not match the decimal pattern adds nothing and warns once.
|
|
41
65
|
* @public
|
|
42
66
|
*/
|
|
43
|
-
export const sumUnrealizedPnl = (
|
|
44
|
-
positions
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
67
|
+
export const sumUnrealizedPnl = (
|
|
68
|
+
positions: readonly Position[]
|
|
69
|
+
): DecimalString => {
|
|
70
|
+
const terms: DecimalString[] = []
|
|
71
|
+
for (const { unrealizedPnl } of positions) {
|
|
72
|
+
if (isDecimalString(unrealizedPnl)) {
|
|
73
|
+
terms.push(unrealizedPnl)
|
|
74
|
+
continue
|
|
75
|
+
}
|
|
76
|
+
warnSkippedTermOnce(
|
|
77
|
+
`${PROVIDER_KEY}|position.unrealizedPnl`,
|
|
78
|
+
`[${PROVIDER_KEY}] skipping a \`position.unrealizedPnl\` term that does not match the decimal pattern: '${String(unrealizedPnl).slice(0, 64)}'`
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
return addDecimalStrings(terms)
|
|
82
|
+
}
|