@0xmonaco/types 1.0.39 → 1.0.41-develop.ebb62ed

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.
@@ -80,6 +80,12 @@ export interface TransferCollateralRequest {
80
80
  amount: string;
81
81
  tradingPairId?: string;
82
82
  strategyKey?: string;
83
+ /**
84
+ * Risk bucket mode. Defaults to ISOLATED, which is selected by
85
+ * `tradingPairId`. Pass `"CROSS"` to release from the account's cross risk
86
+ * bucket, which has no trading pair and so cannot be named any other way.
87
+ */
88
+ marginMode?: MarginMode;
83
89
  }
84
90
  export interface TransferCollateralToParentMarginAccountRequest {
85
91
  asset: string;
@@ -123,6 +123,13 @@ export interface GetCandlesticksParams {
123
123
  endTime?: number;
124
124
  /** Maximum number of bars to return (max: 500, server defaults to 350 if omitted) */
125
125
  limit?: number;
126
+ /**
127
+ * Price series to chart. `"trade"` (default) returns the trade-derived OHLCV
128
+ * series; `"mark"` returns the mark-price series (margin pairs only), where
129
+ * each candle's open/high/low/close are the bucket's closing mark and volume
130
+ * is 0. Omit for the trade series.
131
+ */
132
+ priceType?: "trade" | "mark";
126
133
  }
127
134
  /**
128
135
  * Query parameters for fetching trading pairs
@@ -232,6 +239,18 @@ export interface ScreenerItem {
232
239
  * null for spot pairs and margin pairs with no settled funding window yet
233
240
  */
234
241
  lastFundingTime: string | null;
242
+ /**
243
+ * Open interest in base-asset units (e.g. BTC); null for spot pairs, "0" for
244
+ * a margin pair with no open positions
245
+ */
246
+ openInterestBase: string | null;
247
+ /**
248
+ * Open interest notional in quote units (openInterestBase × latest trade
249
+ * price); null for spot pairs. Valued at the pair's latest trade price (a
250
+ * snapshot); the mark-accurate notional lives on getPerpMarketSummary /
251
+ * getOpenInterest
252
+ */
253
+ openInterestNotional: string | null;
235
254
  }
236
255
  /**
237
256
  * Paginated screener response, sorted by quoteVolume24h desc (nulls last)
@@ -269,6 +288,8 @@ export interface MarketMetadata {
269
288
  low24h: string | null;
270
289
  /** 24h volume in base asset (null if <24h data) */
271
290
  volume24h: string | null;
291
+ /** Quote-token (notional) volume over the rolling 24h window; absent/null when unavailable */
292
+ quoteVolume24h?: string | null;
272
293
  /** Absolute price change in 24h (null if <24h data) */
273
294
  priceChange24h: string | null;
274
295
  /** Percentage price change in 24h (2 decimals, null if <24h data) */
