@0xmonaco/types 1.1.5 → 1.1.6

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 (40) 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 +197 -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 +0 -20
  16. package/dist/profile/index.d.ts +10 -17
  17. package/dist/rfq/responses.d.ts +36 -0
  18. package/dist/rfq/responses.js +29 -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/orderbook-events.d.ts +41 -1
  32. package/dist/websocket/events/rfq-events.d.ts +30 -1
  33. package/dist/websocket/events/trade-events.d.ts +37 -0
  34. package/dist/websocket/index.d.ts +1 -0
  35. package/dist/websocket/index.js +1 -0
  36. package/dist/websocket/snapshots.d.ts +23 -1
  37. package/dist/wire/operations.d.ts +1 -1
  38. package/dist/wire/operations.js +16 -0
  39. package/dist/wire/schema.d.ts +2344 -276
  40. package/package.json +2 -2
@@ -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
+ */
@@ -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
  }
@@ -42,9 +42,17 @@ export interface RfqRequestedEvent {
42
42
  }
43
43
  /** One side of the taker's view: the allocation that would fill the quantity. */
44
44
  export interface RfqSideViewEventData {
45
- /** All-in volume-weighted price, the taker's fee included. */
45
+ /** All-in volume-weighted price, the taker's Monaco and builder fees included. */
46
46
  vwap: string;
47
47
  availableQuantity: string;
48
+ /** The volume-weighted price before fees. */
49
+ grossVwap?: string;
50
+ /** Estimated Monaco taker fee on `availableQuantity`, in the quote asset. */
51
+ estimatedMonacoFee?: string;
52
+ /** Estimated builder fee on `availableQuantity`, in the quote asset. */
53
+ estimatedBuilderFee?: string;
54
+ /** Estimated total taker fee on `availableQuantity`, in the quote asset. */
55
+ estimatedTotalFee?: string;
48
56
  }
49
57
  /** The taker's view of the quotes. No maker identity or individual quote. */
50
58
  export interface RfqViewEventData {
@@ -57,6 +65,10 @@ export interface RfqViewEventData {
57
65
  asOfMs: number;
58
66
  /** Pushes can arrive out of order: keep the view with the highest `sequence`. */
59
67
  sequence: number;
68
+ /** Your Monaco taker fee rate in this view, in centi-bps. */
69
+ monacoFeeCbps?: number;
70
+ /** Your frontend's builder fee rate in this view, in centi-bps; frozen when you accept. */
71
+ builderFeeCbps?: number;
60
72
  }
61
73
  /** To the taker: its view moved. */
62
74
  export interface RfqViewEvent {
@@ -82,6 +94,18 @@ export interface RfqSelectionEventData {
82
94
  makerFeeCbps: number;
83
95
  /** Reject or improve before this time; silence executes. */
84
96
  lastLookDeadlineAtMs: number;
97
+ /**
98
+ * The MOST your frontend's builder add-on charges on this fill, in centi-bps:
99
+ * the rate stored on your quote order. A fill charges it or nothing, never
100
+ * more; the receipt shows what was charged. Absent when it could not be read.
101
+ */
102
+ maxBuilderFeeCbps?: number;
103
+ /**
104
+ * Estimated net at `quantity` and `price`, in the quote asset, at
105
+ * `makerFeeCbps` plus `maxBuilderFeeCbps`: the least you receive when
106
+ * selling, the most you pay when buying. Absent with `maxBuilderFeeCbps`.
107
+ */
108
+ estimatedNet?: string;
85
109
  }
86
110
  /** To one selected maker: its last-look prompt. */
87
111
  export interface RfqSelectedEvent {
@@ -94,7 +118,12 @@ export interface RfqFillEventData {
94
118
  executionId: string;
95
119
  price: string;
96
120
  quantity: string;
121
+ /** Your whole taker fee on this fill: `monacoFee` plus `builderFee`. */
97
122
  fee: string;
123
+ /** The Monaco part of `fee`. */
124
+ monacoFee?: string;
125
+ /** The builder part of `fee`. */
126
+ builderFee?: string;
98
127
  }
99
128
  /** How an RFQ ended, for its taker. */
100
129
  export interface RfqOutcomeEventData {
@@ -40,6 +40,12 @@ export interface TradeEventData {
40
40
  quoteVolumeRaw?: string;
41
41
  /** Application (frontend) that placed the taker order; trade volume and fees are attributed to it. REST trade reads only. */
42
42
  takerApplicationId?: string;
43
+ /**
44
+ * The taker's builder fee: the add-on the taker's application charged, in
45
+ * raw quote-asset units, on top of `takerFeeRaw`; `"0"` when it charged
46
+ * none. REST trade reads only.
47
+ */
48
+ builderFeeRaw?: string;
43
49
  }
44
50
  /**
45
51
  * Trade event emitted when a trade is executed
@@ -53,4 +59,35 @@ export interface TradeEvent {
53
59
  tradingMode: TradingMode | (string & {});
54
60
  /** Trade execution data */
55
61
  data: TradeEventData;
62
+ /**
63
+ * The trade's position in its pair's chain: the durable-log sequence of the
64
+ * step that executed it. Present only when the server sources trades from
65
+ * market-data (`WS_TRADES_SOURCE=market_data`); absent otherwise.
66
+ */
67
+ seq?: number;
68
+ /** The trade's index among its step's fills; with `seq`, the trade's key. Same presence as `seq`. */
69
+ matchIndex?: number;
70
+ /** `seq` of the previous trade on the pair; 0 when the publisher knows none. Same presence as `seq`. */
71
+ prevSeq?: number;
72
+ /** `matchIndex` of the previous trade on the pair; `null` when the publisher knows none. Same presence as `seq`. */
73
+ prevMatchIndex?: number | null;
74
+ }
75
+ /**
76
+ * A sequenced trade `ws.trades` received that did not link to the last trade
77
+ * it delivered (or the snapshot cursor). The server forwards only linking
78
+ * trades, so this means a frame was lost or unreadable on the client; the
79
+ * trade is still delivered and the chain continues from it.
80
+ */
81
+ export interface TradeGap {
82
+ tradingPairId: string;
83
+ /** The key of the last trade delivered, or the snapshot cursor. */
84
+ expected: {
85
+ seq: number;
86
+ matchIndex: number;
87
+ };
88
+ /** The received trade's link as sent; `null` where the frame carried none. */
89
+ received: {
90
+ prevSeq: number | null;
91
+ prevMatchIndex: number | null;
92
+ };
56
93
  }
@@ -6,5 +6,6 @@
6
6
  export * from "./base";
7
7
  export * from "./client";
8
8
  export * from "./clients/orderbook-client";
9
+ export * from "./depth";
9
10
  export * from "./events";
10
11
  export * from "./snapshots";