@0xmonaco/types 1.1.2 → 1.1.5-prerelease.de852e2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/analytics/builders.d.ts +120 -0
- package/dist/analytics/builders.js +11 -0
- package/dist/analytics/index.d.ts +131 -0
- package/dist/analytics/index.js +22 -0
- package/dist/analytics/wallets.d.ts +193 -0
- package/dist/analytics/wallets.js +16 -0
- package/dist/applications/requests.d.ts +5 -5
- package/dist/buildercodes/index.d.ts +13 -11
- package/dist/buildercodes/responses.d.ts +1 -0
- package/dist/buildercodes/responses.js +10 -0
- package/dist/fees/responses.js +2 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/margin-accounts/index.d.ts +7 -2
- package/dist/market/index.d.ts +51 -2
- package/dist/profile/index.d.ts +25 -2
- package/dist/rfq/index.d.ts +44 -0
- package/dist/rfq/index.js +10 -0
- package/dist/rfq/responses.d.ts +276 -0
- package/dist/rfq/responses.js +182 -0
- package/dist/sdk/index.d.ts +25 -2
- package/dist/trading/index.d.ts +19 -4
- package/dist/trading/orders.d.ts +12 -1
- package/dist/trading/responses.d.ts +27 -2
- package/dist/validation/index.d.ts +1 -0
- package/dist/validation/index.js +1 -0
- package/dist/validation/margin-accounts.d.ts +2 -2
- package/dist/validation/margin-accounts.js +5 -5
- package/dist/validation/market.d.ts +7 -0
- package/dist/validation/market.js +4 -0
- package/dist/validation/rfq.d.ts +109 -0
- package/dist/validation/rfq.js +120 -0
- package/dist/validation/trading.d.ts +24 -0
- package/dist/validation/trading.js +55 -42
- package/dist/websocket/base.d.ts +47 -11
- package/dist/websocket/client.d.ts +51 -4
- package/dist/websocket/depth.d.ts +142 -0
- package/dist/websocket/depth.js +13 -0
- package/dist/websocket/events/index.d.ts +2 -0
- package/dist/websocket/events/index.js +2 -0
- package/dist/websocket/events/orderbook-events.d.ts +41 -1
- package/dist/websocket/events/rfq-events.d.ts +116 -0
- package/dist/websocket/events/rfq-events.js +15 -0
- package/dist/websocket/events/rfq-trade-events.d.ts +28 -0
- package/dist/websocket/events/rfq-trade-events.js +6 -0
- package/dist/websocket/events/trade-events.d.ts +53 -0
- package/dist/websocket/index.d.ts +1 -0
- package/dist/websocket/index.js +1 -0
- package/dist/websocket/snapshots.d.ts +23 -1
- package/dist/wire/operations.d.ts +1 -1
- package/dist/wire/operations.js +28 -0
- package/dist/wire/schema.d.ts +5372 -2040
- package/package.json +2 -2
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFQ (block trading) validation schemas.
|
|
3
|
+
*
|
|
4
|
+
* Client-side checks for the RFQ request params, run before a request is
|
|
5
|
+
* sent. The server stays the authority on every business rule (market size
|
|
6
|
+
* rules, deadlines, versions, last-look improvement); these catch malformed
|
|
7
|
+
* input early and mirror the request shape the REST gateway accepts, which
|
|
8
|
+
* rejects unknown fields.
|
|
9
|
+
*/
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
import { MarginModeSchema, PositiveDecimalStringSchema, UUIDSchema } from "./trading.js";
|
|
12
|
+
/** The taker's side, or a quote's side as the taker sees it. */
|
|
13
|
+
export const RfqSideSchema = z.enum(["BUY", "SELL"]);
|
|
14
|
+
/** The market product an RFQ trades. */
|
|
15
|
+
export const RfqProductSchema = z.enum(["SPOT", "PERPETUAL"]);
|
|
16
|
+
/**
|
|
17
|
+
* A client idempotency key: 1-64 letters, digits, or `. _ : -`. A retry with
|
|
18
|
+
* the same key and body returns the first result. Omitted, the SDK generates
|
|
19
|
+
* one per call.
|
|
20
|
+
*/
|
|
21
|
+
export const RfqIdempotencyKeySchema = z
|
|
22
|
+
.string()
|
|
23
|
+
.regex(/^[A-Za-z0-9._:-]{1,64}$/, "idempotencyKey must be 1-64 letters, digits, or . _ : - without whitespace");
|
|
24
|
+
/** A version a request names (`expectedVersion`, `viewVersion`). */
|
|
25
|
+
const VersionSchema = z.number().int("version must be an integer").min(0, "version cannot be negative");
|
|
26
|
+
/** A quote's price (quote units per base unit) and capacity (base units). */
|
|
27
|
+
export const RfqQuoteTermsSchema = z
|
|
28
|
+
.object({
|
|
29
|
+
price: PositiveDecimalStringSchema,
|
|
30
|
+
capacity: PositiveDecimalStringSchema,
|
|
31
|
+
})
|
|
32
|
+
.strict();
|
|
33
|
+
/** Params for requesting quotes. */
|
|
34
|
+
export const CreateRfqSchema = z
|
|
35
|
+
.object({
|
|
36
|
+
tradingPairId: UUIDSchema,
|
|
37
|
+
product: RfqProductSchema,
|
|
38
|
+
/** Maximum base quantity; not a guaranteed fill. */
|
|
39
|
+
quantity: PositiveDecimalStringSchema,
|
|
40
|
+
/**
|
|
41
|
+
* Omit for a two-way RFQ, whose direction stays hidden from makers. Set,
|
|
42
|
+
* makers see it and may quote only the side that fills it (an ask when
|
|
43
|
+
* you buy, a bid when you sell).
|
|
44
|
+
*/
|
|
45
|
+
side: RfqSideSchema.optional(),
|
|
46
|
+
/**
|
|
47
|
+
* Perpetuals: the leverage your order takes when you accept, as on an
|
|
48
|
+
* order (required there, refused on spot). For a two-way RFQ it applies
|
|
49
|
+
* to whichever side you accept.
|
|
50
|
+
*/
|
|
51
|
+
leverage: PositiveDecimalStringSchema.optional(),
|
|
52
|
+
/** Perpetuals: ISOLATED (the default) or CROSS, as on an order. */
|
|
53
|
+
marginMode: MarginModeSchema.optional(),
|
|
54
|
+
idempotencyKey: RfqIdempotencyKeySchema.optional(),
|
|
55
|
+
})
|
|
56
|
+
.strict();
|
|
57
|
+
/** Params for accepting one side of the view the taker last saw. */
|
|
58
|
+
export const AcceptRfqSchema = z
|
|
59
|
+
.object({
|
|
60
|
+
side: RfqSideSchema,
|
|
61
|
+
/** The `view.viewVersion` being accepted; a newer view refuses it. */
|
|
62
|
+
viewVersion: VersionSchema,
|
|
63
|
+
idempotencyKey: RfqIdempotencyKeySchema.optional(),
|
|
64
|
+
})
|
|
65
|
+
.strict();
|
|
66
|
+
/** Params for cancelling an RFQ. */
|
|
67
|
+
export const CancelRfqSchema = z
|
|
68
|
+
.object({
|
|
69
|
+
idempotencyKey: RfqIdempotencyKeySchema.optional(),
|
|
70
|
+
})
|
|
71
|
+
.strict();
|
|
72
|
+
/** Params for placing or replacing a quote: a bid, an ask or both. */
|
|
73
|
+
export const UpsertRfqQuoteSchema = z
|
|
74
|
+
.object({
|
|
75
|
+
/** Your current version for this RFQ (`ownLatestVersion`); 0 for your first quote. */
|
|
76
|
+
expectedVersion: VersionSchema,
|
|
77
|
+
/** You buying. */
|
|
78
|
+
bid: RfqQuoteTermsSchema.optional(),
|
|
79
|
+
/** You selling. */
|
|
80
|
+
ask: RfqQuoteTermsSchema.optional(),
|
|
81
|
+
/** 15000-60000 ms; omitted means 60000. Capped at the request deadline. */
|
|
82
|
+
validityMs: z
|
|
83
|
+
.number()
|
|
84
|
+
.int("validityMs must be an integer")
|
|
85
|
+
.min(15000, "validityMs must be at least 15000")
|
|
86
|
+
.max(60000, "validityMs cannot exceed 60000")
|
|
87
|
+
.optional(),
|
|
88
|
+
/**
|
|
89
|
+
* Perpetuals: the leverage each side's order reserves with, as on an
|
|
90
|
+
* order (required there, refused on spot). A quote reserves funds like a
|
|
91
|
+
* resting limit order; leverage, margin mode and bucket are fixed while a
|
|
92
|
+
* side rests, so to change them withdraw and quote again.
|
|
93
|
+
*/
|
|
94
|
+
leverage: PositiveDecimalStringSchema.optional(),
|
|
95
|
+
/** Perpetuals: ISOLATED (the default) or CROSS, as on an order. */
|
|
96
|
+
marginMode: MarginModeSchema.optional(),
|
|
97
|
+
idempotencyKey: RfqIdempotencyKeySchema.optional(),
|
|
98
|
+
})
|
|
99
|
+
.strict()
|
|
100
|
+
.refine((params) => params.bid !== undefined || params.ask !== undefined, "a quote needs a bid, an ask or both");
|
|
101
|
+
/** Params for withdrawing your current quote. */
|
|
102
|
+
export const WithdrawRfqQuoteSchema = z
|
|
103
|
+
.object({
|
|
104
|
+
/** Your current version for this RFQ. */
|
|
105
|
+
expectedVersion: VersionSchema,
|
|
106
|
+
idempotencyKey: RfqIdempotencyKeySchema.optional(),
|
|
107
|
+
})
|
|
108
|
+
.strict();
|
|
109
|
+
/** Params for answering last look. There is no accept: silence executes. */
|
|
110
|
+
export const RespondRfqLastLookSchema = z
|
|
111
|
+
.object({
|
|
112
|
+
/** `ownSelection.acceptanceId` from the RFQ's status. */
|
|
113
|
+
acceptanceId: UUIDSchema,
|
|
114
|
+
response: z.enum(["REJECT", "IMPROVE"]),
|
|
115
|
+
/** IMPROVE only: a strictly better price or a higher capacity than the frozen terms. */
|
|
116
|
+
improvedTerms: RfqQuoteTermsSchema.optional(),
|
|
117
|
+
idempotencyKey: RfqIdempotencyKeySchema.optional(),
|
|
118
|
+
})
|
|
119
|
+
.strict()
|
|
120
|
+
.refine((params) => (params.response === "IMPROVE") === (params.improvedTerms !== undefined), "improvedTerms is required for IMPROVE and not allowed for REJECT");
|
|
@@ -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
|
*/
|
|
@@ -451,6 +466,15 @@ export declare const CreateTwapOrderSchema: z.ZodObject<{
|
|
|
451
466
|
conditionalExpiry: z.ZodOptional<z.ZodISODateTime>;
|
|
452
467
|
}, z.core.$strip>;
|
|
453
468
|
}, z.core.$strip>;
|
|
469
|
+
/** Bounds of a cancel-all-after timeout; 0 disarms. */
|
|
470
|
+
export declare const CANCEL_ALL_AFTER_MIN_TIMEOUT_MS = 5000;
|
|
471
|
+
export declare const CANCEL_ALL_AFTER_MAX_TIMEOUT_MS = 900000;
|
|
472
|
+
export declare const CancelAllAfterSchema: z.ZodObject<{
|
|
473
|
+
timeoutMs: z.ZodNumber;
|
|
474
|
+
options: z.ZodOptional<z.ZodObject<{
|
|
475
|
+
tradingPairId: z.ZodOptional<z.ZodUUID>;
|
|
476
|
+
}, z.core.$strict>>;
|
|
477
|
+
}, z.core.$strict>;
|
|
454
478
|
export declare const CancelTwapOrderSchema: z.ZodObject<{
|
|
455
479
|
twapOrderId: z.ZodUUID;
|
|
456
480
|
}, z.core.$strip>;
|
|
@@ -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:
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
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
|
|
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",
|
|
@@ -544,6 +544,27 @@ export const CreateTwapOrderSchema = z
|
|
|
544
544
|
message: "conditionalExpiry cannot be more than 30 days after creation (the maximum window)",
|
|
545
545
|
path: ["options", "conditionalExpiry"],
|
|
546
546
|
});
|
|
547
|
+
/** Bounds of a cancel-all-after timeout; 0 disarms. */
|
|
548
|
+
export const CANCEL_ALL_AFTER_MIN_TIMEOUT_MS = 5_000;
|
|
549
|
+
export const CANCEL_ALL_AFTER_MAX_TIMEOUT_MS = 900_000;
|
|
550
|
+
export const CancelAllAfterSchema = z
|
|
551
|
+
.object({
|
|
552
|
+
timeoutMs: z
|
|
553
|
+
.number()
|
|
554
|
+
.int()
|
|
555
|
+
.refine((ms) => ms === 0 || (ms >= CANCEL_ALL_AFTER_MIN_TIMEOUT_MS && ms <= CANCEL_ALL_AFTER_MAX_TIMEOUT_MS), {
|
|
556
|
+
message: `timeoutMs must be 0 or between ${CANCEL_ALL_AFTER_MIN_TIMEOUT_MS} and ${CANCEL_ALL_AFTER_MAX_TIMEOUT_MS}`,
|
|
557
|
+
}),
|
|
558
|
+
// Strict: a misspelled scope key must fail rather than be dropped, or the
|
|
559
|
+
// call would quietly arm the account-wide timer.
|
|
560
|
+
options: z
|
|
561
|
+
.object({
|
|
562
|
+
tradingPairId: UUIDSchema.optional(),
|
|
563
|
+
})
|
|
564
|
+
.strict()
|
|
565
|
+
.optional(),
|
|
566
|
+
})
|
|
567
|
+
.strict();
|
|
547
568
|
export const CancelTwapOrderSchema = z.object({
|
|
548
569
|
twapOrderId: UUIDSchema,
|
|
549
570
|
});
|
|
@@ -593,7 +614,7 @@ export const BatchCreateOrderItemSchema = z
|
|
|
593
614
|
marginMode: MarginModeSchema.optional(),
|
|
594
615
|
riskBucketId: UUIDSchema.optional(),
|
|
595
616
|
riskBucketCollateral: PositiveDecimalStringSchema.optional(),
|
|
596
|
-
strategyKey:
|
|
617
|
+
strategyKey: OrderStrategyKeySchema.optional(),
|
|
597
618
|
positionSide: PositionSideSchema.optional(),
|
|
598
619
|
leverage: PositiveDecimalStringSchema.optional(),
|
|
599
620
|
reduceOnly: z.boolean().optional(),
|
|
@@ -620,17 +641,13 @@ export const BatchCreateOrderItemSchema = z
|
|
|
620
641
|
message: "postOnly cannot be combined with IOC/FOK time in force",
|
|
621
642
|
path: ["postOnly"],
|
|
622
643
|
})
|
|
623
|
-
.refine((data) => data.riskBucketCollateral === undefined || data.tradingMode
|
|
644
|
+
.refine((data) => data.riskBucketCollateral === undefined || data.tradingMode !== "SPOT", {
|
|
624
645
|
message: "riskBucketCollateral is only supported for MARGIN orders",
|
|
625
646
|
path: ["tradingMode"],
|
|
626
647
|
})
|
|
627
|
-
.refine((data) => data.marginMode === undefined || data.tradingMode
|
|
648
|
+
.refine((data) => data.marginMode === undefined || data.tradingMode !== "SPOT", {
|
|
628
649
|
message: "marginMode is only supported for MARGIN orders",
|
|
629
650
|
path: ["tradingMode"],
|
|
630
|
-
})
|
|
631
|
-
.refine((data) => data.marginMode !== "CROSS" || data.marginAccountId !== undefined, {
|
|
632
|
-
message: "marginAccountId is required for CROSS margin orders",
|
|
633
|
-
path: ["marginAccountId"],
|
|
634
651
|
})
|
|
635
652
|
.refine((data) => data.marginMode !== "CROSS" || data.riskBucketId === undefined, {
|
|
636
653
|
message: "marginMode CROSS cannot be combined with riskBucketId",
|
|
@@ -639,10 +656,6 @@ export const BatchCreateOrderItemSchema = z
|
|
|
639
656
|
.refine((data) => data.marginMode !== "CROSS" || data.riskBucketCollateral === undefined, {
|
|
640
657
|
message: "marginMode CROSS cannot be combined with riskBucketCollateral",
|
|
641
658
|
path: ["riskBucketCollateral"],
|
|
642
|
-
})
|
|
643
|
-
.refine((data) => data.marginMode !== "CROSS" || data.strategyKey === undefined, {
|
|
644
|
-
message: "marginMode CROSS cannot be combined with strategyKey",
|
|
645
|
-
path: ["strategyKey"],
|
|
646
659
|
})
|
|
647
660
|
.refine((data) => data.riskBucketCollateral === undefined || data.riskBucketId === undefined, {
|
|
648
661
|
message: "riskBucketCollateral creates a new risk bucket and cannot be combined with riskBucketId",
|
package/dist/websocket/base.d.ts
CHANGED
|
@@ -71,23 +71,43 @@ export interface WebSocketStatusInfo {
|
|
|
71
71
|
*/
|
|
72
72
|
export type StatusHandler = (status: WebSocketStatus, info: WebSocketStatusInfo) => void;
|
|
73
73
|
/**
|
|
74
|
-
* Why the
|
|
75
|
-
* {@link MonacoWebSocketConfig.onResync}
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
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
|
|
85
|
-
* behind
|
|
86
|
-
*
|
|
87
|
-
* number
|
|
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;
|
|
@@ -135,7 +155,13 @@ export type WebSocketErrorCode =
|
|
|
135
155
|
* and back off before reconnecting — a hot re-subscribe loop trips the cap
|
|
136
156
|
* again.
|
|
137
157
|
*/
|
|
138
|
-
| "MESSAGE_RATE_LIMIT"
|
|
158
|
+
| "MESSAGE_RATE_LIMIT"
|
|
159
|
+
/**
|
|
160
|
+
* The `rfq` subscription was refused: RFQ is switched off, or this account
|
|
161
|
+
* is not on its access list. The same `RFQ_DISABLED` the REST and gRPC RFQ
|
|
162
|
+
* calls return. The connection stays open.
|
|
163
|
+
*/
|
|
164
|
+
| "RFQ_DISABLED";
|
|
139
165
|
/**
|
|
140
166
|
* An `Error` frame the server sent on this connection.
|
|
141
167
|
*
|
|
@@ -194,6 +220,16 @@ export type ReauthenticationRequiredHandler = (info: WebSocketReauthenticationIn
|
|
|
194
220
|
export interface MonacoWebSocketConfig {
|
|
195
221
|
/** Enable auto-reconnect on disconnect (default: true) */
|
|
196
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;
|
|
197
233
|
/**
|
|
198
234
|
* Maximum reconnection attempts per outage (default: unlimited). Retry
|
|
199
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 {
|
|
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
|
|
96
|
-
*
|
|
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
|
|
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 */
|
|
@@ -158,4 +186,23 @@ export interface MonacoWebSocket {
|
|
|
158
186
|
marketStats: (tradingPairId: string, handler: MessageHandler<MarketStatsEvent>, onSnapshot?: SnapshotHandler<MarketStatsData>) => () => void;
|
|
159
187
|
/** Subscribe to the all-markets statistics summary (public) */
|
|
160
188
|
marketStatsAll: (handler: MessageHandler<MarketStatsAllEvent>, onSnapshot?: SnapshotHandler<MarketStatsSummary>) => () => void;
|
|
189
|
+
/**
|
|
190
|
+
* Subscribe to RFQ pushes for the authenticated account (requires
|
|
191
|
+
* authentication): `RfqRequested` for every new RFQ you can quote as a maker
|
|
192
|
+
* (never your own wallet family's), and for the RFQs you are party to the
|
|
193
|
+
* taker's `RfqView`, a selected maker's `RfqSelected` (its last-look prompt)
|
|
194
|
+
* and `RfqOutcome`. Narrow on `eventType` (the wire's `type` tag). There is
|
|
195
|
+
* no per-pair variant and no
|
|
196
|
+
* snapshot: a push is a notification, so read a missed RFQ with `getRfq`.
|
|
197
|
+
* While RFQ is not enabled for the account the subscribe is refused with an
|
|
198
|
+
* `RFQ_DISABLED` error to `onError`.
|
|
199
|
+
*/
|
|
200
|
+
rfq: (handler: MessageHandler<RfqEvent>) => () => void;
|
|
201
|
+
/**
|
|
202
|
+
* Subscribe to the public, anonymised RFQ block prints for one pair. RFQ
|
|
203
|
+
* fills never print on `trades`. There is no snapshot: deduplicate on
|
|
204
|
+
* `data.executionId`, and backfill from the REST trade reads, which include
|
|
205
|
+
* RFQ fills with `executionSource: "RFQ"`.
|
|
206
|
+
*/
|
|
207
|
+
rfqTrades: (tradingPairId: string, handler: MessageHandler<RfqTradeEvent>) => () => void;
|
|
161
208
|
}
|