@lifi/perps-sdk 0.0.0-preview-050dcd3 → 0.0.0-preview-ef23ec2

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.
Files changed (88) hide show
  1. package/README.md +7 -5
  2. package/dist/cjs/client/PerpsClient.d.ts +8 -3
  3. package/dist/cjs/client/PerpsClient.d.ts.map +1 -1
  4. package/dist/cjs/client/PerpsClient.js +15 -0
  5. package/dist/cjs/client/PerpsClient.js.map +1 -1
  6. package/dist/cjs/index.d.ts +4 -4
  7. package/dist/cjs/index.d.ts.map +1 -1
  8. package/dist/cjs/index.js +6 -2
  9. package/dist/cjs/index.js.map +1 -1
  10. package/dist/cjs/services/getOrders.d.ts +2 -1
  11. package/dist/cjs/services/getOrders.d.ts.map +1 -1
  12. package/dist/cjs/services/getOrders.js +2 -0
  13. package/dist/cjs/services/getOrders.js.map +1 -1
  14. package/dist/cjs/types/api.d.ts +6 -1
  15. package/dist/cjs/types/api.d.ts.map +1 -1
  16. package/dist/cjs/types/provider.d.ts +7 -6
  17. package/dist/cjs/types/provider.d.ts.map +1 -1
  18. package/dist/cjs/utils/orderClassification.d.ts +9 -5
  19. package/dist/cjs/utils/orderClassification.d.ts.map +1 -1
  20. package/dist/cjs/utils/orderClassification.js +19 -0
  21. package/dist/cjs/utils/orderClassification.js.map +1 -1
  22. package/dist/cjs/utils/orderMath.d.ts +2 -2
  23. package/dist/cjs/utils/orderMath.d.ts.map +1 -1
  24. package/dist/cjs/utils/orderMath.js +15 -4
  25. package/dist/cjs/utils/orderMath.js.map +1 -1
  26. package/dist/cjs/version.d.ts +1 -1
  27. package/dist/cjs/version.js +1 -1
  28. package/dist/cjs/websocket/PerpsWsClient.d.ts +7 -2
  29. package/dist/cjs/websocket/PerpsWsClient.d.ts.map +1 -1
  30. package/dist/cjs/websocket/PerpsWsClient.js +3 -0
  31. package/dist/cjs/websocket/PerpsWsClient.js.map +1 -1
  32. package/dist/esm/client/PerpsClient.d.ts +18 -3
  33. package/dist/esm/client/PerpsClient.d.ts.map +1 -1
  34. package/dist/esm/client/PerpsClient.js +25 -0
  35. package/dist/esm/client/PerpsClient.js.map +1 -1
  36. package/dist/esm/index.d.ts +4 -4
  37. package/dist/esm/index.d.ts.map +1 -1
  38. package/dist/esm/index.js +1 -1
  39. package/dist/esm/index.js.map +1 -1
  40. package/dist/esm/services/getOrders.d.ts +3 -17
  41. package/dist/esm/services/getOrders.d.ts.map +1 -1
  42. package/dist/esm/services/getOrders.js +3 -16
  43. package/dist/esm/services/getOrders.js.map +1 -1
  44. package/dist/esm/types/api.d.ts +13 -3
  45. package/dist/esm/types/api.d.ts.map +1 -1
  46. package/dist/esm/types/provider.d.ts +16 -16
  47. package/dist/esm/types/provider.d.ts.map +1 -1
  48. package/dist/esm/utils/orderClassification.d.ts +14 -19
  49. package/dist/esm/utils/orderClassification.d.ts.map +1 -1
  50. package/dist/esm/utils/orderClassification.js +21 -15
  51. package/dist/esm/utils/orderClassification.js.map +1 -1
  52. package/dist/esm/utils/orderMath.d.ts +3 -13
  53. package/dist/esm/utils/orderMath.d.ts.map +1 -1
  54. package/dist/esm/utils/orderMath.js +17 -16
  55. package/dist/esm/utils/orderMath.js.map +1 -1
  56. package/dist/esm/version.d.ts +1 -1
  57. package/dist/esm/version.js +1 -1
  58. package/dist/esm/websocket/PerpsWsClient.d.ts +25 -6
  59. package/dist/esm/websocket/PerpsWsClient.d.ts.map +1 -1
  60. package/dist/esm/websocket/PerpsWsClient.js +13 -2
  61. package/dist/esm/websocket/PerpsWsClient.js.map +1 -1
  62. package/dist/types/client/PerpsClient.d.ts +18 -3
  63. package/dist/types/client/PerpsClient.d.ts.map +1 -1
  64. package/dist/types/index.d.ts +4 -4
  65. package/dist/types/index.d.ts.map +1 -1
  66. package/dist/types/services/getOrders.d.ts +3 -17
  67. package/dist/types/services/getOrders.d.ts.map +1 -1
  68. package/dist/types/types/api.d.ts +13 -3
  69. package/dist/types/types/api.d.ts.map +1 -1
  70. package/dist/types/types/provider.d.ts +16 -16
  71. package/dist/types/types/provider.d.ts.map +1 -1
  72. package/dist/types/utils/orderClassification.d.ts +14 -19
  73. package/dist/types/utils/orderClassification.d.ts.map +1 -1
  74. package/dist/types/utils/orderMath.d.ts +3 -13
  75. package/dist/types/utils/orderMath.d.ts.map +1 -1
  76. package/dist/types/version.d.ts +1 -1
  77. package/dist/types/websocket/PerpsWsClient.d.ts +25 -6
  78. package/dist/types/websocket/PerpsWsClient.d.ts.map +1 -1
  79. package/package.json +2 -2
  80. package/src/client/PerpsClient.ts +58 -1
  81. package/src/index.ts +7 -1
  82. package/src/services/getOrders.ts +5 -17
  83. package/src/types/api.ts +14 -2
  84. package/src/types/provider.ts +23 -21
  85. package/src/utils/orderClassification.ts +37 -19
  86. package/src/utils/orderMath.ts +25 -17
  87. package/src/version.ts +1 -1
  88. package/src/websocket/PerpsWsClient.ts +29 -6