@@ -319,10 +340,18 @@ export interface PerpMarketSummary {
319
340
  indexPrice: string;
320
341
  high24h?: string;
321
342
  low24h?: string;
343
+ /** 24h volume in base asset */
322
344
  volume24h?: string;
345
+ /** 24h quote-token (notional) volume */
346
+ quoteVolume24h?: string;
323
347
  priceChange24h?: string;
324
348
  priceChangePercent24h?: string;
349
+ /** Open interest in base-asset units (legacy alias of openInterestBase) */
325
350
  openInterest: string;
351
+ /** Open interest in base-asset units (e.g. BTC) */
352
+ openInterestBase?: string;
353
+ /** Open interest notional in quote units (openInterestBase × mark price, falling back to the last trade price when no mark is available) */
354
+ openInterestNotional?: string;
326
355
  currentFundingRate?: string;
327
356
  estimatedNextFundingRate?: string;
328
357
  nextFundingTime?: string;
@@ -164,20 +164,6 @@ export interface PositionRisk {
164
164
  initialMarginRequired?: string;
165
165
  updatedAt: string;
166
166
  }
167
- export interface AddPositionMarginRequest {
168
- amount: string;
169
- asset: string;
170
- }
171
- export interface ReducePositionMarginRequest {
172
- amount: string;
173
- }
174
- export interface PositionMarginResponse {
175
- positionId: string;
176
- marginAccountId: string;
177
- newIsolatedMargin: string;
178
- status: string;
179
- message: string;
180
- }
181
167
  export interface TpSlLeg {
182
168
  triggerPrice: string;
183
169
  orderType: OrderType;
@@ -311,8 +297,6 @@ export interface PositionsAPI extends BaseAPI {
311
297
  closePosition(positionId: string, request: ClosePositionRequest): Promise<ClosePositionResponse>;
312
298
  batchCloseAllPositions(request?: BatchCloseAllRequest): Promise<BatchCloseAllResponse>;
313
299
  getPositionRisk(positionId: string): Promise<PositionRisk>;
314
- addPositionMargin(positionId: string, request: AddPositionMarginRequest): Promise<PositionMarginResponse>;
315
- reducePositionMargin(positionId: string, request: ReducePositionMarginRequest): Promise<PositionMarginResponse>;
316
300
  attachPositionTpSl(positionId: string, request: AttachPositionTpSlRequest): Promise<AttachPositionTpSlResponse>;
317
301
  listPositionHistory(params?: ListPositionHistoryParams): Promise<ListPositionHistoryResponse>;
318
302
  getPositionPnlHistory(positionId: string, params: GetPositionPnlHistoryParams): Promise<GetPositionPnlHistoryResponse>;
@@ -41,10 +41,17 @@ export interface TradingAPI extends BaseAPI {
41
41
  /**
42
42
  * Maker-only: rejected with a 400 carrying the structured error code
43
43
  * `POST_ONLY_WOULD_CROSS` if this limit order would cross the book.
44
- * LIMIT orders with GTC/GTD only; rejected together with IOC/FOK.
44
+ * LIMIT orders with GTC only; rejected together with IOC/FOK.
45
45
  * Echoed back as `postOnly` on order detail and list reads.
46
46
  */
47
47
  postOnly?: boolean;
48
+ /**
49
+ * Client-assigned correlation handle, echoed back on order reads and
50
+ * order WebSocket events. At most 64 characters from [A-Za-z0-9._:-].
51
+ * Not de-duplicated and not unique — a replacement re-states it and
52
+ * inherits nothing from the original order.
53
+ */
54
+ clientOrderId?: string;
48
55
  takeProfit?: ParentTpSlLegParams;
49
56
  stopLoss?: ParentTpSlLegParams;
50
57
  }): Promise<CreateOrderResponse>;
@@ -70,6 +77,13 @@ export interface TradingAPI extends BaseAPI {
70
77
  positionSide?: PositionSide;
71
78
  leverage?: string;
72
79
  reduceOnly?: boolean;
80
+ /**
81
+ * Client-assigned correlation handle, echoed back on order reads and
82
+ * order WebSocket events. At most 64 characters from [A-Za-z0-9._:-].
83
+ * Not de-duplicated and not unique — a replacement re-states it and
84
+ * inherits nothing from the original order.
85
+ */
86
+ clientOrderId?: string;
73
87
  takeProfit?: ParentTpSlLegParams;
74
88
  stopLoss?: ParentTpSlLegParams;
75
89
  }): Promise<CreateOrderResponse>;
@@ -119,6 +133,13 @@ export interface TradingAPI extends BaseAPI {
119
133
  quantity?: string;
120
134
  useMasterBalance?: boolean;
121
135
  postOnly?: boolean;
136
+ /**
137
+ * Client-assigned correlation handle, echoed back on order reads and
138
+ * order WebSocket events. At most 64 characters from [A-Za-z0-9._:-].
139
+ * Not de-duplicated and not unique — a replacement re-states it and
140
+ * inherits nothing from the original order.
141
+ */
142
+ clientOrderId?: string;
122
143
  }): Promise<ReplaceOrderResponse>;
123
144
  /**
124
145
  * Batch creates multiple orders in a single request.
@@ -40,13 +40,13 @@ export interface Order {
40
40
  averageFillPrice?: string;
41
41
  /** Trading mode (SPOT or MARGIN) */
42
42
  tradingMode: TradingMode;
