@0xmonaco/types 1.1.5 → 1.1.7

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 (42) hide show
  1. package/README.md +1 -3
  2. package/dist/analytics/builders.d.ts +135 -0
  3. package/dist/analytics/builders.js +11 -0
  4. package/dist/analytics/index.d.ts +153 -0
  5. package/dist/analytics/index.js +27 -0
  6. package/dist/analytics/wallets.d.ts +205 -0
  7. package/dist/analytics/wallets.js +16 -0
  8. package/dist/applications/requests.d.ts +5 -5
  9. package/dist/buildercodes/index.d.ts +13 -11
  10. package/dist/buildercodes/responses.d.ts +1 -0
  11. package/dist/buildercodes/responses.js +10 -0
  12. package/dist/index.d.ts +1 -0
  13. package/dist/index.js +1 -0
  14. package/dist/margin-accounts/index.d.ts +7 -2
  15. package/dist/market/index.d.ts +19 -20
  16. package/dist/profile/index.d.ts +10 -17
  17. package/dist/rfq/responses.d.ts +145 -0
  18. package/dist/rfq/responses.js +102 -0
  19. package/dist/sdk/index.d.ts +4 -1
  20. package/dist/trading/index.d.ts +7 -3
  21. package/dist/trading/orders.d.ts +11 -0
  22. package/dist/trading/responses.d.ts +9 -3
  23. package/dist/validation/margin-accounts.d.ts +2 -2
  24. package/dist/validation/margin-accounts.js +5 -5
  25. package/dist/validation/trading.d.ts +15 -0
  26. package/dist/validation/trading.js +34 -42
  27. package/dist/websocket/base.d.ts +40 -10
  28. package/dist/websocket/client.d.ts +32 -4
  29. package/dist/websocket/depth.d.ts +142 -0
  30. package/dist/websocket/depth.js +13 -0
  31. package/dist/websocket/events/market-stats-events.d.ts +19 -0
  32. package/dist/websocket/events/orderbook-events.d.ts +41 -1
  33. package/dist/websocket/events/position-events.d.ts +3 -2
  34. package/dist/websocket/events/rfq-events.d.ts +51 -1
  35. package/dist/websocket/events/trade-events.d.ts +37 -0
  36. package/dist/websocket/index.d.ts +1 -0
  37. package/dist/websocket/index.js +1 -0
  38. package/dist/websocket/snapshots.d.ts +23 -1
  39. package/dist/wire/operations.d.ts +1 -1
  40. package/dist/wire/operations.js +16 -0
  41. package/dist/wire/schema.d.ts +2485 -308
  42. package/package.json +2 -2
@@ -64,7 +64,7 @@ export declare const TransferCollateralToRiskBucketSchema: z.ZodObject<{
64
64
  marginMode: z.ZodLiteral<"CROSS">;
65
65
  marginAccountId: z.ZodOptional<z.ZodUUID>;
66
66
  selectedTradingPairIds: z.ZodOptional<z.ZodNever>;
67
- strategyKey: z.ZodOptional<z.ZodNever>;
67
+ strategyKey: z.ZodOptional<z.ZodString>;
68
68
  tradingPairId: z.ZodOptional<z.ZodNever>;
69
69
  }, z.core.$strict>]>>;
70
70
  }, z.core.$strip>;