package/src/types/api.ts CHANGED
@@ -14,6 +14,7 @@ import type {
14
14
  OnboardParams,
15
15
  OrderSide,
16
16
  OrderType,
17
+ PortfolioHistoryRange,
17
18
  ProviderAction,
18
19
  SignedActionStep,
19
20
  TimeInForce,
@@ -175,8 +176,8 @@ export interface PlaceOrderParams {
175
176
  }
176
177
 
177
178
  /**
178
- * Parameters for placing trigger-only orders (TP/SL on existing positions).
179
- * Sends a TRIGGER_ONLY order that skips the main order wire.
179
+ * Sends `ActionType.PLACE_TRIGGER_ORDER` with
180
+ * `{ market, side, takeProfit?, stopLoss? }`.
180
181
  *
181
182
  * @public
182
183
  */
@@ -298,6 +299,17 @@ export interface GetWithdrawableBalancesParams {
298
299
  address: Address
299
300
  }
300
301
 
302
+ /**
303
+ * Parameters for {@link PerpsClient.getPortfolioHistory}.
304
+ *
305
+ * @public
306
+ */
307
+ export interface GetPortfolioHistoryParams {
308
+ provider: string
309
+ address: Address
310
+ range: PortfolioHistoryRange
311
+ }
312
+
301
313
  /**
302
314
  * One entry on {@link ProviderSetup.checklist}: a user-facing setup
303
315
  * descriptor plus its satisfied state for the queried account.
@@ -13,9 +13,12 @@ import type {
13
13
  MarketRef,
14
14
  MarketSettings,
15
15
  Order,
16
+ OrderStatus,
16
17
  OrdersResponse,
17
18
  PerpsMarket,
18
19
  PerpsSigner,
20
+ PortfolioHistoryRange,
21
+ PortfolioHistoryResponse,
19
22
  Position,
20
23
  PositionMarginConstraints,
21
24
  PositionsResponse,
@@ -25,7 +28,6 @@ import type {
25
28
  SignedActionStep,
26
29
  SigningMethod,
27
30
  TradeType,
28
- TwapOrder,
29
31
  } from '@lifi/perps-types'
30
32
  import type { Address } from 'viem'
31
33
  import type {
@@ -221,6 +223,7 @@ export interface ProviderGetMarketSettingsParams {
221
223
  */
222
224
  export interface ProviderGetOrdersParams {
223
225
  address: Address
226
+ statuses?: OrderStatus[]
224
227
  /** Optional opaque `Market.id` filter (not a display symbol). */
225
228
  marketId?: string
226
229
  /** Maximum items returned; provider defaults and caps apply. */
@@ -229,17 +232,6 @@ export interface ProviderGetOrdersParams {
229
232
  cursor?: string
230
233
  }
231
234
 
232
- /**
233
- * Read params for {@link PerpsProvider.getRunningTwaps}.
234
- *
235
- * @public
236
- */
237
- export interface ProviderGetRunningTwapsParams {
238
- address: Address
239
- /** Optional opaque `Market.id` filter (not a display symbol). */
240
- marketId?: string
241
- }
242
-
243
235
  /**
244
236
  * Read params for {@link PerpsProvider.getOrder}.
245
237
  *
@@ -287,6 +279,16 @@ export interface ProviderGetActivityParams {
287
279
  type?: ActivityType[]
288
280
  }
289
281
 
282
+ /**
283
+ * Read params for {@link PerpsProvider.getPortfolioHistory}.
284
+ *
285
+ * @public
286
+ */
287
+ export interface ProviderGetPortfolioHistoryParams {
288
+ address: Address
289
+ range: PortfolioHistoryRange
290
+ }
291
+
290
292
  /**
291
293
  * Read params for {@link PerpsProviderPlugin.getQuote}. `provider` is implicit
292
294
  * in the provider instance and so is not duplicated here.
@@ -445,15 +447,6 @@ export interface PerpsProviderPlugin {
445
447
  options?: SDKRequestOptions
446
448
  ): Promise<OrdersResponse>
447
449
 
448
- /**
449
- * Fetch the account's currently running TWAP parent orders directly from the
450
- * venue. Child slice orders are excluded.
451
- */
452
- getRunningTwaps?(
453
- params: ProviderGetRunningTwapsParams,
454
- options?: SDKRequestOptions
455
- ): Promise<TwapOrder[]>
456
-
457
450
  getOrder(
458
451
  params: ProviderGetOrderParams,
459
452
  options?: SDKRequestOptions
@@ -469,6 +462,15 @@ export interface PerpsProviderPlugin {
469
462
  options?: SDKRequestOptions
470
463
  ): Promise<ActivitiesResponse>
471
464
 
465
+ /**
466
+ * Read the account's portfolio value and cumulative PnL over
467
+ * `params.range`, oldest point first, directly from the venue.
468
+ */
469
+ getPortfolioHistory?(
470
+ params: ProviderGetPortfolioHistoryParams,
471
+ options?: SDKRequestOptions
472
+ ): Promise<PortfolioHistoryResponse>
473
+
472
474
  /**
473
475
  * Produce a one-shot fill {@link Quote} for `params.symbol` at `params.size`
474
476
  * USD notional on this venue. The provider resolves the symbol against its
@@ -1,17 +1,15 @@
1
- /**
2
- * Order classification utilities.
3
- *
4
- * Type guards and classifiers that operate on SDK types to determine
5
- * order categories (TP/SL, open/close). These use the OrderType enum
6
- * for classification — no string matching.
7
- */
8
-
9
- import type { OpenOrder } from '@lifi/perps-types'
1
+ import type {
2
+ Order,
3
+ RegularOrder,
4
+ TriggerOrder,
5
+ TwapOrder,
6
+ } from '@lifi/perps-types'
10
7
  import {
11
8
  FillClassification,
12
9
  OrderSide,
13
10
  OrderStatus,
14
11
  OrderType,
12
+ TriggerCondition,
15
13
  } from '@lifi/perps-types'
16
14
  import { stringToFloat } from './parse.js'
17
15
 
@@ -36,7 +34,7 @@ const SL_TYPES = new Set<OrderType>([
36
34
  * Check if an open order is a Take Profit trigger order.
37
35
  * @public
38
36
  */
39
- export function isTakeProfitOrder(order: Pick<OpenOrder, 'type'>): boolean {
37
+ export function isTakeProfitOrder(order: Pick<Order, 'type'>): boolean {
40
38
  return TP_TYPES.has(order.type)
41
39
  }
42
40
 
@@ -44,7 +42,7 @@ export function isTakeProfitOrder(order: Pick<OpenOrder, 'type'>): boolean {
44
42
  * Check if an open order is a Stop Loss trigger order.
45
43
  * @public
46
44
  */
47
- export function isStopLossOrder(order: Pick<OpenOrder, 'type'>): boolean {
45
+ export function isStopLossOrder(order: Pick<Order, 'type'>): boolean {
48
46
  return SL_TYPES.has(order.type)
49
47
  }
50
48
 
@@ -52,17 +50,37 @@ export function isStopLossOrder(order: Pick<OpenOrder, 'type'>): boolean {
52
50
  * Check if an open order is a TP or SL trigger order.
53
51
  * @public
54
52
  */
55
- export function isTpSlOrder(order: Pick<OpenOrder, 'type'>): boolean {
53
+ export function isTpSlOrder(order: Pick<Order, 'type'>): boolean {
56
54
  return TP_TYPES.has(order.type) || SL_TYPES.has(order.type)
57
55
  }
58
56
 
59
- /**
60
- * Order statuses representing an order still resting on the book (visible
61
- * in `openOrders` / `triggerOrders`). Anything not in this set is terminal —
62
- * filled, cancelled, rejected, expired — and should be evicted from the
63
- * cached orders list when seen in a WS update.
64
- * @public
65
- */
57
+ /** Narrow an order to a price-activated order. */
58
+ export function isTriggerOrder(order: Order): order is TriggerOrder {
59
+ return isTpSlOrder(order)
60
+ }
61
+
62
+ /** Narrow an order to a market or limit order. */
63
+ export function isRegularOrder(order: Order): order is RegularOrder {
64
+ return order.type === OrderType.MARKET || order.type === OrderType.LIMIT
65
+ }
66
+
67
+ /** Narrow an order to a time-weighted execution parent. */
68
+ export function isTwapOrder(order: Order): order is TwapOrder {
69
+ return order.type === OrderType.TWAP
70
+ }
71
+
72
+ /** Derive the trigger price relation from the trigger type and execution side. */
73
+ export function triggerConditionFor(
74
+ type: TriggerOrder['type'],
75
+ side: OrderSide
76
+ ): TriggerCondition {
77
+ const takeProfit = TP_TYPES.has(type)
78
+ return takeProfit === (side === OrderSide.SELL)
79
+ ? TriggerCondition.ABOVE
80
+ : TriggerCondition.BELOW
81
+ }
82
+
83
+ /** Lifecycle statuses included in order reads by default. */
66
84
  export const ACTIVE_ORDER_STATUSES: ReadonlySet<OrderStatus> = new Set([
67
85
  OrderStatus.OPEN,
68
86
  OrderStatus.PENDING,
@@ -1,10 +1,12 @@
1
1
  import {
2
- type OpenOrder,
3
2
  OrderSide,
3
+ OrderStatus,
4
4
  type Position,
5
5
  PositionSide,
6
+ type RegularOrder,
6
7
  type TriggerOrder,
7
8
  } from '@lifi/perps-types'
9
+ import { isActiveOrderStatus } from './orderClassification.js'
8
10
  import { realizedPnlOnClose } from './positionMath.js'
9
11
 
10
12
  /**
@@ -55,10 +57,10 @@ export function resolveCloseSize(
55
57
  * @public
56
58
  */
57
59
  export function expectedRealizedPnlForOpenOrder(
58
- order: OpenOrder,
60
+ order: RegularOrder,
59
61
  position: Position | undefined
60
62
  ): number | null {
61
- if (!position) {
63
+ if (!position || !isActiveOrderStatus(order.status)) {
62
64
  return null
63
65
  }
64
66
 
@@ -70,7 +72,7 @@ export function expectedRealizedPnlForOpenOrder(
70
72
  return null
71
73
  }
72
74
 
73
- const limitPrice = Number.parseFloat(order.price)
75
+ const limitPrice = Number.parseFloat(order.price ?? '')
74
76
  const entryPrice = Number.parseFloat(position.entryPrice)
75
77
  const orderSize = Math.abs(Number.parseFloat(order.remainingSize))
76
78
  const positionSize = Math.abs(Number.parseFloat(position.size))
@@ -100,29 +102,29 @@ export function expectedRealizedPnlForOpenOrder(
100
102
  })
101
103
  }
102
104
 
103
- /**
104
- * Expected rPnL for a TP/SL trigger order against a matching position.
105
- *
106
- * A trigger order is by construction a closing leg — its direction is the
107
- * opposite of the position's. With no matching position there is nothing to
108
- * close, so rPnL is `null`. The trigger price (always present on the SDK
109
- * `TriggerOrder` shape) is used as the rPnL price; the optional `limitPrice`
110
- * for STOP_LIMIT / TAKE_PROFIT_LIMIT is the post-trigger limit, not the rPnL
111
- * price.
112
- * @public
113
- */
105
+ /** Project the unfilled closing quantity of an active trigger at its trigger price. */
114
106
  export function expectedRealizedPnlForTriggerOrder(
115
107
  order: TriggerOrder,
116
108
  position: Position | undefined
117
109
  ): number | null {
118
- if (!position) {
110
+ if (
111
+ !position ||
112
+ !isActiveOrderStatus(order.status) ||
113
+ order.status === OrderStatus.PENDING
114
+ ) {
119
115
  return null
120
116
  }
121
117
 
122
118
  const isLong = position.side === PositionSide.LONG
119
+ if (
120
+ (isLong && order.side !== OrderSide.SELL) ||
121
+ (!isLong && order.side !== OrderSide.BUY)
122
+ ) {
123
+ return null
124
+ }
123
125
  const triggerPrice = Number.parseFloat(order.triggerPrice)
124
126
  const entryPrice = Number.parseFloat(position.entryPrice)
125
- const orderSize = Math.abs(Number.parseFloat(order.size))
127
+ const orderSize = Math.abs(Number.parseFloat(order.remainingSize))
126
128
  const positionSize = Math.abs(Number.parseFloat(position.size))
127
129
  if (
128
130
  !Number.isFinite(triggerPrice) ||
@@ -133,6 +135,12 @@ export function expectedRealizedPnlForTriggerOrder(
133
135
  ) {
134
136
  return null
135
137
  }
138
+ if (
139
+ orderSize === 0 &&
140
+ (Number.parseFloat(order.originalSize) !== 0 || !order.reduceOnly)
141
+ ) {
142
+ return null
143
+ }
136
144
 
137
145
  const closeSize = resolveCloseSize(orderSize, positionSize)
138
146
  return realizedPnlOnClose({
package/src/version.ts CHANGED
@@ -10,4 +10,4 @@ export const name = '@lifi/perps-sdk'
10
10
  *
11
11
  * @public
12
12
  */
13
- export const version = '0.0.0-preview-050dcd3'
13
+ export const version = '0.0.0-preview-ef23ec2'
@@ -12,12 +12,11 @@ import type {
12
12
  } from './types.js'
13
13
 
14
14
  /**
15
- * Factory for a per-provider WS plugin. Invoked once per provider key the
16
- * first time `subscribe(...)` is called against it.
15
+ * Call parameters of a {@link WsProviderFactory}.
17
16
  *
18
17
  * @public
19
18
  */
20
- export type WsProviderFactory = (params: {
19
+ export interface WsProviderFactoryParams {
21
20
  provider: string
22
21
  /** WS URL discovered from `/providers`. */
23
22
  wsUrl: string
@@ -34,7 +33,19 @@ export type WsProviderFactory = (params: {
34
33
  * duplicating backend orchestration in the WS layer.
35
34
  */
36
35
  client: PerpsSDKClient
37
- }) => WsProvider
36
+ }
37
+
38
+ /**
39
+ * Factory for a per-provider WS plugin. Invoked once per provider key the
40
+ * first time `subscribe(...)` is called against it.
41
+ *
42
+ * @public
43
+ */
44
+ export interface WsProviderFactory {
45
+ (params: WsProviderFactoryParams): WsProvider
46
+ /** `true` when the venue socket serves the `candle` channel. */
47
+ readonly streamsCandles: boolean
48
+ }
38
49
 
39
50
  /**
40
51
  * Options for {@link PerpsWsClient}.
@@ -54,7 +65,7 @@ export interface PerpsWsClientOptions {
54
65
  }
55
66
 
56
67
  /**
57
- * Realtime client: lazily instantiates a per-provider {@link WsProvider} on
68
+ * WebSocket client: lazily instantiates a per-provider {@link WsProvider} on
58
69
  * first subscription and fans subscriptions out to it.
59
70
  *
60
71
  * @public
@@ -72,7 +83,19 @@ export class PerpsWsClient {
72
83
  }
73
84
 
74
85
  /**
75
- * Subscribe to a realtime channel, lazily creating the provider's WS
86
+ * Whether `provider`'s socket serves the `candle` channel, as reported by
87
+ * its registered factory. Returns `false` when no factory is registered.
88
+ * Synchronous: it reads the factory without instantiating the provider and
89
+ * makes no network call, so a caller can branch before the first subscribe.
90
+ *
91
+ * @public
92
+ */
93
+ streamsCandles(provider: string): boolean {
94
+ return this.options.wsProviders?.[provider]?.streamsCandles ?? false
95
+ }
96
+
97
+ /**
98
+ * Subscribe to a WebSocket channel, lazily creating the provider's WS
76
99
  * connection. Returns an unsubscribe function.
77
100
  *
78
101
  * @param onStatus - Optional listener for the underlying connection's