43
- /** Time in force - GTC, IOC, FOK, or GTD */
43
+ /** Time in force - GTC, IOC, or FOK (GTD is deprecated and rejected) */
44
44
  timeInForce?: TimeInForce;
45
45
  /** Order creation timestamp (ISO 8601) */
46
46
  createdAt: string;
47
47
  /** Order last update timestamp (ISO 8601) */
48
48
  updatedAt?: string;
49
- /** Optional expiration date for GTD orders (ISO 8601, max 1 year) */
49
+ /** Optional expiry for a GTC order (ISO 8601, max 1 year) */
50
50
  expirationDate?: string;
51
51
  /** Application taker fee in basis points (e.g., "100" = 1%) - populated after fills */
52
52
  applicationTakerFee?: string;
@@ -70,6 +70,14 @@ export interface Order {
70
70
  reduceOnly?: boolean;
71
71
  /** Whether the order was placed post-only (maker-only). Absent for orders placed before the flag was persisted. */
72
72
  postOnly?: boolean;
73
+ /**
74
+ * Client-assigned correlation handle as stored: the value supplied on create
75
+ * or replace, with surrounding whitespace trimmed. Absent when the order
76
+ * carried none, including every order placed before the field was accepted on
77
+ * write. Not unique — several orders may share one value, so a lookup by it
78
+ * can be ambiguous.
79
+ */
80
+ clientOrderId?: string;
73
81
  /** Position ID linked to the order, when available */
74
82
  positionId?: string;
75
83
  /** Stable cause when status is CANCELLED */
@@ -134,7 +142,10 @@ export type TradingMode = "SPOT" | "MARGIN";
134
142
  * - GTC: Good Till Cancel - remains active until filled or canceled
135
143
  * - IOC: Immediate or Cancel - execute immediately and cancel unfilled portion
136
144
  * - FOK: Fill or Kill - execute completely or cancel entirely
137
- * - GTD: Good Till Date - remains active until specified expiration date
145
+ * - GTD: **deprecated, never implemented** - the server rejects it with HTTP
146
+ * 400 (`Time in force must be GTC, IOC, or FOK`). The variant is retained so
147
+ * existing code keeps compiling. For an order that expires at a set time, use
148
+ * `GTC` together with `expirationDate`.
138
149
  */
139
150
  export type TimeInForce = "GTC" | "IOC" | "FOK" | "GTD";
140
151
  /**
@@ -38,8 +38,12 @@ export interface MatchResult {
38
38
  } | null;
39
39
  }
40
40
  /**
41
- * Parent TP/SL follows the parent order quantity and becomes active once the
42
- * parent order creates or extends a position.
41
+ * A take-profit / stop-loss leg attached to an order at placement. It becomes
42
+ * active once the parent order creates or extends a position.
43
+ *
44
+ * Sizing is the leg's own, set by `quantity` / `closePosition` below — it does
45
+ * NOT follow the parent order's quantity. Sizing from the parent is what let a
46
+ * leg freeze at the order's size and under-cover a position that later grew.
43
47
  */
44
48
  export interface ParentTpSlLegParams {
45
49
  /** Mark price that arms the close order */
@@ -54,6 +58,18 @@ export interface ParentTpSlLegParams {
54
58
  slippageToleranceBps?: number;
55
59
  /** Optional conditional order expiry timestamp (ISO 8601) */
56
60
  expiresAt?: string;
61
+ /**
62
+ * Deliberate partial size: this leg closes exactly this much and never
63
+ * resizes, however the position grows. Mutually exclusive with
64
+ * `closePosition: true`; required when `closePosition: false`.
65
+ */
66
+ quantity?: string;
67
+ /**
68
+ * Resolve the full live position size when triggered, so the leg keeps
69
+ * covering the position as it grows. Mutually exclusive with `quantity`.
70
+ * Omitting both also means full-position close.
71
+ */
72
+ closePosition?: boolean;
57
73
  }
58
74
  /**
59
75
  * Response from creating an order.
@@ -354,11 +370,18 @@ export interface BatchCreateOrderParams {
354
370
  /**
355
371
  * Maker-only: rejected with a structured `error.code` of
356
372
  * `POST_ONLY_WOULD_CROSS` on this item's result if the limit order would
357
- * cross the book. LIMIT orders with GTC/GTD only; rejected on MARKET
373
+ * cross the book. LIMIT orders with GTC only; rejected on MARKET
358
374
  * orders and combined with IOC/FOK. Echoed back as `postOnly` on order
359
375
  * detail and list reads.
360
376
  */
361
377
  postOnly?: boolean;
378
+ /**
379
+ * Client-assigned correlation handle, echoed back on order reads and on
380
+ * order WebSocket events. At most 64 characters from [A-Za-z0-9._:-].
381
+ * Monaco does not de-duplicate on it and does not enforce uniqueness —
382
+ * it correlates a response to a request, it does not make a retry safe.
383
+ */
384
+ clientOrderId?: string;
362
385
  }
363
386
  /**
364
387
  * Parameters for a single order in a batch replace request
@@ -377,6 +400,13 @@ export interface BatchReplaceOrderParams {
377
400
  * inherited from the original order — see `TradingAPI.replaceOrder`.
378
401
  */
379
402
  postOnly?: boolean;
403
+ /**
404
+ * Client-assigned correlation handle, echoed back on order reads and on
405
+ * order WebSocket events. At most 64 characters from [A-Za-z0-9._:-].
406
+ * Monaco does not de-duplicate on it and does not enforce uniqueness —
407
+ * it correlates a response to a request, it does not make a retry safe.
408
+ */
409
+ clientOrderId?: string;
380
410
  }