@@ -171,7 +171,7 @@ export declare const SimulateRiskBucketOrderRiskSchema: z.ZodObject<{
171
171
  marginMode: z.ZodLiteral<"CROSS">;
172
172
  marginAccountId: z.ZodOptional<z.ZodUUID>;
173
173
  selectedTradingPairIds: z.ZodOptional<z.ZodNever>;
174
- strategyKey: z.ZodOptional<z.ZodNever>;
174
+ strategyKey: z.ZodOptional<z.ZodString>;
175
175
  tradingPairId: z.ZodUUID;
176
176
  side: z.ZodEnum<{
177
177
  BUY: "BUY";
@@ -2,7 +2,7 @@
2
2
  * Margin Account API Validation Schemas
3
3
  */
4
4
  import { z } from "zod";
5
- import { MarketSlippageToleranceBpsSchema, OrderIdempotencyKeySchema, OrderSideSchema, OrderTypeSchema, PositionSideSchema, PositiveDecimalStringSchema, UUIDSchema, } from "./trading";
5
+ import { MarketSlippageToleranceBpsSchema, OrderIdempotencyKeySchema, OrderSideSchema, OrderTypeSchema, PositionSideSchema, PositiveDecimalStringSchema, StrategyKeySchema, UUIDSchema, } from "./trading";
6
6
  const CursorPaginationSchema = z.object({
7
7
  /**
8
8
  * Rejected, not ignored. A non-strict object would let a JS or `any` caller
@@ -37,7 +37,7 @@ const TransferCollateralRequestSchema = z
37
37
  asset: z.string().trim().min(1, "Asset cannot be empty"),
38
38
  amount: PositiveDecimalStringSchema,
39
39
  tradingPairId: UUIDSchema.optional(),
40
- strategyKey: z.string().trim().min(1, "Strategy key cannot be empty").optional(),
40
+ strategyKey: StrategyKeySchema.optional(),
41
41
  // A cross risk bucket has no trading pair, so CROSS is the only way to name
42
42
  // one on the way out (0XM-2420). The two never combine.
43
43
  marginMode: z.enum(["ISOLATED", "CROSS"]).optional(),
@@ -54,7 +54,7 @@ const ParentMarginAccountCollateralRequestSchema = z.object({
54
54
  });
55
55
  const RiskBucketRequestSchema = z.object({
56
56
  tradingPairId: UUIDSchema,
57
- strategyKey: z.string().trim().min(1, "Strategy key cannot be empty").optional(),
57
+ strategyKey: StrategyKeySchema.optional(),
58
58
  });
59
59
  const IsolatedRiskBucketRequestSchema = RiskBucketRequestSchema.extend({
60
60
  marginMode: z.literal("ISOLATED").optional(),
@@ -78,7 +78,7 @@ const CrossRiskBucketSimulateRequestSchema = z.object({
78
78
  marginMode: z.literal("CROSS"),
79
79
  marginAccountId: UUIDSchema.optional(),
80
80
  selectedTradingPairIds: z.never().optional(),
81
- strategyKey: z.never().optional(),
81
+ strategyKey: StrategyKeySchema.optional(),
82
82
  });
83
83
  // A cross transfer-in names no pairs. Cross scope is derived from trading, so
84
84
  // funding has nothing to declare; `selectedTradingPairIds` used to REPLACE the
@@ -89,7 +89,7 @@ const CrossRiskBucketRequestSchema = z.object({
89
89
  marginMode: z.literal("CROSS"),
90
90
  marginAccountId: UUIDSchema.optional(),
91
91
  selectedTradingPairIds: z.never().optional(),
92
- strategyKey: z.never().optional(),
92
+ strategyKey: StrategyKeySchema.optional(),
93
93
  tradingPairId: z.never().optional(),
94
94
  });
95
95
  export const TransferCollateralSchema = z.object({
@@ -126,6 +126,21 @@ export declare const ParentTrailingStopLegSchema: z.ZodObject<{
126
126
  slippageToleranceBps: z.ZodOptional<z.ZodNumber>;
127
127
  expiresAt: z.ZodOptional<z.ZodISODateTime>;
128
128
  }, z.core.$strip>;
129
+ /**
130
+ * An order's `strategyKey` names one of the caller's margin accounts by its
131
+ * sub-account key (`default` is the default margin account), as
132
+ * `marginAccountId` names it by id; a copy trading account's `copy:` key names
133
+ * it too, for the reduce-only close a copy account admits. The server refuses
134
+ * a key outside the sub-account key alphabet and a key naming none of the
135
+ * caller's open sub-accounts.
136
+ */
137
+ export declare const OrderStrategyKeySchema: z.ZodString;
138
+ /**
139
+ * A risk-bucket transfer's or preview's `strategyKey`: the order rule, and a
140
+ * reserved `copy:` key is refused (a copy account's risk buckets are funded
141
+ * by its follow only).
142
+ */
143
+ export declare const StrategyKeySchema: z.ZodString;
129
144
  /**
130
145
  * Place Limit Order validation schema
131
146
  */
@@ -171,6 +171,26 @@ export const TrailingStopLegSchema = z
171
171
  export const ParentTrailingStopLegSchema = TrailingStopLegSchema;
172
172
  const hasParentTpSl = (options) => options?.takeProfit !== undefined || options?.stopLoss !== undefined || options?.trailingStop !== undefined;
173
173
  const legacyPositionSideMatchesOrderSide = (side, positionSide) => positionSide === undefined || (positionSide !== "NONE" && ((side === "BUY" && positionSide === "LONG") || (side === "SELL" && positionSide === "SHORT")));
174
+ /**
175
+ * An order's `strategyKey` names one of the caller's margin accounts by its
176
+ * sub-account key (`default` is the default margin account), as
177
+ * `marginAccountId` names it by id; a copy trading account's `copy:` key names
178
+ * it too, for the reduce-only close a copy account admits. The server refuses
179
+ * a key outside the sub-account key alphabet and a key naming none of the
180
+ * caller's open sub-accounts.
181
+ */
182
+ export const OrderStrategyKeySchema = z
183
+ .string()
184
+ .trim()
185
+ .min(1, "strategyKey cannot be empty")
186
+ .max(64, "strategyKey must be a sub-account key: letters, digits, _ - . :, up to 64 characters")
187
+ .regex(/^[A-Za-z0-9_.:-]+$/, "strategyKey must be a sub-account key: letters, digits, _ - . :, up to 64 characters");
188
+ /**
189
+ * A risk-bucket transfer's or preview's `strategyKey`: the order rule, and a
190
+ * reserved `copy:` key is refused (a copy account's risk buckets are funded
191
+ * by its follow only).
192
+ */
193
+ export const StrategyKeySchema = OrderStrategyKeySchema.refine((key) => !key.toLowerCase().startsWith("copy:"), "strategy keys starting with copy: are reserved");
174
194
  /**
175
195
  * Place Limit Order validation schema
176
196
  */
@@ -196,7 +216,7 @@ export const PlaceLimitOrderSchema = z
196
216
  marginMode: MarginModeSchema.optional(),
197
217
  riskBucketId: UUIDSchema.optional(),
198
218
  riskBucketCollateral: PositiveDecimalStringSchema.optional(),
199
- strategyKey: z.string().min(1).max(128).optional(),
219
+ strategyKey: OrderStrategyKeySchema.optional(),
200
220
  positionSide: PositionSideSchema.optional(),
201
221
  leverage: PositiveDecimalStringSchema.optional(),
202
222
  reduceOnly: z.boolean().optional(),
@@ -216,7 +236,7 @@ export const PlaceLimitOrderSchema = z
216
236
  message: "leverage is required for normal MARGIN orders",
217
237
  path: ["options", "leverage"],
218
238
  })
219
- .refine((data) => !hasParentTpSl(data.options) || data.options?.tradingMode === "MARGIN", {
239
+ .refine((data) => !hasParentTpSl(data.options) || data.options?.tradingMode !== "SPOT", {
220
240
  message: "takeProfit/stopLoss/trailingStop are only supported for MARGIN orders",
221
241
  path: ["options"],
222
242
  })
@@ -224,17 +244,13 @@ export const PlaceLimitOrderSchema = z
224
244
  message: "takeProfit/stopLoss/trailingStop cannot be attached to reduce-only orders",
225
245
  path: ["options"],
226
246
  })
227
- .refine((data) => data.options?.riskBucketCollateral === undefined || data.options?.tradingMode === "MARGIN", {
247
+ .refine((data) => data.options?.riskBucketCollateral === undefined || data.options?.tradingMode !== "SPOT", {
228
248
  message: "riskBucketCollateral is only supported for MARGIN orders",
229
249
  path: ["options", "tradingMode"],
230
250
  })
231
- .refine((data) => data.options?.marginMode === undefined || data.options?.tradingMode === "MARGIN", {
251
+ .refine((data) => data.options?.marginMode === undefined || data.options?.tradingMode !== "SPOT", {
232
252
  message: "marginMode is only supported for MARGIN orders",
233
253
  path: ["options", "tradingMode"],
234
- })
235
- .refine((data) => data.options?.marginMode !== "CROSS" || data.options?.marginAccountId !== undefined, {
236
- message: "marginAccountId is required for CROSS margin orders",
237
- path: ["options", "marginAccountId"],
238
254
  })
239
255
  .refine((data) => data.options?.marginMode !== "CROSS" || data.options?.riskBucketId === undefined, {
240
256
  message: "marginMode CROSS cannot be combined with riskBucketId",
@@ -243,10 +259,6 @@ export const PlaceLimitOrderSchema = z
243
259
  .refine((data) => data.options?.marginMode !== "CROSS" || data.options?.riskBucketCollateral === undefined, {
244
260
  message: "marginMode CROSS cannot be combined with riskBucketCollateral",
245
261
  path: ["options", "riskBucketCollateral"],
246
- })
247
- .refine((data) => data.options?.marginMode !== "CROSS" || data.options?.strategyKey === undefined, {
248
- message: "marginMode CROSS cannot be combined with strategyKey",
249
- path: ["options", "strategyKey"],
250
262
  })
251
263
  .refine((data) => data.options?.riskBucketCollateral === undefined || data.options?.riskBucketId === undefined, {
252
264
  message: "riskBucketCollateral creates a new risk bucket and cannot be combined with riskBucketId",
@@ -277,7 +289,7 @@ export const PlaceMarketOrderSchema = z
277
289
  marginMode: MarginModeSchema.optional(),
278
290
  riskBucketId: UUIDSchema.optional(),
279
291
  riskBucketCollateral: PositiveDecimalStringSchema.optional(),
280
- strategyKey: z.string().min(1).max(128).optional(),
292
+ strategyKey: OrderStrategyKeySchema.optional(),
281
293
  positionSide: PositionSideSchema.optional(),
282
294
  leverage: PositiveDecimalStringSchema.optional(),
283
295
  reduceOnly: z.boolean().optional(),
@@ -296,7 +308,7 @@ export const PlaceMarketOrderSchema = z
296
308
  message: "leverage is required for normal MARGIN orders",
297
309
  path: ["options", "leverage"],
298
310
  })
299
- .refine((data) => !hasParentTpSl(data.options) || data.options?.tradingMode === "MARGIN", {
311
+ .refine((data) => !hasParentTpSl(data.options) || data.options?.tradingMode !== "SPOT", {
300
312
  message: "takeProfit/stopLoss/trailingStop are only supported for MARGIN orders",
301
313
  path: ["options"],
302
314
  })
@@ -304,17 +316,13 @@ export const PlaceMarketOrderSchema = z
304
316
  message: "takeProfit/stopLoss/trailingStop cannot be attached to reduce-only orders",
305
317
  path: ["options"],
306
318
  })
307
- .refine((data) => data.options?.riskBucketCollateral === undefined || data.options?.tradingMode === "MARGIN", {
319
+ .refine((data) => data.options?.riskBucketCollateral === undefined || data.options?.tradingMode !== "SPOT", {
308
320
  message: "riskBucketCollateral is only supported for MARGIN orders",
309
321
  path: ["options", "tradingMode"],
310
322
  })
311
- .refine((data) => data.options?.marginMode === undefined || data.options?.tradingMode === "MARGIN", {
323
+ .refine((data) => data.options?.marginMode === undefined || data.options?.tradingMode !== "SPOT", {
312
324
  message: "marginMode is only supported for MARGIN orders",
313
325
  path: ["options", "tradingMode"],
314
- })
315
- .refine((data) => data.options?.marginMode !== "CROSS" || data.options?.marginAccountId !== undefined, {
316
- message: "marginAccountId is required for CROSS margin orders",
317
- path: ["options", "marginAccountId"],
318
326
  })
319
327
  .refine((data) => data.options?.marginMode !== "CROSS" || data.options?.riskBucketId === undefined, {
320
328
  message: "marginMode CROSS cannot be combined with riskBucketId",
@@ -323,10 +331,6 @@ export const PlaceMarketOrderSchema = z
323
331
  .refine((data) => data.options?.marginMode !== "CROSS" || data.options?.riskBucketCollateral === undefined, {
324
332
  message: "marginMode CROSS cannot be combined with riskBucketCollateral",
325
333
  path: ["options", "riskBucketCollateral"],
326
- })
327
- .refine((data) => data.options?.marginMode !== "CROSS" || data.options?.strategyKey === undefined, {
328
- message: "marginMode CROSS cannot be combined with strategyKey",
329
- path: ["options", "strategyKey"],
330
334
  })
331
335
  .refine((data) => data.options?.riskBucketCollateral === undefined || data.options?.riskBucketId === undefined, {
332
336
  message: "riskBucketCollateral creates a new risk bucket and cannot be combined with riskBucketId",
@@ -466,7 +470,7 @@ export const CreateTwapOrderSchema = z
466
470
  riskBucketId: UUIDSchema.optional(),
467
471
  marginMode: MarginModeSchema.optional(),
468
472
  leverage: PositiveDecimalStringSchema.optional(),
469
- strategyKey: z.string().min(1).max(128).optional(),
473
+ strategyKey: OrderStrategyKeySchema.optional(),
470
474
  useMasterBalance: z.boolean().optional(),
471
475
  clientTwapId: z.string().min(1).max(36, "clientTwapId cannot exceed 36 characters").optional(),
472
476
  triggerPrice: PositiveDecimalStringSchema.optional(),
@@ -482,21 +486,17 @@ export const CreateTwapOrderSchema = z
482
486
  message: "startTime is only valid together with endTime",
483
487
  path: ["options", "startTime"],
484
488
  })
485
- .refine((data) => data.options.marginMode === undefined || data.options.tradingMode === "MARGIN", {
489
+ .refine((data) => data.options.marginMode === undefined || data.options.tradingMode !== "SPOT", {
486
490
  message: "marginMode is only supported for MARGIN orders",
487
491
  path: ["options", "tradingMode"],
488
492
  })
489
- .refine((data) => data.options.riskBucketId === undefined || data.options.tradingMode === "MARGIN", {
493
+ .refine((data) => data.options.riskBucketId === undefined || data.options.tradingMode !== "SPOT", {
490
494
  message: "riskBucketId is only supported for MARGIN orders",
491
495
  path: ["options", "tradingMode"],
492
496
  })
493
497
  .refine((data) => data.options.marginMode !== "CROSS" || data.options.riskBucketId === undefined, {
494
498
  message: "marginMode CROSS cannot be combined with riskBucketId",
495
499
  path: ["options", "riskBucketId"],
496
- })
497
- .refine((data) => data.options.marginMode !== "CROSS" || data.options.strategyKey === undefined, {
498
- message: "marginMode CROSS cannot be combined with strategyKey",
499
- path: ["options", "strategyKey"],
500
500
  })
501
501
  .refine((data) => data.options.tradingMode !== "MARGIN" || data.options.reduceOnly === true || data.options.leverage !== undefined, {
502
502
  message: "leverage is required for normal MARGIN TWAP orders",
@@ -614,7 +614,7 @@ export const BatchCreateOrderItemSchema = z
614
614
  marginMode: MarginModeSchema.optional(),
615
615
  riskBucketId: UUIDSchema.optional(),
616
616
  riskBucketCollateral: PositiveDecimalStringSchema.optional(),
617
- strategyKey: z.string().min(1).max(128).optional(),
617
+ strategyKey: OrderStrategyKeySchema.optional(),
618
618
  positionSide: PositionSideSchema.optional(),
619
619
  leverage: PositiveDecimalStringSchema.optional(),
620
620
  reduceOnly: z.boolean().optional(),
@@ -641,17 +641,13 @@ export const BatchCreateOrderItemSchema = z
641
641
  message: "postOnly cannot be combined with IOC/FOK time in force",
642
642
  path: ["postOnly"],
643
643
  })
644
- .refine((data) => data.riskBucketCollateral === undefined || data.tradingMode === "MARGIN", {
644
+ .refine((data) => data.riskBucketCollateral === undefined || data.tradingMode !== "SPOT", {
645
645
  message: "riskBucketCollateral is only supported for MARGIN orders",
646
646
  path: ["tradingMode"],
647
647
  })
648
- .refine((data) => data.marginMode === undefined || data.tradingMode === "MARGIN", {
648
+ .refine((data) => data.marginMode === undefined || data.tradingMode !== "SPOT", {
649
649
  message: "marginMode is only supported for MARGIN orders",
650
650
  path: ["tradingMode"],
651
- })
652
- .refine((data) => data.marginMode !== "CROSS" || data.marginAccountId !== undefined, {
653
- message: "marginAccountId is required for CROSS margin orders",
654
- path: ["marginAccountId"],
655
651
  })
656
652
  .refine((data) => data.marginMode !== "CROSS" || data.riskBucketId === undefined, {
657
653
  message: "marginMode CROSS cannot be combined with riskBucketId",
@@ -660,10 +656,6 @@ export const BatchCreateOrderItemSchema = z
660
656
  .refine((data) => data.marginMode !== "CROSS" || data.riskBucketCollateral === undefined, {
661
657
  message: "marginMode CROSS cannot be combined with riskBucketCollateral",
662
658
  path: ["riskBucketCollateral"],
663
- })
664
- .refine((data) => data.marginMode !== "CROSS" || data.strategyKey === undefined, {
665
- message: "marginMode CROSS cannot be combined with strategyKey",
666
- path: ["strategyKey"],
667
659
  })
668
660
  .refine((data) => data.riskBucketCollateral === undefined || data.riskBucketId === undefined, {
669
661
  message: "riskBucketCollateral creates a new risk bucket and cannot be combined with riskBucketId",
@@ -71,23 +71,43 @@ export interface WebSocketStatusInfo {
71
71
  */
72
72
  export type StatusHandler = (status: WebSocketStatus, info: WebSocketStatusInfo) => void;
73
73
  /**
74
- * Why the connection was re-established. Delivered by
75
- * {@link MonacoWebSocketConfig.onResync} after the socket reopens and sends its
76
- * authentication/subscription requests. It does not wait for server acks or
77
- * snapshots. The application owns channel-specific recovery; the SDK does not
78
- * automatically refetch REST state.
74
+ * Why the application should refetch REST state, delivered by
75
+ * {@link MonacoWebSocketConfig.onResync}. Two cases:
76
+ *
77
+ * - A reconnect (`reason` absent): sent after the socket reopens and sends its
78
+ * authentication/subscription requests, without waiting for server acks or
79
+ * snapshots. Refetch every channel.
80
+ * - A scoped resync (`reason: "resynced"`, 0XM-3553): the connection stayed
81
+ * open, but the server reported that an upstream loss may have cost the
82
+ * listed `channels` frames, or re-sent a snapshot for a channel that has no
83
+ * snapshot handler. Delivered once per burst, no earlier than the server's
84
+ * requested delay, with `code: 1013` and `slowClient: true` so a handler
85
+ * written for reconnects still refetches (everything). Refetch only
86
+ * `channels` to recover precisely. The subscriptions stay active.
87
+ *
88
+ * The application owns channel-specific recovery; the SDK does not refetch
89
+ * REST state itself.
79
90
  */
80
91
  export interface WebSocketResyncInfo {
81
92
  /** WebSocket close code of the connection that was lost. */
82
93
  code: number;
83
94
  /**
84
- * True when the server closed with 1013 (try again later): the client fell
85
- * behind a sequential stream (orders, conditional orders, liquidations,
86
- * trades, movements) and the stream has a gap. There is no wire sequence
87
- * number — the 1013 close is the gap signal, and a snapshot refetch is the
88
- * only safe repair.
95
+ * True when the server closed with 1013 (try again later): the connection
96
+ * fell behind, or the server lost events upstream, and any of its streams
97
+ * may have a gap. Order, account and engine-sourced public streams carry no
98
+ * wire sequence number, so the 1013 close is their gap signal and a snapshot
99
+ * refetch is the only safe repair. `depth`, `bbo` and a single market's
100
+ * market-data-sourced `trades` rebuild from the snapshot the reconnect
101
+ * brings; `trades:*` has no snapshot, so backfill its history over REST.
89
102
  */
90
103
  slowClient: boolean;
104
+ /** `"resynced"` for a scoped resync; absent on a reconnect. */
105
+ reason?: "resynced";
106
+ /**
107
+ * The channels to refetch, exactly as subscribed, on a scoped resync;
108
+ * absent on a reconnect, which covers every channel.
109
+ */
110
+ channels?: string[];
91
111
  }
92
112
  /** Handler invoked after a reconnect resumes the live stream. */
93
113
  export type ResyncHandler = (info: WebSocketResyncInfo) => void;
@@ -200,6 +220,16 @@ export type ReauthenticationRequiredHandler = (info: WebSocketReauthenticationIn
200
220
  export interface MonacoWebSocketConfig {
201
221
  /** Enable auto-reconnect on disconnect (default: true) */
202
222
  autoReconnect?: boolean;
223
+ /**
224
+ * Offer the server the `resync` capability (default: true when
225
+ * {@link onResync} is set, 0XM-3553; never without it, since the channels
226
+ * would have nowhere to go): on an
227
+ * upstream loss it can attribute, the server keeps the connection open and
228
+ * names the channels to refetch (delivered through {@link onResync} with
229
+ * `reason: "resynced"`), or re-sends their snapshots, instead of closing it
230
+ * with 1013. `false` keeps the close-and-reconnect behaviour.
231
+ */
232
+ scopedResync?: boolean;
203
233
  /**
204
234
  * Maximum reconnection attempts per outage (default: unlimited). Retry
205
235
  * delay is full-jitter exponential backoff capped at 30s, so unlimited
@@ -59,8 +59,14 @@ import type { Interval } from "../market";
59
59
  import type { TradingMode } from "../trading";
60
60
  import type { SubscriptionChangeHandler, WebSocketStatus, WebSocketSubscriptionState } from "./base";
61
61
  import type { OrderbookQuotationMode } from "./clients/orderbook-client";
62
- import type { AccountEvent, AccountEventData, ConditionalOrderEvent, ConditionalOrderEventData, CopyEvent, CopyRelationshipEventData, InstrumentEvent, InstrumentEventData, LiquidationEvent, LiquidationEventData, MarketLiquidationEvent, MarketStatsAllEvent, MarketStatsData, MarketStatsEvent, MarketStatsSummary, OHLCVEvent, OHLCVPriceType, OrderbookEvent, OrderEvent, PositionEvent, PositionEventData, PositionValuationEvent, RfqEvent, RfqTradeEvent, TradeEvent, TradeEventData, TwapOrderEvent, TwapOrderEventData, UserBalanceEvent, UserBalanceEventData, UserMovementEvent } from "./events";
62
+ import type { Bbo, DepthBook, LocalBookOptions } from "./depth";
63
+ import type { AccountEvent, AccountEventData, ConditionalOrderEvent, ConditionalOrderEventData, CopyEvent, CopyRelationshipEventData, InstrumentEvent, InstrumentEventData, LiquidationEvent, LiquidationEventData, MarketLiquidationEvent, MarketStatsAllEvent, MarketStatsData, MarketStatsEvent, MarketStatsSummary, OHLCVEvent, OHLCVPriceType, OrderbookEvent, OrderEvent, PositionEvent, PositionEventData, PositionValuationEvent, RfqEvent, RfqTradeEvent, TradeEvent, TradeEventData, TradeGap, TwapOrderEvent, TwapOrderEventData, UserBalanceEvent, UserBalanceEventData, UserMovementEvent } from "./events";
63
64
  import type { OHLCVSnapshotCandle, OrderSnapshotItem, SnapshotHandler } from "./snapshots";
65
+ /** Options for `ws.trades`. */
66
+ export interface TradesOptions {
67
+ /** Called when a sequenced trade does not link to the last trade delivered (it is still delivered). */
68
+ onGap?: (gap: TradeGap) => void;
69
+ }
64
70
  export type MessageHandler<T> = (data: T) => void;
65
71
  export interface MonacoWebSocket {
66
72
  /** Connect to the WebSocket server */
@@ -92,10 +98,26 @@ export interface MonacoWebSocket {
92
98
  /** Subscribe to order events (requires authentication); `onSnapshot` receives every resting order on the pair */
93
99
  orders: (tradingPairId: string, tradingMode: TradingMode, handler: MessageHandler<OrderEvent>, onSnapshot?: SnapshotHandler<OrderSnapshotItem>) => () => void;
94
100
  /**
95
- * Subscribe to orderbook events (public); `onSnapshot` receives one event, the current book read from the matching
96
- * engine, in the same shape as a live event. Its `sequence` is 0. A pair or mode with no book gets `[]`.
101
+ * Subscribe to orderbook events (public); `onSnapshot` receives one event, the current book, in the same shape as a
102
+ * live event. From the matching engine it is the top 20 levels with `sequence` 0; from the market-data service it is
103
+ * grouped over the whole book (at most 20 levels or buckets per side), carries `bookSeq`, and its `sequence` equals
104
+ * `bookSeq`. From the engine, a pair or mode with no book gets `[]`; from the market-data service, an unknown pair
105
+ * gets a `SNAPSHOT_UNAVAILABLE` error (through `onError`) instead, and no snapshot until the pair is listed.
97
106
  */
98
107
  orderbook: (tradingPairId: string, tradingMode: TradingMode, magnitude: number, quotationMode: OrderbookQuotationMode, handler: MessageHandler<OrderbookEvent>, onSnapshot?: SnapshotHandler<OrderbookEvent>) => () => void;
108
+ /**
109
+ * Keep a local depth book from the market-data `depth:<tradingPairId>:<SPOT|MARGIN>` channel (public): up to 1000
110
+ * levels per side. The subscribe-time snapshot is the base; live frames that do not link to it are dropped or
111
+ * trigger a rebuild from a fresh snapshot. `onBook` receives the whole book after the snapshot and after every
112
+ * applied frame. Subscribers on the same channel share one book. Returns a function that stops listening.
113
+ */
114
+ depth: (tradingPairId: string, tradingMode: TradingMode, onBook: MessageHandler<DepthBook>, options?: LocalBookOptions) => () => void;
115
+ /**
116
+ * Keep the top of book from the market-data `bbo:<tradingPairId>:<SPOT|MARGIN>` channel (public), with the same
117
+ * snapshot handoff and link checks as `depth`. `onBbo` receives the current best bid and ask (an empty side is
118
+ * `null`) after the snapshot and after every applied frame.
119
+ */
120
+ bbo: (tradingPairId: string, tradingMode: TradingMode, onBbo: MessageHandler<Bbo>, options?: LocalBookOptions) => () => void;
99
121
  /**
100
122
  * Subscribe to OHLCV candlestick events (public); `onSnapshot` receives the series' newest 350 candles, oldest first.
101
123
  * The newest snapshot candle can be partial or missing, so upsert live candles by `T`. A `*` price type gets no snapshot.
@@ -104,8 +126,14 @@ export interface MonacoWebSocket {
104
126
  /**
105
127
  * Subscribe to trade events (public); `onSnapshot` receives the pair's newest 50 trades, newest first.
106
128
  * The snapshot can overlap the first live trades or miss one executed just before subscribing, so dedupe on `tradeId`.
129
+ *
130
+ * When the server sources trades from market-data, each trade carries `seq` / `matchIndex` / `prevSeq` /
131
+ * `prevMatchIndex`, and the snapshot's `meta.cursor` names the trade it is current as of. The helper then drops
132
+ * trades at or below the cursor or the last delivered trade, and reports one that does not link to the last
133
+ * delivered trade to `options.onGap` (still delivering it: the server forwards only linking trades, so a mismatch
134
+ * means a frame was lost on this client). Without those fields every trade is delivered as before.
107
135
  */
108
- trades: (tradingPairId: string, handler: MessageHandler<TradeEvent>, onSnapshot?: SnapshotHandler<TradeEventData>) => () => void;
136
+ trades: (tradingPairId: string, handler: MessageHandler<TradeEvent>, onSnapshot?: SnapshotHandler<TradeEventData>, options?: TradesOptions) => () => void;
109
137
  /** Subscribe to user movement events (requires authentication) */
110
138
  movements: (handler: MessageHandler<UserMovementEvent>) => () => void;
111
139
  /** Subscribe to user order events for all trading pairs (requires authentication); `onSnapshot` receives every resting order */
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Market-data depth and BBO types (0XM-3551).
3
+ *
4
+ * The `depth:<tradingPairId>:<SPOT|MARGIN>` and `bbo:<tradingPairId>:<SPOT|MARGIN>`
5
+ * WebSocket channels carry the market-data service's sequenced book: a
6
+ * subscribe-time snapshot, then live frames linked by `bookSeq` /
7
+ * `prevBookSeq`. The SDK's `ws.depth` and `ws.bbo` helpers keep the local
8
+ * state for you; the frame shapes are exported for callers that need them.
9
+ *
10
+ * Sequence numbers are durable-log positions (u64). They are surfaced as
11
+ * decimal strings, since a u64 can exceed `Number.MAX_SAFE_INTEGER`; compare
12
+ * them with `BigInt`.
13
+ */
14
+ import type { TradingMode } from "../trading";
15
+ /** One price level, with its absolute (not incremental) values. */
16
+ export interface DepthLevel {
17
+ /** Price, a decimal string. */
18
+ price: string;
19
+ /** Resting quantity at this price, a decimal string. */
20
+ quantity: string;
21
+ /** Number of resting orders at this price. */
22
+ orderCount: number;
23
+ }
24
+ /**
25
+ * The `depth` channel's subscribe-time snapshot: up to 1000 levels per side,
26
+ * best first, exact as of `bookSeq`.
27
+ */
28
+ export interface DepthSnapshot {
29
+ tradingPairId: string;
30
+ tradingMode: TradingMode | (string & {});
31
+ /** The durable-log sequence the snapshot is exact as of (u64, decimal string). */
32
+ bookSeq: string;
33
+ bids: DepthLevel[];
34
+ asks: DepthLevel[];
35
+ /** Every bid level is in `bids`; when false, levels below the last one are unknown. */
36
+ bidsComplete: boolean;
37
+ /** Every ask level is in `asks`; when false, levels above the last one are unknown. */
38
+ asksComplete: boolean;
39
+ }
40
+ /**
41
+ * A live `depth` frame: only the levels that changed since `prevBookSeq`,
42
+ * each with its absolute value at `bookSeq`. A quantity of `"0"` (order
43
+ * count 0) removes the level.
44
+ */
45
+ export interface DepthDelta {
46
+ tradingPairId: string;
47
+ tradingMode: TradingMode | (string & {});
48
+ /** The durable-log sequence of the last change this frame includes. */
49
+ bookSeq: string;
50
+ /** The `bookSeq` this frame continues from. */
51
+ prevBookSeq: string;
52
+ /** The durable-log timestamp of the step at `bookSeq`, in milliseconds. */
53
+ timestampMs: number;
54
+ bids: DepthLevel[];
55
+ asks: DepthLevel[];
56
+ /** Set while the publisher lags the durable log. */
57
+ stale: boolean;
58
+ }
59
+ /** The local book `ws.depth` maintains and hands to its listener. */
60
+ export interface DepthBook {
61
+ tradingPairId: string;
62
+ tradingMode: TradingMode | (string & {});
63
+ /** The sequence the book is current as of (u64, decimal string). */
64
+ bookSeq: string;
65
+ /** Bids, best (highest) first. */
66
+ bids: DepthLevel[];
67
+ /** Asks, best (lowest) first. */
68
+ asks: DepthLevel[];
69
+ /**
70
+ * Every bid level is known. When false, the book holds only levels at or
71
+ * above the snapshot's deepest bid: a level below it that a removal would
72
+ * promote stays unknown until the next snapshot.
73
+ */
74
+ bidsComplete: boolean;
75
+ /** Every ask level is known (see `bidsComplete`). */
76
+ asksComplete: boolean;
77
+ /** The latest applied frame was published while the service lagged. */
78
+ stale: boolean;
79
+ /** Durable-log time of the latest applied frame; absent right after a snapshot. */
80
+ timestampMs?: number;
81
+ }
82
+ /** The `bbo` channel's subscribe-time snapshot. An empty side is `null`. */
83
+ export interface BboSnapshot {
84
+ tradingPairId: string;
85
+ tradingMode: TradingMode | (string & {});
86
+ bookSeq: string;
87
+ bestBid: string | null;
88
+ /** Quantity resting at `bestBid`. */
89
+ bidQty: string | null;
90
+ bestAsk: string | null;
91
+ /** Quantity resting at `bestAsk`. */
92
+ askQty: string | null;
93
+ }
94
+ /** A live `bbo` frame. */
95
+ export interface BboEvent extends BboSnapshot {
96
+ prevBookSeq: string;
97
+ timestampMs: number;
98
+ stale: boolean;
99
+ }
100
+ /** The top of book `ws.bbo` maintains and hands to its listener. */
101
+ export interface Bbo extends BboSnapshot {
102
+ /** The latest applied frame was published while the service lagged. */
103
+ stale: boolean;
104
+ /** Durable-log time of the latest applied frame; absent right after a snapshot. */
105
+ timestampMs?: number;
106
+ }
107
+ /** Why a local book was discarded and is being rebuilt from a new snapshot. */
108
+ export type LocalBookResyncReason =
109
+ /** A frame did not link to the book (a lost frame), or could not be read. */
110
+ "gap"
111
+ /**
112
+ * The server could not serve a snapshot (`SNAPSHOT_UNAVAILABLE`; it retries
113
+ * and sends one when the book heals), or the one it sent could not be read.
114
+ */
115
+ | "snapshot_unavailable"
116
+ /**
117
+ * A side whose snapshot was incomplete has thinned below half its snapshot
118
+ * depth: the levels beyond its boundary are unknown, so a fresh snapshot is
119
+ * taken.
120
+ */
121
+ | "truncated"
122
+ /** The connection dropped; the book is rebuilt from the snapshot the reconnect brings. */
123
+ | "disconnected";
124
+ /** A channel-level error the server sent for a `depth` / `bbo` subscription. */
125
+ export interface LocalBookError {
126
+ /** The server's error code, e.g. `INVALID_SUBSCRIPTION`. */
127
+ code: string;
128
+ message: string;
129
+ }
130
+ /** Options for `ws.depth` and `ws.bbo`. */
131
+ export interface LocalBookOptions {
132
+ /**
133
+ * Called when the local state is discarded to be rebuilt; the listener is
134
+ * called again once the new snapshot arrives.
135
+ */
136
+ onResync?: (reason: LocalBookResyncReason) => void;
137
+ /**
138
+ * Called when the server rejects the subscription with an error other than
139
+ * `SNAPSHOT_UNAVAILABLE` (which is retried): the book will not arrive.
140
+ */
141
+ onError?: (error: LocalBookError) => void;
142
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Market-data depth and BBO types (0XM-3551).
3
+ *
4
+ * The `depth:<tradingPairId>:<SPOT|MARGIN>` and `bbo:<tradingPairId>:<SPOT|MARGIN>`
5
+ * WebSocket channels carry the market-data service's sequenced book: a
6
+ * subscribe-time snapshot, then live frames linked by `bookSeq` /
7
+ * `prevBookSeq`. The SDK's `ws.depth` and `ws.bbo` helpers keep the local
8
+ * state for you; the frame shapes are exported for callers that need them.
9
+ *
10
+ * Sequence numbers are durable-log positions (u64). They are surfaced as
11
+ * decimal strings, since a u64 can exceed `Number.MAX_SAFE_INTEGER`; compare
12
+ * them with `BigInt`.
13
+ */
@@ -79,6 +79,11 @@ export interface MarketStatsData {
79
79
  dailyPriceChange?: string;
80
80
  /** 24h percentage price change, two decimals (decimal string) */
81
81
  dailyPriceChangePercent?: string;
82
+ /**
83
+ * The 24h volumes split into their order-book and RFQ parts. Omitted while
84
+ * any candle in the window has no recorded split.
85
+ */
86
+ dailyVolumeBySource?: DailyVolumeBySource;
82
87
  /** Current (last settled) funding rate (decimal string). Perp-only; omitted for spot. */
83
88
  currentFundingRate?: string;
84
89
  /** Estimated next-window funding rate (decimal string). Perp-only; omitted for spot. */
@@ -185,3 +190,17 @@ export interface MarketStatsAllEvent {
185
190
  /** One summary row per market */
186
191
  markets: MarketStatsSummary[];
187
192
  }
193
+ /**
194
+ * A market's 24h volume split by execution source: each total is the
195
+ * order-book part plus the RFQ part (decimal strings, normalized token units).
196
+ */
197
+ export interface DailyVolumeBySource {
198
+ /** 24h base-token volume filled on the order book */
199
+ orderBookBaseTokenVolume: string;
200
+ /** 24h base-token volume filled by RFQ block trades */
201
+ rfqBaseTokenVolume: string;
202
+ /** 24h quote-token volume filled on the order book; omitted when the 24h quote volume is unavailable */
203
+ orderBookQuoteTokenVolume?: string;
204
+ /** 24h quote-token volume filled by RFQ block trades; omitted when the 24h quote volume is unavailable */
205
+ rfqQuoteTokenVolume?: string;
206
+ }
@@ -67,6 +67,46 @@ export interface OrderbookEvent {
67
67
  quoteDecimals: number;
68
68
  /** Event timestamp */
69
69
  timestamp: string;
70
- /** Sequence number for ordering */
70
+ /**
71
+ * Sequence number for ordering. Under the default engine source it is the
72
+ * matching engine's own frame counter; when the server renders the channel
73
+ * from market-data's book (`WS_ORDERBOOK_SOURCE=market_data`) it equals
74
+ * `bookSeq`. The two are different number spaces: do not compare a value
75
+ * from one source with a value from the other (a reconnect or deploy can
76
+ * switch sources). For exact comparison under the market-data source use
77
+ * `bookSeq`, a u64 decimal string.
78
+ */
71
79
  sequence: number;
80
+ /**
81
+ * Durable-log sequence this book is exact as of, as a decimal string
82
+ * (a u64 can exceed `Number.MAX_SAFE_INTEGER`; compare with `BigInt`).
83
+ *
84
+ * Present on a REST snapshot of more than 100 levels: a point-in-time
85
+ * read and staleness check, not a base for applying depth deltas (the REST
86
+ * snapshot may come from a different market-data replica than the stream;
87
+ * for a live local book use `sdk.ws.depth`, which hands off from the
88
+ * `depth` channel's own snapshot). A side that came back with as many
89
+ * levels as requested may hold more.
90
+ *
91
+ * Also present on every `orderbook` WebSocket frame and snapshot row when
92
+ * the server renders the channel from market-data's book
93
+ * (`WS_ORDERBOOK_SOURCE=market_data`): the same watermark the `depth`
94
+ * channel carries, identical on every server. Each such frame restates the
95
+ * book, so per subscription (one channel string: pair, mode, magnitude and
96
+ * quotation) a frame whose `bookSeq` is not past the last one applied to it
97
+ * can be ignored. The watermark is the book's, shared by every magnitude
98
+ * and quotation of it: a newly subscribed variant starts from its own
99
+ * snapshot even when its `bookSeq` equals another variant's.
100
+ */
101
+ bookSeq?: string;
102
+ /**
103
+ * On an `orderbook` WebSocket frame rendered from market-data's book
104
+ * (`WS_ORDERBOOK_SOURCE=market_data`): the `bookSeq` of the previous frame
105
+ * this server rendered for the book, `"0"` before the first, as a decimal
106
+ * string. A `prevBookSeq` at or below the `bookSeq` you hold means no
107
+ * rendered state was skipped. Informational only: every frame restates the
108
+ * whole book, so nothing needs to be re-requested when it is higher.
109
+ * Absent under the engine source and on REST snapshots.
110
+ */
111
+ prevBookSeq?: string;
72
112
  }