381
411
  export interface CancelConditionalOrderResponse {
382
412
  conditionalOrderId: string;
@@ -25,6 +25,10 @@ export declare const TransferCollateralSchema: z.ZodObject<{
25
25
  amount: z.ZodString;
26
26
  tradingPairId: z.ZodOptional<z.ZodUUID>;
27
27
  strategyKey: z.ZodOptional<z.ZodString>;
28
+ marginMode: z.ZodOptional<z.ZodEnum<{
29
+ ISOLATED: "ISOLATED";
30
+ CROSS: "CROSS";
31
+ }>>;
28
32
  }, z.core.$strip>;
29
33
  }, z.core.$strip>;
30
34
  export declare const TransferCollateralToParentMarginAccountSchema: z.ZodObject<{
@@ -25,11 +25,19 @@ export const GetAvailableCollateralSchema = z
25
25
  asset: z.string().trim().min(1, "Asset cannot be empty").optional(),
26
26
  })
27
27
  .optional();
28
- const TransferCollateralRequestSchema = z.object({
28
+ const TransferCollateralRequestSchema = z
29
+ .object({
29
30
  asset: z.string().trim().min(1, "Asset cannot be empty"),
30
31
  amount: PositiveDecimalStringSchema,
31
32
  tradingPairId: UUIDSchema.optional(),
32
33
  strategyKey: z.string().trim().min(1, "Strategy key cannot be empty").optional(),
34
+ // A cross risk bucket has no trading pair, so CROSS is the only way to name
35
+ // one on the way out (0XM-2420). The two never combine.
36
+ marginMode: z.enum(["ISOLATED", "CROSS"]).optional(),
37
+ })
38
+ .refine((request) => !(request.marginMode === "CROSS" && request.tradingPairId !== undefined), {
39
+ message: "tradingPairId is not supported for CROSS risk buckets",
40
+ path: ["tradingPairId"],
33
41
  });
34
42
  const ParentMarginAccountCollateralRequestSchema = z.object({
35
43
  asset: z.string().trim().min(1, "Asset cannot be empty"),
@@ -171,6 +171,10 @@ export declare const GetCandlesticksByPairIdSchema: z.ZodObject<{
171
171
  startTime: z.ZodOptional<z.ZodNumber>;
172
172
  endTime: z.ZodOptional<z.ZodNumber>;
173
173
  limit: z.ZodOptional<z.ZodNumber>;
174
+ priceType: z.ZodOptional<z.ZodEnum<{
175
+ trade: "trade";
176
+ mark: "mark";
177
+ }>>;
174
178
  }, z.core.$strip>;
175
179
  /**
176
180
  * @deprecated Use GetCandlesticksByPairIdSchema instead. Symbol-based lookups are no longer supported.
@@ -191,6 +195,10 @@ export declare const GetCandlesticksBySymbolSchema: z.ZodObject<{
191
195
  startTime: z.ZodOptional<z.ZodNumber>;
192
196
  endTime: z.ZodOptional<z.ZodNumber>;
193
197
  limit: z.ZodOptional<z.ZodNumber>;
198
+ priceType: z.ZodOptional<z.ZodEnum<{
199
+ trade: "trade";
200
+ mark: "mark";
201
+ }>>;
194
202
  }, z.core.$strip>;
195
203
  /**
196
204
  * Get Trading Pair validation schema
@@ -188,6 +188,7 @@ export const GetCandlesticksByPairIdSchema = z
188
188
  startTime: TimestampSchema.optional(),
189
189
  endTime: TimestampSchema.optional(),
190
190
  limit: CandlestickLimitSchema,
191
+ priceType: z.enum(["trade", "mark"]).optional(),
191
192
  })
192
193
  .refine((data) => {
193
194
  // Only validate startTime < endTime if both are provided
@@ -37,19 +37,6 @@ export declare const BatchCloseAllSchema: z.ZodObject<{
37
37
  export declare const GetPositionRiskSchema: z.ZodObject<{
38
38
  positionId: z.ZodUUID;
39
39
  }, z.core.$strip>;
40
- export declare const AddPositionMarginSchema: z.ZodObject<{
41
- positionId: z.ZodUUID;
42
- request: z.ZodObject<{
43
- amount: z.ZodString;
44
- asset: z.ZodString;
45
- }, z.core.$strip>;
46
- }, z.core.$strip>;
47
- export declare const ReducePositionMarginSchema: z.ZodObject<{
48
- positionId: z.ZodUUID;
49
- request: z.ZodObject<{
50
- amount: z.ZodString;
51
- }, z.core.$strip>;
52
- }, z.core.$strip>;
53
40
  export declare const AttachPositionTpSlSchema: z.ZodObject<{
54
41
  positionId: z.ZodUUID;
55
42
  request: z.ZodObject<{
@@ -33,12 +33,14 @@ export const ClosePositionSchema = PositionIdSchema.extend({
33
33
  quantity: PositiveDecimalStringSchema.optional(),
34
34
  }),
35
35
  })
36
- .refine((data) => data.request.closeType !== "LIMIT" || data.request.limitPrice !== undefined, {
37
- message: "limitPrice is required for LIMIT close requests",
36
+ // An IOC close is a LIMIT+IOC order server-side (`close_order_shape`), so it
37
+ // needs a price exactly like a LIMIT close does; only MARKET forbids one.
38
+ .refine((data) => data.request.closeType === "MARKET" || data.request.limitPrice !== undefined, {
39
+ message: "limitPrice is required for LIMIT and IOC close requests",
38
40
  path: ["request", "limitPrice"],
39
41
  })
40
- .refine((data) => data.request.closeType === "LIMIT" || data.request.limitPrice === undefined, {
41
- message: "limitPrice is only allowed for LIMIT close requests",
42
+ .refine((data) => data.request.closeType !== "MARKET" || data.request.limitPrice === undefined, {
43
+ message: "limitPrice is not allowed for MARKET close requests",
42
44
  path: ["request", "limitPrice"],
43
45
  });
44
46
  export const BatchCloseAllSchema = z.object({
@@ -46,17 +48,6 @@ export const BatchCloseAllSchema = z.object({
46
48
  slippageToleranceBps: SlippageToleranceBpsSchema.optional(),
47
49
  });
48
50
  export const GetPositionRiskSchema = PositionIdSchema;
49
- export const AddPositionMarginSchema = PositionIdSchema.extend({
50
- request: z.object({
51
- amount: PositiveDecimalStringSchema,
52
- asset: z.string().trim().min(1, "Asset cannot be empty"),
53
- }),
54
- });
55
- export const ReducePositionMarginSchema = PositionIdSchema.extend({
56
- request: z.object({
57
- amount: PositiveDecimalStringSchema,
58
- }),
59
- });
60
51
  const TpSlLegSchema = z
61
52
  .object({
62
53
  triggerPrice: PositiveDecimalStringSchema,
@@ -74,6 +74,8 @@ export declare const ParentTpSlLegSchema: z.ZodObject<{
74
74
  MARKET: "MARKET";
75
75
  }>;
76
76
  limitPrice: z.ZodOptional<z.ZodString>;
77
+ quantity: z.ZodOptional<z.ZodString>;
78
+ closePosition: z.ZodOptional<z.ZodBoolean>;
77
79
  timeInForce: z.ZodOptional<z.ZodEnum<{
78
80
  GTC: "GTC";
79
81
  IOC: "IOC";
@@ -127,6 +129,8 @@ export declare const PlaceLimitOrderSchema: z.ZodObject<{
127
129
  MARKET: "MARKET";
128
130
  }>;
129
131
  limitPrice: z.ZodOptional<z.ZodString>;
132
+ quantity: z.ZodOptional<z.ZodString>;
133
+ closePosition: z.ZodOptional<z.ZodBoolean>;
130
134
  timeInForce: z.ZodOptional<z.ZodEnum<{
131
135
  GTC: "GTC";
132
136
  IOC: "IOC";
@@ -141,6 +145,8 @@ export declare const PlaceLimitOrderSchema: z.ZodObject<{
141
145
  MARKET: "MARKET";
142
146
  }>;
143
147
  limitPrice: z.ZodOptional<z.ZodString>;
148
+ quantity: z.ZodOptional<z.ZodString>;
149
+ closePosition: z.ZodOptional<z.ZodBoolean>;
144
150
  timeInForce: z.ZodOptional<z.ZodEnum<{
145
151
  GTC: "GTC";
146
152
  IOC: "IOC";
@@ -188,6 +194,8 @@ export declare const PlaceMarketOrderSchema: z.ZodObject<{
188
194
  MARKET: "MARKET";
189
195
  }>;
190
196
  limitPrice: z.ZodOptional<z.ZodString>;
197
+ quantity: z.ZodOptional<z.ZodString>;
198
+ closePosition: z.ZodOptional<z.ZodBoolean>;
191
199
  timeInForce: z.ZodOptional<z.ZodEnum<{
192
200
  GTC: "GTC";
193
201
  IOC: "IOC";
@@ -202,6 +210,8 @@ export declare const PlaceMarketOrderSchema: z.ZodObject<{
202
210
  MARKET: "MARKET";
203
211
  }>;
204
212
  limitPrice: z.ZodOptional<z.ZodString>;
213
+ quantity: z.ZodOptional<z.ZodString>;
214
+ closePosition: z.ZodOptional<z.ZodBoolean>;
205
215
  timeInForce: z.ZodOptional<z.ZodEnum<{
206
216
  GTC: "GTC";
207
217
  IOC: "IOC";
@@ -360,6 +370,12 @@ export declare const BatchCreateOrderItemSchema: z.ZodObject<{
360
370
  reduceOnly: z.ZodOptional<z.ZodBoolean>;
361
371
  postOnly: z.ZodOptional<z.ZodBoolean>;
362
372
  }, z.core.$strip>;
373
+ /**
374
+ * Maximum items per batch create/replace/cancel request. Mirrors the server's
375
+ * cap (Zenith #11): a batch is one matching-engine sequencer command, so its
376
+ * item count is bounded independent of the transport message-size limit.
377
+ */
378
+ export declare const MAX_BATCH_ORDER_ITEMS = 100;
363
379
  /**
364
380
  * Batch Create Orders validation schema
365
381
  *
@@ -83,6 +83,8 @@ export const ParentTpSlLegSchema = z
83
83
  triggerPrice: PositiveDecimalStringSchema,
84
84
  orderType: OrderTypeSchema,
85
85
  limitPrice: PositiveDecimalStringSchema.optional(),
86
+ quantity: PositiveDecimalStringSchema.optional(),
87
+ closePosition: z.boolean().optional(),
86
88
  timeInForce: ConditionalTimeInForceSchema.optional(),
87
89
  slippageToleranceBps: SlippageToleranceBpsSchema.optional(),
88
90
  expiresAt: ISO8601DateSchema.optional(),
@@ -102,6 +104,16 @@ export const ParentTpSlLegSchema = z
102
104
  .refine((data) => data.orderType !== "LIMIT" || data.slippageToleranceBps === undefined, {
103
105
  message: "slippageToleranceBps is only allowed for MARKET parent TP/SL",
104
106
  path: ["slippageToleranceBps"],
107
+ })
108
+ // Same sizing contract the position-attached rail enforces: omit both to
109
+ // track the live position, or name a deliberate partial that never resizes.
110
+ .refine((data) => data.closePosition !== true || data.quantity === undefined, {
111
+ message: "quantity must be omitted when closePosition is true",
112
+ path: ["quantity"],
113
+ })
114
+ .refine((data) => data.quantity !== undefined || data.closePosition !== false, {
115
+ message: "quantity is required when closePosition is false",
116
+ path: ["closePosition"],
105
117
  });
106
118
  const hasParentTpSl = (options) => options?.takeProfit !== undefined || options?.stopLoss !== undefined;
107
119
  const legacyPositionSideMatchesOrderSide = (side, positionSide) => positionSide === undefined || (positionSide !== "NONE" && ((side === "BUY" && positionSide === "LONG") || (side === "SELL" && positionSide === "SHORT")));
@@ -429,13 +441,22 @@ export const BatchCreateOrderItemSchema = z
429
441
  message: "leverage is required for normal MARGIN orders",
430
442
  path: ["leverage"],
431
443
  });
444
+ /**
445
+ * Maximum items per batch create/replace/cancel request. Mirrors the server's
446
+ * cap (Zenith #11): a batch is one matching-engine sequencer command, so its
447
+ * item count is bounded independent of the transport message-size limit.
448
+ */
449
+ export const MAX_BATCH_ORDER_ITEMS = 100;
432
450
  /**
433
451
  * Batch Create Orders validation schema
434
452
  *
435
453
  * Validates the full array of orders for a batch create request.
436
454
  */
437
455
  export const BatchCreateOrdersSchema = z.object({
438
- orders: z.array(BatchCreateOrderItemSchema).min(1, "At least one order is required"),
456
+ orders: z
457
+ .array(BatchCreateOrderItemSchema)
458
+ .min(1, "At least one order is required")
459
+ .max(MAX_BATCH_ORDER_ITEMS, `At most ${MAX_BATCH_ORDER_ITEMS} orders per batch request`),
439
460
  });
440
461
  /**
441
462
  * Single batch replace order item validation schema
@@ -463,5 +484,8 @@ export const BatchReplaceOrderItemSchema = z
463
484
  * Validates the full array of orders for a batch replace request.
464
485
  */
465
486
  export const BatchReplaceOrdersSchema = z.object({
466
- orders: z.array(BatchReplaceOrderItemSchema).min(1, "At least one order is required"),
487
+ orders: z
488
+ .array(BatchReplaceOrderItemSchema)
489
+ .min(1, "At least one order is required")
490
+ .max(MAX_BATCH_ORDER_ITEMS, `At most ${MAX_BATCH_ORDER_ITEMS} orders per batch request`),
467
491
  });
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Account WebSocket Event Types
3
+ *
4
+ * Types for real-time account-level margin updates: equity, collateral, free
5
+ * collateral, margin ratio, and maintenance requirement for a margin account.
6
+ *
7
+ * This is an authenticated channel - requires the signed session-key handshake.
8
+ * Lag policy is Conflate: a lagging subscriber is fast-forwarded to the latest
9
+ * state rather than disconnected, so there is no gap signal to reconcile. Each
10
+ * frame carries the account's full current health, so consume it as a
11
+ * terminal-state snapshot per margin account, never as an additive delta.
12
+ */
13
+ /**
14
+ * Account event data carrying the current margin health of a single account.
15
+ */
16
+ export interface AccountEventData {
17
+ /** Margin account this update describes (UUID) */
18
+ marginAccountId: string;
19
+ /** Mark-inclusive account equity: collateral + unrealized PnL + funding (decimal string) */
20
+ equity: string;
21
+ /** Raw deposited collateral in USD (decimal string) */
22
+ collateral: string;
23
+ /** Collateral available for new margin allocation (decimal string) */
24
+ freeCollateral: string;
25
+ /**
26
+ * Maintenance margin required divided by equity; `0` when equity is zero
27
+ * (decimal string).
28
+ */
29
+ marginRatio: string;
30
+ /** Maintenance margin required to keep the account solvent (decimal string) */
31
+ maintenanceRequirement: string;
32
+ /** Timestamp when the account state was updated (ISO 8601) */
33
+ updatedAt: string;
34
+ }
35
+ /**
36
+ * Account event emitted when a user's account-level margin health changes.
37
+ */
38
+ export interface AccountEvent {
39
+ /** Event type identifier */
40
+ eventType: "account_update";
41
+ /** User ID (UUID) */
42
+ userId: string;
43
+ /** Account data */
44
+ data: AccountEventData;
45
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Account WebSocket Event Types
3
+ *
4
+ * Types for real-time account-level margin updates: equity, collateral, free
5
+ * collateral, margin ratio, and maintenance requirement for a margin account.
6
+ *
7
+ * This is an authenticated channel - requires the signed session-key handshake.
8
+ * Lag policy is Conflate: a lagging subscriber is fast-forwarded to the latest
9
+ * state rather than disconnected, so there is no gap signal to reconcile. Each
10
+ * frame carries the account's full current health, so consume it as a
11
+ * terminal-state snapshot per margin account, never as an additive delta.
12
+ */
@@ -6,9 +6,24 @@
6
6
  */
7
7
  import type { Address } from "viem";
8
8
  /**
9
- * Reason for the balance update
9
+ * Reason for the balance update.
10
+ *
11
+ * `fee` and `rebate` accompany a fill: `fee` when a taker/application fee is
12
+ * charged, `rebate` when a maker rebate is credited (including perp/margin
13
+ * makers). `funding` accompanies a funding settlement against margin collateral
14
+ * (also surfaced on the movements channel with `transactionType: "funding"`).
15
+ * `liquidation` and `adl` accompany a forced-close on the liquidation-worker
16
+ * path: `liquidation` on the liquidated victim's collateral, `adl` on an
17
+ * account impacted by auto-deleveraging.
18
+ *
19
+ * A single fill can emit more than one `balance_update` for the same account
20
+ * (e.g. a `trade` frame plus a `rebate` frame). Each frame carries the
21
+ * account's RESULTING balance for its token — it is a terminal-state snapshot,
22
+ * not an additive delta — so consume it by applying the latest balance per
23
+ * (account, token). That makes reconnect/replay naturally idempotent: never sum
24
+ * the `reason` frames as if they were separate credits.
10
25
  */
11
- export type BalanceUpdateReason = "lock" | "unlock" | "deposit" | "withdrawal" | "trade" | "margin_transfer_in" | "margin_transfer_out";
26
+ export type BalanceUpdateReason = "lock" | "unlock" | "deposit" | "margin_deposit" | "withdrawal" | "trade" | "fee" | "rebate" | "funding" | "liquidation" | "adl" | "margin_transfer_in" | "margin_transfer_out";
12
27
  /**
13
28
  * User balance event data containing current balance state
14
29
  */
@@ -1,6 +1,8 @@
1
+ export * from "./account-events";
1
2
  export * from "./balance-events";
2
3
  export * from "./conditional-order-events";
3
4
  export * from "./liquidation-events";
5
+ export * from "./market-stats-events";
4
6
  export * from "./movement-events";
5
7
  export * from "./ohlcv-events";
6
8
  export * from "./orderbook-events";
@@ -1,6 +1,8 @@
1
+ export * from "./account-events";
1
2
  export * from "./balance-events";
2
3
  export * from "./conditional-order-events";
3
4
  export * from "./liquidation-events";
5
+ export * from "./market-stats-events";
4
6
  export * from "./movement-events";
5
7
  export * from "./ohlcv-events";
6
8
  export * from "./orderbook-events";